Finding simplifications
Turn a broad "find things to simplify" request into evidence-backed Agent Notes that remove or collapse existing surface across code, docs, and skills. It is guidance, not a checklist: follow the code, keep judgment active, and prefer a few well-proven candidates over a pile of thin guesses.
Start with repo context
- Read the root — the pre-release stance when present, and conventions such as tests-are-not-golden-truth and Agent Notes-are-not-golden-truth doctrines — plus the repository's defensive-patterns and testing docs when they exist.
- Skim the architecture doc before judging core code; simplifications that fight the service map or event taxonomy need extra evidence.
- Use the Agent Note tree and its rules to understand intentional architecture; a recorded decision needs new evidence to overturn, not a "looks complex" flag. Start with high-signal implemented examples — capability seams, twin adapters, and persistence notes — when the tree has them.
- Treat recorded architectural twins — dual LLM adapters and dual persistence backends — as intentional by default. Do not propose deleting either side as "low effort" unless the user explicitly overrides that constraint. Removing an unused method or hook inside a protected seam can still be valid if it does not collapse the protected design.
What counts as a strong candidate
A strong simplification removes, folds, or demotes something real and has clear evidence that the current design costs more than it buys:
- A public method, event, config knob, registry notification, helper, package, durable event, or test artifact has no production consumer.
- Tests or docs are the only consumers, and the behavior they pin is not load-bearing.
- Two representations mirror the same fact, especially across durable events and transient in-memory events.
- A seam has methods every implementation must support but no consumer uses.
- A separate package exists only for test/demo/support code and adds publish or dependency overhead.
- A feature implements speculative product generality: multi-session/session-load, background job rosters, live registry invalidation, mid-turn steering, tool-owned UI rendering, and similar designs with no product owner.
- An invariant, rollback path, set of expected outputs, or special-case test exists only to protect an unused API.
- Hand-rolled code reimplements what a well-maintained external package or a builtin at the repository's engine floor already provides, and the swap would delete the implementation plus its dedicated tests.
- The simplified behavior may differ slightly, but the new behavior is still reasonable and easier to explain.
Thin candidates are usually not enough for an Agent Note: deleting one typo, running a dead-code tool once, removing an intentionally documented backend or adapter, or flagging "this looks complex" without call-site proof.
Survey broadly
Use parallel subagents when the user asks for breadth or many candidates. Give each agent a domain and require evidence, not guesses. Useful domains:
- Agent loop and session log: turn/step boundaries, steering, abort/cancel, durable events, replay, load/resume.
- Automation and human UI APIs: prompt settlement and teardown on the protocol side; transcript rendering and interaction state on the UI side.
- LLM/tools/system prompt: stream/generate APIs, assemblers, registries, tool schema defaults, presentation hooks.
- Bash and tool execution: foreground/background split, job ownership, output spill files, executor methods.
- Packages/examples/scripts/tests: package splits, static inventories, redundant snapshot expected outputs, support packages.
If subagents are unavailable, simulate the same breadth yourself. Do not let the first good candidate stop the survey.
Start with the largest production-code deltas. A broad audit that stops after obvious unused symbols can miss the files where duplicated lifecycle or defensive machinery carries most of the cost.
Audit trust and lifecycle boundaries
For every defensive copy, freeze, validator, and callback capture, name where the value came from and who owns it next. Same-process typed service/plugin calls ordinarily borrow readonly values; parsers, config loaders, queues, model/tool JSON, durable files, workers, processes, and wire decoders own or validate their data. Tests built around hostile getters, fake typed objects, callback replacement, or mutation after a same-process handoff are evidence of a potentially speculative contract, not automatic justification for keeping it.
For complex asynchronous code, draw the ownership graph and map each sentinel, readiness promise, cancellation path, disposer, and state flag to a distinct owner or transition. When several mechanisms mirror the same liveness or settlement fact, propose one transaction or lifecycle controller instead. Preserve separate machinery where it protects synchronous publication and rollback, callback containment, first-terminal-outcome arbitration, worker/process ownership, or dispose-to-quiescence.
Hand-rolled code versus a dependency
Introducing a dependency is a valid simplification move, not a policy exception; the repository's dependency policy, when recorded, owns the bar. When surveying, ask of protocol parsers, framers, retry/backoff loops, glob matchers, diff engines, and similar infrastructure: does a well-maintained package or a builtin at the repository's engine floor already do this?
Prove a dependency-swap candidate like any other, plus:
- Read the hand-rolled implementation and name the exact surface the package covers; residual semantics the package does not cover count against the swap and stay in the Agent Note.
- Check the package's health honestly (maintenance, adoption, transitive footprint) and prefer builtins when the engine floor has them.
- Check the Agent Note tree first: recorded seams are settled — a swap that collapses one needs to beat the recorded rationale, not just cite the policy.
- Weigh net deletion: implementation plus dedicated tests plus docs, minus the glue that remains. A wrapper that relocates the same complexity is not a win.
Prove or reject each candidate
For every symbol or behavior, classify consumers before writing:
- Production corpus: production source (e.g. , , ), runtime scripts, and loader/config paths.
- Non-production corpus: tests, README/docs, Agent Notes, snapshots, generated expected outputs, and comments.
- Ambiguous corpus: examples and scripts that may be product smoke paths. Inspect usage before classifying.
Use
first. Good searches include the exact symbol, event name, package name, config key, method name with both
and
, and any wire strings. Then read the call sites. A dead-code tool such as
can help, but it is not a substitute for understanding public interfaces, dynamic event names, tests, docs, and loader paths.
Reject or downgrade a candidate when:
- A production caller exists and the simplification would be a feature decision rather than a cleanup.
- The API is explicitly justified by an implemented Agent Note or a hard-won defensive pattern, and the new evidence does not beat that reason.
- The removal would force unrelated churn without actually reducing the public API or required behavior.
- The idea is correct but tiny. Add a targeted TODO/FIXME/XXX instead, using the urgency semantics in the repository's conventions doc.
Coalesce superseded Agent Notes
When the user asks to reduce or coalesce the note tree, or a simplification makes an owning note obsolete, follow the coalescing workflow: classify each old note fully or partially, consolidate through the note-archiving skill, and repair every inbound link before deleting a superseded triplet.
Write the Agent Note
Create one file per durable proposal under the repository's note tree — typically
.agents/notes/<lifecycle>/<class>/yyyy-mm-dd-topic.md
— following its lifecycle and classification rules. Keep prose paragraphs on one physical line and use relative Markdown links.
Prefer this structure, adjusting when the idea needs it:
# Agent Note: <action-oriented title>
- : name the current API, cite the relevant files, and state the consumer evidence. Separate production callers from tests/docs.
- : say exactly what to remove, fold, demote, or rehome. Include tests, docs, READMEs, JSDoc, event-taxonomy, snapshot, and generated-file cleanup when relevant.
- or : make the strongest counterargument legible.
- : observable end state and gates.
- : public API changes, behavior changes, future product wants, and why the tradeoff is still reasonable.
Be concrete enough that an implementing PR can follow the trail. Avoid vague "simplify this package" Agent Notes. When a proposal overlaps an existing Agent Note, consolidate the useful details into the existing one rather than creating a duplicate.
Inline TODO notes
Use inline TODO/FIXME/XXX only for small, local cleanups that are clearly useful but not durable design decisions. Keep them short and actionable:
- Name the smell with a stable tag, e.g. or .
- Explain why it is safe to revisit and what action would simplify it.
- Do not add TODOs for speculative complaints or for behavior that needs an Agent Note-level decision.
When folding another PR or branch
When folding simplification ideas from a sibling PR or branch, follow the folding workflow: diff against the base branch, port only the non-overlapping candidates that meet the bar, and update the PR body.
Validation and PR hygiene
For docs-only Agent Note work, run at least the repository's documentation gates, lint, and
— for example
plus
in a pnpm repo. For code or skill changes, also run the relevant validator when one exists. Select any other evidence from the outgoing diff; the pre-push hook contributes typecheck only.
When opening or updating a PR, summarize:
- How many Agent Notes and inline notes were added, consolidated, retained as partial supersessions, or deleted.
- The main areas surveyed.
- What was intentionally excluded.
- Which checks passed.
For each consolidation group, name the old and current owners, state the evidence for full supersession, and explain why deletion is safe. If an added-then-removed scan finds no qualifying note, report that result and the representative partial cases retained.
Use a draft PR while the survey is still expanding; mark ready only when the candidate set, review responses, and validation are settled.