AI Adoption GuideSoftwareRetire
Codebase Cleanup Agent
Agent removes dead feature flag branches, config keys, and related tests after retirement completes, using tools like Trunk.io.
Software processDiscoverDesignBuildTestReleaseAdoptSupportRetire
By Don, DoneThat’s AI coach · updated
What this agent does
A codebase cleanup agent takes a completed feature-flag retirement as input and produces a focused pull request that deletes the leftover wiring. After a flag is fully rolled out or permanently off, the temporary branches, config keys, and tests that once protected both paths become dead weight. Leaving them in place slows reviews, confuses ownership, and raises the cost of the next change in the same area.
The agent does not decide when a flag is safe to retire. It assumes retirement already finished through your existing process (for example a rollout tool such as Trunk.io, LaunchDarkly, or an in-house flag service) and that you supply a machine-readable map of what was retired. From that map it locates stale conditionals, unused config entries, and tests that only exercised the removed path, then drafts a cleanup PR for human review.
Engineers still own merge. The agent never auto-merges. If the retired flag map is missing, incomplete, or cannot be resolved to a known flag identity, the agent produces empty output and stops rather than guessing.
Inputs the agent needs
Treat the retired flag map as a contract, not a hint. A useful map names each retired flag, its final state (always on or always off), the repositories or packages in scope, and any known aliases (env vars, config keys, SDK identifiers). Without that map, search results are ambiguous: many codebases reuse similar names across services, and a false-positive deletion is worse than leaving the flag in place for another sprint.
Pair the map with repository context the agent can query through your normal tools: source trees, test manifests, and config schemas. Point it at the same surfaces your team already uses for flag management. If Trunk.io or another platform recorded retirement events, prefer those records over ad-hoc chat notes so the agent works from an authoritative list.
Optional but valuable inputs include ownership metadata (CODEOWNERS, service catalogs) and recent change history for the flagged modules. Those signals help the agent keep PRs small and assignable. They do not replace the map. When the map is absent, return nothing; do not fall back to “scan everything that looks like a flag.”
How cleanup runs end to end
- Validate the map. Confirm every entry resolves to a known flag identity and a final state. Drop or escalate entries that fail validation. Emit empty output if the map itself is missing.
- Locate references. Search for conditionals, config keys, SDK calls, and test fixtures tied to each retired flag. Prefer exact identifiers from the map over fuzzy string matches.
- Classify removals. For an always-on retirement, keep the surviving path and delete the dormant branch. For always-off, delete the experimental path and any tests that only covered it. Leave shared helpers alone unless the map (or a follow-on dead-code pass) proves they are unused.
- Draft the PR. One PR per coherent unit of work: a single flag family, a single service, or a bounded package. Include a short summary that lists flags removed, files touched, and tests deleted or rewritten. Do not merge.
- Hand off for review. Route to the owning team. Reviewers verify behavior parity, run the usual CI gates, and merge when ready.
Keep the loop boring on purpose. Cleanup that silently edits main or batches dozens of unrelated flags into one PR creates review risk and teaches teams to ignore the agent.
Guardrails reviewers should enforce
Human-in-the-loop is the product requirement, not a nice-to-have. The agent drafts; engineers review and merge. That split keeps cleanup fast without transferring production responsibility to an unattended job.
Empty output on a missing map is equally non-negotiable. A cleanup agent that invents targets from heuristics will eventually delete a live experiment or a similarly named config key in another environment. Fail closed.
Do not auto-merge, even when CI is green. Flag removal can change runtime behavior in ways unit tests miss: default values in config loaders, cached payloads, or admin UIs that still list the flag. Reviewers should check those edges explicitly.
Prefer small, reversible PRs. If a flag’s references span multiple deployables, split by service so each merge can roll forward independently. If the agent cannot prove a test is solely for the retired path, leave the test and note the uncertainty in the PR description instead of deleting it.
Avoid rewriting adjacent code “while you are there.” Cleanup PRs that also rename modules or refactor control flow hide the retirement diff and slow approval. Follow-up agents or humans can handle broader dead-code and migration work after the flag surface is gone.
What good output looks like
A strong cleanup PR is dull to read and easy to verify. The title names the retired flag and the final state. The description links to the retirement record (Trunk.io event, ticket, or changelog entry) and quotes the map entries used. The diff removes conditionals and config keys without introducing new abstractions. Tests that only asserted the discarded branch disappear; tests that still protect the surviving behavior stay, updated only as needed for compilation.
CI should pass with the same suite the team already trusts for that package. If the agent had to delete or skip a test it could not confidently classify, the PR should say so in plain language so reviewers know where to look.
When there is nothing safe to do (no map, no resolvable references, or only ambiguous hits), empty output is the correct result. Silence is better than a speculative PR that burns review time and erodes trust in the workflow.
How this fits a retire-stage practice
Feature-flag retirement is incomplete until the code catches up. Platforms can mark a flag as done while repositories still carry both paths for months. A cleanup agent closes that gap as a scheduled or event-driven step after retirement completes, not as a substitute for product or SRE judgment about when to retire.
Use it alongside, not instead of, broader hygiene. A Dead Code Detector can find leftovers the flag map never named. A Dependency Usage Analyzer helps when removing a flag also drops a library that only served the experiment. A Migration Guide Generator helps when external consumers or other teams still need to know which config keys disappeared.
Measure success in operational terms: time from retirement event to merged cleanup PR, review cycle count, and incidents attributable to incorrect removals (ideally zero). Keep the agent conservative, keep humans in the merge path, and keep empty output as the default when evidence is thin. That combination turns flag retirement from a lingering tax into a finished change.
Is this worth automating for you?
Whether this pays back depends on how much time it takes your team today. Most teams estimate that from memory, and the estimate is usually wrong in one direction or the other. This one is rated high effort to implement, so the baseline matters more than usual.
DoneThat reconstructs where the time actually went, with no timers to forget, so you can measure the baseline before committing to a project and check the gain afterward.
Measure the baseline first