Best Practices for Coding Agents Start With a Legible Codebase
Last updated:
Every time a coding agent opens your repository fresh, it starts from nothing it can rely on. It doesn’t know your commit conventions, so it guesses at them. It doesn’t know how you cut a release, so it reconstructs the steps from shell history and inference. It doesn’t know you already have a script for the exact thing it’s about to do, so it writes that thing again, a little differently, inline. Almost none of this surfaces as an error. It surfaces as wasted time, output that drifts from how your team actually works, and a senior engineer who quietly becomes the bottleneck because the real answers only live in their head.
That is the cost worth naming before any argument about which agent or which model to use, because it is the cost that scales with every session and every new person or agent you add. A better model shortens the time the agent spends thinking. It does nothing about the time the agent spends re-deriving facts about your project that were never written down. In my experience the second number is the bigger one, and it is the one you can actually do something about this week.
So here is the claim this post is built on, stated plainly: most of what makes a coding agent
effective on a real codebase is not the model, it’s whether the codebase is legible to the agent.
The rest of this is what legibility means concretely, plus a worked example of the minimum mechanism
that delivers it. The example is a small open-source kit I pulled out of my own daily workspace,
agent-context-kit; I dogfood it because that is the only way I came to trust it.
What makes a codebase legible to a coding agent?
A codebase is legible to a coding agent when the agent can find the project’s conventions, procedures, and existing automation on its own, instead of re-deriving them from scratch every session. It is a property of how the project is written down, not a feature of the agent: either the answer to “how does this project do X” is discoverable in the repository, or the agent guesses and you review the guess. Legibility is the difference between an agent that acts like it has worked here before and one that acts like it is seeing the place for the first time — every time.
Three questions decide it, and each maps onto a kind of knowledge every project already has:
- Are your conventions written down somewhere the agent will actually look?
- Are your operational procedures documented, or do they live as tribal knowledge in one person’s memory?
- Is your existing automation discoverable, or does it get silently reimplemented?
Each of those has a failure mode you have already paid for, and each has a fix that is mechanical rather than clever. The sections below take them one at a time. Get all three right and the agent stops needing you as its memory: the engineer stops answering the same questions, and the manager stops seeing the same rework land in review.
The bottleneck is legibility, not the model
The default move, when an agent underperforms on your codebase, is to reach for a bigger model or a more elaborate prompt. Sometimes that helps. More often it treats a symptom. An agent that reimplements your logging helper because it never found the existing one will do exactly the same thing on a stronger model, just with tidier code wrapped around the duplication.
It is worth being honest about the full set of reasons an agent keeps getting things wrong, because the right fix depends on which one is actually true:
- The model isn’t capable enough. Real sometimes — but the least common case on mainstream work today, and the most expensive to bet on.
- The prompt is underspecified. Fixable, but it fixes one task; the next session starts cold again.
- Everything got stuffed into one giant instructions file. This scales badly. The file grows until it strains the context budget, goes stale in the parts nobody re-reads, and still doesn’t cover the operational task you happen to be doing right now.
- The knowledge the agent needed was never written down anywhere it looks. This is the common one, and the only one whose fix compounds across every future session.
I prefer to fix the last one first, and to fix it as durable, discoverable project artifacts rather than as prompt text. Prompt text helps the current task. A convention written into the repository where the agent is trained to look helps every task, every agent, and every human who joins later. A better prompt improves one session; a legible codebase improves every session that will ever run against it. That is the whole reason to spend the effort here instead of on prompt-tuning: the return is multiplied by how many times anyone touches the project, and for a codebase under active development that number only goes up.
Write conventions down where the agent looks
Start with conventions, because they are the decisions your team has already made and does not want reopened. Commits use imperative mood. Every service runs in a container. Build artifacts stay out of the source tree. These are settled. When they live only in reviewers’ heads, an agent re-litigates them on every task, and you catch the drift in review if you catch it at all. The reviewer becomes a linter for decisions that were made months ago.
The fix is to write each convention down as a short document in the place the agent is told to read
before it starts, and to make that reading a standing instruction rather than something you remember
to paste in. In agent-context-kit this is the directives skill: conventions and standards stored
as markdown files in a project’s docs/ folders, each with a one-line description so the agent can
tell what’s relevant to the task at hand without reading every file in full. Before any task, the
agent loads the directives that match what it’s about to do. “Commits use imperative mood” stops
being tribal knowledge and becomes a fact the agent reads before it writes the commit.
The shape is deliberately boring. A directive doc is just a few lines of frontmatter above the prose:
---
description: one-line summary of what this doc covers
scope: root
covers: [commits, git, workflow]
---
The point of that frontmatter is cheap discovery. A companion script reads only the description and
covers fields across every doc, so the agent can match a task to the handful of relevant
conventions without opening and reading all of them first. On a project with fifty convention docs,
that is the difference between a fast, focused load and burning the context window on documents that
have nothing to do with the work in front of you. Written this way, a convention is enforced by being
read at the right moment rather than by a reviewer noticing its absence after the fact, which is how
the engineer stops repeating themselves and the decision-maker stops paying for the same
course-correction twice.
Document the procedures instead of remembering them
Conventions govern how code should be written. They say nothing about how to actually carry out the recurring operational tasks: cut a release, rotate an access token, run the deploy, regenerate a report. Those procedures are where tribal knowledge hides most dangerously, because the steps are exact, the order matters, and getting one wrong has consequences a style violation never does. When the procedure lives in one engineer’s memory, the agent either asks that engineer, which defeats the point, or reconstructs the steps and gets one subtly wrong.
Write the procedure down as an ordered, followable list, once, and point the agent at it before it
attempts the task. agent-context-kit calls these how-tos: step-by-step operational procedures in
how-tos/ folders, read before an operational task instead of reconstructed from memory. A how-to
for cutting a release is six numbered steps the agent executes in order. It is emphatically not a
paragraph of remembered context that quietly omits step four because whoever wrote it does step four
on autopilot.
Keeping this distinct from conventions matters, because the two get conflated. A directive says “commits use imperative mood,” a rule that holds everywhere. A how-to says “to cut a release, do these six things in this order,” a procedure for one specific task. A convention is a rule that is always true; a procedure is a sequence you follow when you’re doing one particular thing. Filing them in separate systems means the agent loads only the procedure it needs when it needs it, and only the conventions that apply to what it is writing. That turns “ask the one person who knows” into “read the file,” which is exactly the dependency you want gone before it becomes a single point of failure for both delivery and the person carrying it.
Make automation discoverable, not reimplemented
The third kind of knowledge is the automation you already have. Most non-trivial projects accumulate
a scripts/ folder over time: a report generator, a token minter, a deploy wrapper. The failure mode
here is quiet and expensive. The agent needs to do something a script already does, doesn’t know the
script exists, and writes the logic again inline. Now you have two implementations of the same task
drifting apart, and the reviewer has to spot the reinvention to stop it.
Making automation discoverable means the agent can find and understand what a script does before
deciding whether to run it or duplicate it. agent-context-kit’s scripts skill does this, and its
central design choice is worth stealing even if you never install the kit: it uses each script’s own
--help output as the source of truth for what the script does, not a comment header. A comment
header drifts from the code the instant someone changes the behaviour and forgets the comment.
--help is generated from the same code that runs, so it cannot misdescribe the flags without the
script itself breaking first.
That choice carries a hard requirement, and it is a healthy discipline with or without an agent in
the picture: every script must implement --help properly. Always available, exits zero, no side
effects, fast, and printing a real description and usage instead of a bare flag list. The discovery
mechanism runs --help on every script it considers, so a script whose --help is broken or has
side effects breaks discovery itself. In practice this pushes you toward scripts that describe
themselves honestly, which is worth having whoever ends up reading them. When existing automation is
discoverable, the agent runs what you already built instead of rebuilding it worse: you stop
maintaining three versions of the same deploy step, and the engineer stops reviewing reinventions of
problems that were already solved.
Give the agent one front door
Writing conventions, procedures, and script discovery into the repository does nothing on its own if the agent never loads them. Installing the mechanism makes it available; it does not make the agent reach for it before relevant work. Something has to tell the agent, at the start of every task, to go and look. That is the job of a single entry-point file.
The emerging cross-tool convention for that file is AGENTS.md at the repo root: a short standing
instruction that tells the agent to load the relevant conventions before any task and the relevant
procedure before any operational one. agent-context-kit leans on this directly. Each skill
documents a small block to paste into AGENTS.md, and the file is treated as canonical. If your
agent is Claude Code, which reads a file called CLAUDE.md, that file gets a single import line
pointing at AGENTS.md rather than a second copy of the same instructions, so there is one source of
truth and not two that drift.
One reason to prefer an open entry-point file over a vendor-specific one is that the whole approach is
built on an open format to begin with. The skills in the kit are SKILL.md files, a published
specification that several agents read, rather than one company’s proprietary layout. The same three skills
work with Claude Code, Codex, Cursor, OpenCode, and more, and they run on plain Python with Git,
identically on Linux, macOS, and Windows. If you standardise your project’s legibility on an open file
the way you would standardise on an open config format, you don’t have to redo the work when you
switch agents or add a second one. A single open front door is what turns a pile of well-written docs
into something the agent actually reads at the right moment, without tying your project’s legibility to
one vendor you might not be using next year.
Start where re-derivation costs you most
You do not have to write all of this at once, and trying to is how the effort stalls. The right first move is not the most complete one; it is the one that removes the re-derivation you pay for most often. So watch one agent work on your codebase for a day and note where it guesses, asks, or reinvents. That is your backlog, in priority order, for free.
In my experience the highest-frequency waste is usually conventions, because they touch nearly every task, so that is where I start: a handful of short directive docs for the decisions you are tired of seeing re-litigated in review. Procedures come next, written down the first time an agent gets one wrong, because that is the moment you have proof the knowledge was tribal. Script discovery lands last of the three for most teams, since it only pays off once you have enough automation worth reinventing, though a project already thick with scripts might reasonably flip that order. The point is to let observed cost drive the sequence rather than documenting everything to the same depth on day one.
One compounding effect is worth stating outright. These three kinds of knowledge reinforce each other: a procedure step that is automatable should point at a script instead of restating the command, and a convention about your git workflow governs how the tooling commits its own changes. Written together, they stop being three separate piles of documentation and become a single legible surface the agent reads the right slice of for whatever it is doing. Sequencing by observed cost is what makes the first afternoon you spend on this pay for itself inside the first week, which is the version of this work a decision-maker can approve and an engineer can actually finish.
Where this leaves you
The teams getting real work out of coding agents are not, mostly, the ones with privileged access to a better model. They are the ones whose projects an agent can read: conventions written where the agent looks, procedures documented instead of remembered, automation it can find instead of rebuild. That work is unglamorous and largely mechanical, which is precisely why it gets skipped in favour of prompt-tuning that feels like progress and compounds far less.
None of it requires the kit I used as the example here. agent-context-kit is one open-source way to
get there, and its ideas carry even if you build your own: conventions in docs/, procedures in
how-tos/, automation discoverable through --help, and one open AGENTS.md front door. The gap
between an agent that acts like a stranger in your codebase and one that acts like it has worked here
before is closed by what you write down, not by what you prompt. That holds in every domain, and it
bites hardest where the feedback loop is already expensive: in embedded work, the same legibility
question often decides whether an agent can do useful work at all (I make that case in
Why Embedded Is a Better Place for AI Agents Than Web Development).
Writing your project down for an agent is a decision available to you this week, and it pays back
every session that runs after it.
Frequently asked questions
What does it mean for a codebase to be "legible" to a coding agent?
A codebase is legible to a coding agent when the agent can find the project's conventions, operational procedures, and existing automation on its own, instead of re-deriving them every session. It's a property of how the project is written down, not a feature of the agent: either the answer to "how does this project do X" is discoverable in the repository, or the agent guesses and you review the guess.
Is a coding agent's effectiveness mostly about the model or the codebase?
On a real, non-trivial codebase, most of it is the codebase. A stronger model shortens the time the agent spends thinking, but it does nothing about the time spent re-deriving project facts that were never written down. That second cost usually dominates, and it's the one you fix by making conventions, procedures, and automation discoverable.
What's the difference between a directive, a how-to, and a script?
A directive is a convention that's always true ("commits use imperative mood"). A how-to is an ordered procedure you follow for one specific operational task ("to cut a release, do these six steps"). A script is the executable automation itself, made discoverable through its own --help output so an agent can find and run it instead of reimplementing it. They compose: an automatable how-to step points at a script rather than inlining the command.
What is AGENTS.md, and why not just use a Claude Code CLAUDE.md?
AGENTS.md is an emerging cross-tool file at the repo root that tells any coding agent to load the relevant conventions and procedures before it starts work. It's treated as canonical because it isn't tied to one vendor: several agents read it. If you use Claude Code, its CLAUDE.md gets a single import line pointing at AGENTS.md rather than a duplicate copy, so there's one source of truth instead of two that drift apart.
Why use a script's --help as the source of truth instead of a comment header?
A comment header drifts from the code the moment someone changes the behaviour and forgets to update the comment. --help is generated from the same code that runs, so it can't misdescribe the script's flags without the script itself breaking. The trade-off is a discipline requirement: every script must implement --help properly (always available, exits zero, no side effects, fast, real usage), because the discovery mechanism runs it on every script it considers.