Using AI on an existing codebase without breaking it
Almost every AI coding demo starts with an empty folder. Almost no real work does. Here is how to bridge the gap without wrecking something that already works.
The demo is always an empty directory. Your situation is four years of code, three people who have left, and a system that is currently making money, which means the downside of a bad change is not a wasted afternoon.
This is the harder problem and the more valuable one, and it needs a different method.
Why greenfield technique fails here
| Empty folder | Existing codebase | |
|---|---|---|
| Context needed | Your prompt | Four years of undocumented decisions |
| Cost of a wrong guess | Regenerate | Break something that works |
| Conventions | Whatever the model likes | Ones you must match exactly |
| Verification | Does it run? | Did anything else change? |
The last row is the crux. In greenfield, working is the goal. In brownfield, working is the starting position, and the entire risk is in unintended change elsewhere.
The method
Get a map before you get an agent
Know what the parts are and what calls what, before anything writes code. An agent let loose on a system nobody has mapped will produce changes nobody can evaluate. This is the step people skip and the one that decides the outcome.
Scope every task to named files
Not "add caching to the product page" but "add caching, touching only these four files". A scoped task can be reviewed by a person who did not write it; an unscoped one cannot.
Make the boundaries mechanical
Whatever rules keep the system coherent (which layer may call which) should fail a build rather than live in someone's memory. An agent will honour a check and cannot honour a convention it has not been told about.
Verify structurally, not just behaviourally
Tests tell you the behaviour you thought to test still works. Also ask: did this change touch files it had no business touching, and does the system's shape still match the map?
One task per commit
The single most valuable habit. When something breaks in a week, the difference between a five-minute bisect and a two-day investigation is whether commits are atomic.
Scoping, concretely
"Scope the task" sounds like advice until you have to do it. In practice it means answering three questions before the agent starts:
- 01Which files may this change touch? Write the list. If you cannot, you do not understand the change well enough to supervise it.
- 02What must remain true afterwards? The existing behaviour this must not disturb: the thing you will check.
- 03How will I know it went wrong? A specific check, not "the app still loads".
Graphlit enforces this directly: each task names the graph nodes it owns, which resolve to the files it is allowed to modify, and a run that edits outside that set is rejected rather than reviewed.
Sketch → shapes
deterministic
Shapes → typed nodes
model
Infer what wasn't drawn
model
Graph → ordered work
deterministic
One task, then stop
model
Green or reverted
deterministic
Drawing still true?
deterministic
› 6 shapes, 5 arrows, 6 labels recovered from the board
Where AI is genuinely strong on old code
It is easy to read the above as caution. There are places where AI is better on an existing codebase than on a new one:
- Explaining code nobody understands. Handing a model a gnarly file and asking what it does is genuinely excellent, and it is read-only, so the risk is zero.
- Mechanical migrations. Renaming an API across two hundred call sites, moving to a new library version, updating a deprecated pattern. Tedious, well-specified, and verifiable.
- Writing the missing tests. Adding characterisation tests to legacy code is exactly the kind of work people avoid, and it makes every later change safer.
- Finding duplication. "Where else does this pattern appear?" over a large codebase is a search problem models are good at.
Notice the pattern: these are all tasks where the correct answer is checkable. That is the real dividing line, and it is a better guide than greenfield-versus-brownfield.
The one thing to do first
If you take one action: import your codebase into a map before you point an agent at it.
Graphlit reads an existing repository (routes, services, tables, jobs and the calls between them) and produces a typed graph from it, with no drawing required. From there you can declare the rules that matter and scope work against real structure instead of guessing.
You do not have to start from a drawing.
Point it at a repository that already exists (a local folder, a git URL, or an upload) and the same graph comes out the other side.
Everything else in this article is easier once the map exists, and most of it is guesswork until it does.
Common questions
Can AI coding tools work on large legacy codebases?
Yes, with scoping. The failure mode is not code quality but blast radius: an unscoped change touching files nobody expected. Naming the files a task may modify converts review into a question with an objective answer.
What is brownfield development?
Working on an existing codebase rather than starting fresh. The distinguishing constraint is that the system already works, so the risk lives in unintended change rather than in failing to produce something.
Should I let an AI agent refactor my whole codebase at once?
No. Large refactors are exactly where verification is weakest, because the diff is too big to review and the tests were written for the old structure. Do it in scoped steps, one per commit, each independently revertable.
How do I give an AI tool context about my existing architecture?
A prose description helps but competes for attention and cannot be checked. The stronger approach is structural: a machine-readable map of the components and their relationships, plus dependency rules that fail a build when violated.
Draw it. Then keep it true.
Graphlit turns an architecture drawing into a typed graph, builds against it, and proves the code still matches. Free to start.