AI Coding Made a Mess? A Safe Recovery Workflow for Your Codebase
Contents
If an AI coding agent has made your codebase worse, stop asking it to “fix everything.” Preserve what changed, reproduce the failure, restore a known-good boundary, and repair one observable behavior at a time.
The fastest recovery is usually not another large generation pass. It is reducing uncertainty until you know what is broken and why.
Step 1: Stop the agent before it creates more uncertainty
Do not keep prompting while the repository is in an unknown state. Every extra refactor can erase clues about which change introduced the problem.
First capture:
- the current branch and commit;
- the working-tree diff;
- which tests/build commands fail;
- the user-visible symptom;
- any generated files or migrations that changed state outside Git.
If the work is not committed, save the diff or create a temporary recovery branch before you start reverting pieces. The goal is to make every next action reversible.
Step 2: Separate “messy” from “broken”
A large diff can feel bad while still functioning, and a tiny diff can contain a severe bug. Define the failure in observable terms.
Examples:
- “Login now returns 500 after submitting valid credentials.”
- “The build fails because module X imports Y in a cycle.”
- “The page still works, but the agent duplicated the same validation in four components.”
- “Tests pass, but the agent bypassed the repository's existing service boundary.”
Those are different recovery jobs. Do not use “clean up the code” as the first prompt.
Step 3: Reproduce the problem with the smallest test
For a bug, create or identify a test that fails for the exact behavior. Run it and confirm the failure is real before changing implementation code.
A useful recovery test answers one question: what should happen that does not happen now?
If the problem is architectural rather than behavioral, use a deterministic check where possible: dependency rules, type checking, lint rules, schema validation, or a focused integration test.
Step 4: Find the smallest bad change
Read the diff instead of asking the model to summarize it from memory. Look for:
- new abstractions that duplicate existing ones;
- changes outside the requested scope;
- tests that were weakened instead of fixed;
- new dependencies added for trivial tasks;
- configuration or environment changes that alter runtime behavior;
- database or API contract changes hidden inside a UI task.
If several commits are involved, compare them against the last known-good revision. A binary search through commits is often faster than reading thousands of generated lines at once.
Step 5: Restore the known-good boundary, not necessarily the whole branch
A full revert is appropriate when the entire change is disposable. If part of the work is valid, restore only the files or commits that broke the invariant you care about.
For example, if the agent added a working UI but rewrote authentication unnecessarily, keep the UI diff and restore the authentication layer from the known-good revision. Then reapply the minimum integration change explicitly.
Avoid copying random fragments between versions until tests happen to pass. That produces a state nobody can explain.
Step 6: Fix one failing behavior at a time
Once you have a failing test and a bounded cause, ask the agent for the smallest implementation that makes the test pass. Then run the broader project checks.
A disciplined loop is:
- write or identify the failing test;
- run it and confirm the expected failure;
- make the minimum code change;
- run the focused test;
- run the full relevant suite;
- review the diff;
- commit a known-good checkpoint.
This gives you evidence after every repair instead of one giant “trust me” fix at the end.
Step 7: Remove duplication after behavior is stable
Do not start with a broad refactor if the system is already broken. Stabilize behavior first. Then remove repeated code or rename confusing abstractions while the tests stay green.
Refactoring with a known-good test suite is controlled work. Refactoring while you are still unsure which behavior is correct is guesswork.
Why AI agents create this kind of mess
The common cause is not that models are “bad at code.” It is that the agent is optimizing the current request with incomplete context. If the repository does not expose its architecture, conventions, and acceptance tests, a locally plausible solution can conflict with the system around it.
Large prompts also encourage large diffs. When the agent is asked to “build the whole feature,” it may create new helpers, rename existing modules, add dependencies, and restructure code before you have verified the first behavior.
Prevent the next incident with repository-level instructions
Store stable constraints in the repository instead of repeating them in chat. Cursor, for example, supports version-controlled project rules in .cursor/rules/ and plain AGENTS.md files. See Cursor's current Rules documentation.
Good instructions tell an agent:
- how to run tests, typecheck, lint, and build;
- which folder owns each responsibility;
- which public contracts must remain compatible;
- which files are generated and must not be hand-edited;
- how secrets and migrations are handled;
- what “done” means for the project.
Use reusable skills for processes that have several steps
If your team repeatedly needs the same debugging, release, migration, or review process, package that process as a skill rather than a long prompt pasted into every session. Cursor documents Agent Skills as reusable instructions that can be invoked when relevant. See Cursor Agent Skills.
The important part is not the format. It is moving critical process knowledge out of one conversation and into durable project context.
Do not let the agent weaken the evidence
One particularly dangerous “fix” is changing tests, validation, or configuration so the red signal disappears without restoring the intended behavior.
If a regression test existed before the AI change, treat it as part of the contract unless you have evidence that the requirement itself changed. A green CI run is meaningless if the agent made the gate easier instead of fixing the code.
A 20-minute recovery checklist
- Stop generation.
- Save the current diff on a recovery branch or patch.
- Run the project checks and record the first concrete failure.
- Compare against the last known-good commit.
- Create a focused failing test for the regression.
- Restore or fix the smallest responsible area.
- Run focused + full verification.
- Commit the recovery before starting cleanup.
The rule that prevents most AI-code disasters
Do not allow the amount of generated code to grow faster than your ability to verify it. The agent can write 1,000 lines quickly; that does not make a 1,000-line unreviewed diff a good unit of work.
Small requests, durable repository context, failing tests, and frequent known-good checkpoints turn AI coding from a slot machine into an engineering workflow.