The Two-Model Pruning Cycle: How to Simplify an AI-Assisted Codebase Safely
AI-assisted feature delivery and repository simplification are separate jobs: a working change can still leave duplicate implementations, dead paths, obsolete tests, or stale guidance. The two-model pruning cycle addresses that residue with independent analysis of one revision, evidence-based reconciliation, a small reversible implementation batch, and a second review of the actual diff and validation results.
A working feature can leave duplicate paths
Consider a service that already has a function for normalizing customer addresses. You ask an AI coding agent to add regional formatting. The feature ships, the tests pass, and customers get the expected result.
But the agent has added a second normalization path beside the first. One endpoint calls the old path. Another reaches the new one through a wrapper. A compatibility test still describes behavior that nobody intends to support. The repository instructions tell future contributors to use a helper that the new code bypasses.
The repository now contains two nearly equivalent answers to the same question. Before making another change, the next person or agent has to determine which implementation is authoritative.
This example is hypothetical, but I recognize the pattern from my own AI-assisted development. Repeated feature work can leave extra implementations, wrappers, tests, and instructions behind. I have not measured a universal rate of code growth, and I do not assume that every model or feature produces this result. I am describing residue I have found while maintaining real projects.
The important measure is the maintained surface: all the code and supporting material that looks active enough to demand attention. A short duplicate function can create more uncertainty than a long module with clear ownership.
My working explanation is that a feature task can be completed correctly while retirement of the previous path remains outside its scope. I therefore assign pruning as its own maintenance job instead of expecting every feature prompt to produce it automatically.
The model does not literally hate the delete key
Saying a model “hates the delete key” is a playful metaphor. The proposed explanation is that language models generate tokens, deletion produces fewer tokens, and models therefore prefer adding code. That conclusion does not follow from the mechanics of text generation.
Autoregressive language models generate successive tokens, or pieces of text, based on the prompt and prior output. Decoding works with next-token probability distributions, and the model does not always have to choose the single most likely token. The Hugging Face text-generation guide gives a useful overview of those mechanics.
Those mechanics do not prevent a model from proposing a deletion. A patch that removes a thousand lines is still represented through generated tokens. Next-token generation explains how the model produces text. It does not establish a motive to preserve code in a repository.
Training and runtime conditions add more to the explanation. Historical work on instruction-following language models describes how demonstrations, ranked outputs, and reinforcement learning can shape behavior beyond a base next-word objective. It is historical evidence, not a disclosure of how every current system is trained. It does show why token prediction alone cannot explain the behavior we observe. Instructions, tools, retrieved context, and task scope also matter.
Research also resists the blanket claim that AI always writes more code. A 2026 observational study of merged GitHub pull requests found that agent-authored changes in its sample were generally smaller and more localized than the human-authored changes used for comparison. The study examined pull-request characteristics. It did not establish the lifetime maintenance value of the resulting repositories or isolate a causal effect from token generation.
The practical question is which working conditions allow obsolete paths to survive, and how we can check those paths safely.
Why useful feature work can still leave residue
Repository access does not give an agent simultaneous understanding of every file. Coding agents can search for symbols, inspect directories, load selected files, and retrieve more context as a task develops. Anthropic’s discussion of context engineering for AI agents describes this incremental, just-in-time retrieval. An agent may inspect a large part of a repository when the task calls for it. Access alone does not mean that every file is present in context or understood at once.
Instructions such as “check first,” “reuse existing utilities,” “avoid duplication,” and “follow existing patterns” are useful starting points. Inference: they are not complete repository audits unless the search scope and supporting evidence are visible. A quick check can miss an indirect entry point, an older implementation with different terminology, or a rule stored outside the directory being searched.
Feature work also rewards local completion. If the immediate request is regional address formatting, a narrow adapter may be the shortest supported route. The older path can remain untouched because the task never gathered enough evidence to retire it safely.
The two tasks have different objectives:
- Feature work asks, “How do we make this behavior work?”
- Pruning asks, “Which implementation should remain, what still depends on it, and what can be retired without changing required behavior?”
If nobody assigns the second job, residue can survive even when the first job was done well.
Pruning is a behavior-preservation job
Pruning is maintenance and refactoring: improving the internal structure while preserving required behavior. A smaller diff or lower line count alone cannot establish that a change meets that goal. Martin Fowler’s definition of refactoring puts that preservation at the center.
In my own pruning passes, I look for several kinds of residue, each of which requires evidence:
- competing implementations that can be consolidated;
- code shown to be unreachable or unused;
- obsolete or redundant tests;
- stale repository guidance;
- workflows that still point to an older path.
Suppose a text search finds no callers for a function. That makes the function a candidate, not a safe deletion. It may still be reached through an export, package entry point, configuration file, script, plugin, dynamic import, worker, generated registry, CI command, or external consumer. The documentation for Knip’s entry-file analysis shows how broad entry-point discovery can become in a JavaScript or TypeScript repository. Knip is useful in that ecosystem, but it is not a universal proof system.
Tests need the same care. Age, inconvenience, or a current failure does not make a test obsolete. First identify the supported behavior it protects. Keep relevant regression coverage. Adapt useful tests when implementations are consolidated. Remove a test only when its expected behavior has been demonstrably retired or its coverage is redundant. Never delete a failing test merely to make a cleanup pass succeed.
Repository governance belongs in the review too. In this context, governance means the material that steers future work: contributor notes, agent instructions, review checklists, CI rules, migration notes, and similar repository-local guidance.
Before retiring a rule, find out why it was introduced and whether that reason still applies. When the architecture changes, update the active guidance in the same change. Otherwise the repository may teach the next contributor to recreate the structure you just removed.
Inference: removing obsolete implementations and instructions can reduce what people and agents must sort through during later changes. The goal is preserved behavior, clear ownership, and a structure that is easier to understand; code size alone is insufficient.
One pruning cycle, two independent views
I use one recurring cycle with two independent reviews. The reviewers can be different model families, different configurations, or separate sessions whose initial analyses are deliberately isolated. I often pair Claude and Codex. In my experience, that cross-review has helped me catch deletion mistakes and maintain a stable, regularly pruned codebase. That is an account of my practice, not a promise of permanent stability for every repository.
Whichever models you use, begin by fixing the object of review. Record the repository revision, preferably with an immutable commit identifier, and list the behavior and interfaces that must remain. Include relevant commands, supported platforms, public exports, compatibility requirements, and anything explicitly approved for retirement.
Give Model A and Model B the same revision and retained requirements. Each should complete an initial analysis before seeing the other’s conclusions. The reports should identify what was inspected, what was not, the evidence behind each candidate, possible remaining dependencies, and the validation that would make removal safer.
Reconcile the results candidate by candidate, using the evidence in both reports to determine:
- what it does;
- whether a retained requirement still needs it;
- how it is reached;
- what would replace it, if anything;
- which tests or guidance must change with it;
- what uncertainty remains.
Agreement does not prove that a deletion is safe. A research preprint on multi-agent debate cautions that consensus-seeking protocols can filter out useful disagreement. It does not evaluate Claude and Codex performing repository pruning, but the warning applies: preserve disagreement until evidence resolves it.
When the evidence is weak, or the reviewers disagree about a live dependency, defer the candidate. Record the missing fact needed to reconsider it.
After identifying a small supported set, appoint one model as the writer for a reversible batch. Run baseline checks first. Preserve supported public interfaces and current requirements unless their retirement is explicitly in scope. Keep the batch narrow enough to inspect and revert without separating unrelated edits.
The other model then audits the actual diff and the validation results. It should review removed tests, modified exports, changed configuration, and updated guidance along with the source code.
A green test run is useful evidence. It cannot show by itself that the right tests ran or that every supported entry point was covered. A clean static-analysis report has the same limitation. Keep or reject the batch based on the evidence taken together.
Deferred candidates become input to a later cycle. They do not need to expand the current cleanup patch.
Paste-ready prompts for Model A and Model B
These prompts are provider-neutral. Replace the bracketed fields with facts from your repository.
When the sessions or tools are not connected, neither model can automatically see the other report, repository state, or validation output. Supply the same revision and retained requirements to both, then transfer reports and diffs manually at each handoff.
Model A: independent analysis
You are Model A, the first independent reviewer in a behavior-preserving
repository-pruning cycle.
Repository revision:
[IMMUTABLE COMMIT OR REVISION]
Retained requirements:
[SUPPORTED BEHAVIOR, PUBLIC INTERFACES, PLATFORMS, AND CONSTRAINTS]
Explicitly approved retirements:
[ITEMS, OR "NONE"]
Available validation commands:
[COMMANDS AND WHAT EACH COMMAND COVERS]
Analyze only. Do not edit files.
Look for:
- duplicate or competing implementations;
- wrappers and compatibility paths that may no longer be needed;
- unreachable or unused code;
- obsolete or redundant tests;
- stale repository instructions, review rules, CI rules, and migration notes;
- workflows or automation that still reference an older path.
For every candidate, report:
1. exact files and symbols;
2. the candidate’s apparent purpose;
3. concrete evidence of usage or non-usage;
4. entry points and indirect references checked, including applicable
configuration, imports, exports, scripts, plugins, dynamic loading,
workers, automation, and external-interface risk;
5. retained behavior or public interfaces that could be affected;
6. tests and guidance that protect or describe the candidate;
7. proposed validation before and after a change;
8. uncertainty, missing evidence, and reasons to defer.
A missing text-search result is not sufficient evidence for deletion.
Do not optimize for line-count reduction.
Do not assume another reviewer will agree.
Return an evidence report, a clearly labeled candidate list, and explicit
deferrals.
Model B: independent analysis
You are Model B, the second independent reviewer in a behavior-preserving
repository-pruning cycle.
You must complete your initial analysis without seeing Model A's conclusions.
Repository revision:
[THE SAME IMMUTABLE COMMIT OR REVISION GIVEN TO MODEL A]
Retained requirements:
[THE SAME REQUIREMENTS GIVEN TO MODEL A]
Explicitly approved retirements:
[THE SAME RETIREMENT SCOPE GIVEN TO MODEL A]
Available validation commands:
[THE SAME COMMANDS AND COVERAGE NOTES GIVEN TO MODEL A]
Analyze only. Do not edit files.
Independently identify possible duplicate implementations, dead paths,
obsolete or redundant tests, stale governance, and outdated workflows.
For every candidate, provide:
- exact location and current purpose;
- observable supporting evidence;
- search and inspection scope;
- applicable entry points, configuration, imports, exports, scripts,
plugins, dynamic loading, workers, automation, and external consumers;
- behavior, tests, or instructions that could still depend on it;
- a safe validation plan;
- confidence and counterevidence;
- a clear deferral when evidence is incomplete.
Do not infer safety from a missing search result, test age, model confidence,
or expected line-count reduction.
Return your independent evidence report before reading Model A's report.
Evidence-based reconciliation
Reconcile the two independent pruning reports below.
Repository revision:
[SHARED IMMUTABLE REVISION]
Retained requirements:
[SHARED RETAINED REQUIREMENTS]
MODEL A REPORT:
[PASTE REPORT]
MODEL B REPORT:
[PASTE REPORT]
Do not force consensus and do not treat agreement as proof.
For each candidate:
1. align the two reports on the exact file, symbol, rule, or test;
2. list evidence supporting retirement;
3. list evidence supporting retention;
4. identify any difference in search scope or assumptions;
5. decide one of:
- supported for a small reversible batch;
- retain;
- defer pending named evidence;
6. specify baseline checks, post-change checks, and manual inspections;
7. identify code, tests, configuration, automation, and active guidance
that must change together.
Preserve unresolved disagreement in the record. Recommend the smallest
coherent batch whose safety is supported by observable evidence.
Model A: scoped implementation
You are the sole writer for this pruning batch.
Repository revision and working state:
[REVISION AND CLEAN/KNOWN WORKTREE STATUS]
Retained requirements:
[REQUIREMENTS]
Approved batch:
[PASTE ONLY THE RECONCILED, SUPPORTED CANDIDATES]
Deferred and prohibited items:
[PASTE DEFERRALS, PUBLIC INTERFACES, AND OUT-OF-SCOPE AREAS]
Baseline results:
[COMMANDS, OUTPUT SUMMARY, AND ANY KNOWN FAILURES]
Implement only the approved batch.
Requirements:
- preserve retained behavior and public interfaces unless retirement is
explicitly approved;
- keep the change small and reversible;
- update affected tests rather than deleting failures for convenience;
- remove tests only when the reconciled evidence shows they are obsolete
or redundant;
- update active repository guidance, configuration, and workflows in the
same change when their references become stale;
- do not act on deferred candidates.
After editing, run the approved validation. Return:
1. a concise diff summary;
2. exact files changed;
3. validation commands and results;
4. tests, rules, exports, or entry points removed or modified;
5. remaining uncertainty;
6. anything that should cause the batch to be reverted or narrowed.
Model B: post-change audit
You are the independent post-change auditor. Review the actual change, not
the implementation plan.
Base revision:
[BASE REVISION]
Retained requirements:
[REQUIREMENTS]
Approved batch and deferrals:
[RECONCILIATION RECORD]
Actual diff:
[PROVIDE THE DIFF OR ACCESS TO THE EXACT CHANGED REVISION]
Baseline and post-change validation:
[COMMANDS, COVERAGE NOTES, RESULTS, AND KNOWN FAILURES]
Audit:
- every changed and deleted line;
- retained behavior and public interfaces;
- applicable entry points, configuration, imports, exports, scripts,
plugins, dynamic loading, workers, and automation;
- removed or modified tests and the behavior they protected;
- repository instructions, review rules, CI rules, and migration notes;
- whether any deferred candidate was changed accidentally;
- whether validation actually covers the affected behavior.
Do not approve merely because tests pass, tools report no references, the
diff is smaller, or both reviewers previously agreed.
Return prioritized findings with concrete evidence. For each finding,
state whether to block, revise, revert, or investigate. If no blocking
issue is found, state the residual risks and why the available evidence
supports keeping this batch.
Make deletion an explicit recurring job
A useful pruning pass preserves required behavior, clarifies ownership, removes obsolete paths, and brings active instructions into line with the remaining code. Deletion counts alone cannot tell you whether it succeeded.
I recommend pruning often enough that the evidence is still recoverable. People may still remember why a wrapper exists, migration notes may still have context, and the cleanup may still fit into a small batch separate from feature work. The right frequency depends on the repository and the team.
Make this a recurring assignment: gather independent evidence, prune a small reversible batch, and validate the actual diff before keeping it.