# 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.

**Source:** https://graphlit.co/blog/ai-on-existing-codebase

**Published:** 2026-08-09

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

1. **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.
2. **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.
3. **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.
4. **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?
5. **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:

1. **Which files may this change touch?** Write the list. If you cannot, you do not understand the change well enough to supervise it.
2. **What must remain true afterwards?** The existing behaviour this must not disturb: the thing you will check.
3. **How will I know it went wrong?** A specific check, not "the app still loads".

> **The file list is the safety mechanism**
>
> It converts review from "read the whole diff and hope" into a question with an objective answer: did it stay inside the lines? A change that touches a file outside its allowlist is worth stopping on principle, before anyone reads what it did.

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.

*[Interactive demo: One task, fenced to an allowlist, verified before it is kept.]*

## 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.

*[Interactive demo: An existing repository, imported into a typed graph. The starting point, not the output.]*

Everything else in this article is easier once the map exists, and most of it is guesswork until it does.

## Frequently asked

### 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.

