Rhys Brett-Bowen Coding in the age of AI

Your Codebase Is the Prompt

updated

“We shape our tools and thereafter they shape us.” — John M. Culkin

Three carefully aligned stones setting a pattern and a fourth echoing their shape and spacing; one clay stone sets the standard.

The AI reads from your codebase before it writes into it. Whatever’s already there — your conventions, your shortcuts, your best work and your worst — is the prompt. Give Away the Writing, Keep the Reading argued that for code that has to be right, reading it is the check you can’t hand back. This is the other half: what the AI does to a codebase over time, and why your reading sets the direction.

BLUF: Bottom line up front

  • The AI tends to mirror your conventions — so keep the code it reads clean. Consistent code in, consistent code out; slop in, slop out.
  • On quality it tends to pull towards a competent-generic middle; your reading adds the delta. Hold the bar, or you just get more average code — faster.
  • Modernise in slices, not one rewrite. Raise one area with your reading; the AI then has a cleaner local base to match. Consistency is the lever.
  • Aim it at the code that changes most. What you’re actively changing sits in the AI’s context, so lifting those paths is where your reading travels furthest.
  • Try it now: before a big generation, hand the AI a clean example from your repo (or tidy the local file first). It tends to write to match what it sees.

The codebase conditions the AI

An AI conditions on the code around it — many repository-level completion systems work by pulling the surrounding code into the context window (RepoCoder, EMNLP 2023; RepoFusion trains models on repo context). Give it consistent conventions and it tends to match them; give it slop and its output fits right in. This is structure and idiom — the quality question comes next.

A stack representing the codebase conditions a model, which produces a code diff. A human reading gate either rejects the diff or admits an accepted change back into the codebase, where it becomes the next prompt.
The codebase conditions the model, which produces a diff; a human read either rejects it or admits it back into the codebase, where it becomes the next prompt.

Mirror on conventions, regress on quality

Be precise about what moves. On conventions — naming, structure, idiom — the model mirrors your repo. On quality it doesn’t mirror; my inference is that it pulls towards the competent-generic middle its training rewards. That’s a tendency, not a law, and it cuts both ways: it lifts code below that middle (I’ve watched AI pull clearly below-par code up toward that competent-generic middle) and drags your best down towards it — the very code you’d fight to protect. That drag is consistent with the trend GitClear reports (211 million changed lines, 2020–2024: duplication up, refactoring down) — though that’s copy-paste-vs-refactor across the field, not a measurement of your best code regressing on its own.

So for the code that matters, the model proposes at its middle and your reading pushes it above — when the reading is real. The model proposes. Your reading adds the delta.

A quality axis with a competent-generic middle. The model lifts weak code up toward that middle and drags excellent code down toward it, while a separate clay arrow shows the human read adding the delta above the middle.
The model pulls toward the middle. Your reading is the force that keeps your best above it.

Migrating a library, I let the AI collapse a pile of promise-based helpers into one clean handler type. It read well — until I noticed the old .on() handed back an unsubscribe you could call to detach a handler, while the rewrite had .on() return the emitter so calls could chain instead. The method was still there and the shape was cleaner. The unsubscribe had quietly gone. That’s not quality drifting toward the middle — it’s a silently removed contract, a correctness regression a read catches. Closing that gap is the delta.

// before: .on() returns an unsubscribe — you can detach the handler
const off = emitter.on("tick", update);
off();                       // stops listening

// after the "cleaner" rewrite: .on() returns the emitter, so calls chain
emitter.on("tick", update).on("error", onError);
// the unsubscribe is silently gone — a contract removed, tests still green

Which is how you modernise — in slices

That’s how you modernise a codebase with AI, and why it goes in steps, not one rewrite: raise a slice with your review, and the AI has a cleaner local base to match on the next. Amazon’s Q Code Transformation and IBM’s watsonx Code Assistant for Z are both scoped as incremental modernisation, not one-shot rewrites. And aim it: the old rule that quality work belongs on the code that changes, not the code that sits still (I make that case in How to Think About Code) sharpens here — the code you’re actively changing is what you point the AI at, so lifting the paths you touch most is where your reading propagates furthest.

Someone has built a codebase for this on purpose. Meta’s Astryx design system — open source, currently in beta — states it as a principle: “One system for humans and AI. Every change that made Astryx easier for AI made it easier for people too.” Astryx frames it as no tradeoff between the two readers, which is the part I’d have expected to bite. And it names the property it optimises for: conventions strong enough, and documented enough, that “both people and AI can predict how an unfamiliar component behaves.” That is a sharper definition of clean than I’ve been using. Not tidy. Not consistent for its own sake. Predictable to a reader who has never seen the file. Astryx ships a CLAUDE.md and a .claude directory as well. Those are the explicit part of the prompt. The conventions are the implicit part, and my inference is that the implicit part is the bigger one. I haven’t used it, and a stated principle is not a result. But it’s the first place I’ve seen the codebase-as-prompt treated as a design constraint rather than a consequence.

The slower loop

There’s a second loop at the scale of the whole field, and it’s a different mechanism. Models trained on model-generated output degrade: Shumailov and colleagues showed it and Nature published it (2024) — train recursively on generated data and the distribution loses its tails and collapses, generation over generation (irreversibly, in the regime where each model trains mostly on the last one’s output). That’s about training runs, not your afternoon; one unreviewed diff doesn’t collapse the next model.

But it’s the same shape a level up, and that level is yours. On the loop you control — your own repo — your reading sets the sign. Left alone, generated output becomes the next input, and for code above the model’s middle quality bleeds out: slop becomes the substrate the next writer — human or model — builds on. Ride the loop with a real read and the same feedback ratchets it up instead. Keep reading, and you’re the reason it gets better.


Sources

  • RepoCoder (EMNLP 2023) and RepoFusion — repository-level context conditioning.
  • GitClear, AI Copilot Code Quality — 211M changed lines, 2020–2024 (duplication up, refactoring down; correlational, vendor-authored).
  • Shumailov et al., AI models collapse when trained on recursively generated data, Nature (2024).
  • Amazon Q Code Transformation; IBM watsonx Code Assistant for Z — incremental modernisation.
  • facebook/astryx — Meta’s open-source design system (beta), README: “One system for humans and AI”; conventions documented so “both people and AI can predict how an unfamiliar component behaves.”

How sure I am: The mirror-and-regress claim is a tendency, not a law — marked as such in the text. That AI lifts below-middle code is my own observation, n=1 — an anecdote, not a measurement. The repo loop mirroring model collapse is an analogy and a prediction, not a demonstrated result. And “your reading adds the delta” is my model of where the value sits, not a proven claim. The Astryx reference is a design principle quoted from its README — a team’s stated intent, not a measured result, and not a system I’ve used.

Related: The Nit Was Never Optional (the small consistency call is the one that shapes what the model matches next); The Raw Is the Trust Boundary (a clean codebase as a partial raw — the mechanism behind this post’s claim); A Survivorship-Biased Corpus (what the code you kept is silently teaching, and what it never recorded); “Context Debt” Is a Strawman (the case against the tidy version of this argument).

Reading series, part 3 of 4 (start with Give Away the Writing, Keep the Reading). Next → Thinking at the Speed of Code.