AI coding

Teaching an Agent Your Codebase Conventions

Antonio Evans10 min read

A developer and a robot sit side by side at a table covered with blueprint-style diagrams of a codebase.
Key points

Key points

  1. 1Agents over-edit because they lack your local conventions and default to generic patterns, so the fix is explicit context, not stronger prompting.
  2. 2Store naming, structure and style rules in a versioned file at the repo root (CONVENTIONS.md or AGENTS.md) with concrete examples, not adjectives.
  3. 3Feed rules at the moment of writing: load the file into the system prompt, reference it in the task spec, and enforce it with a pre-edit hook.
  4. 4Measure the result by comparing diff size against the minimal fix, since passing tests hides over-editing entirely.

Why agents rewrite working code

Ask a model to fix an off-by-one error and you often get the bug fix plus rewritten input validation, renamed variables, new helper functions and a different plotting path. The diff is huge, and the reviewer now has to re-understand a function that previously worked. This is the over-editing problem: the output is functionally correct but structurally diverges from the original far more than the minimal fix requires, as documented in a study of 400 corrupted BigCodeBench problems where the correct edit was constructed as the exact reversal of a single operator flip or boolean swap (nrehiew.github.io).

The important detail for anyone writing conventions is why tests do not catch it. Over-editing is a brownfield failure: the code compiles, the tests pass, and nothing in CI flags that the model rewrote half the module. The study makes the point directly, that over-editing is invisible to test suites even though it degrades codebase quality over time (nrehiew.github.io). Practitioners describe the same failure and report that the fixes which stick are the ones recorded in the project's own instruction files, not one-off prompt corrections (news.ycombinator.com).

Where the generic behavior comes from

A model has no memory of your repository. It has seen millions of functions, and the statistical center of that corpus is a reasonably defensive, reasonably verbose style that is probably not yours. When it touches a file, the cheapest continuation it can produce is the pattern it has seen most: explicit null checks, type conversion helpers, defensive validation. Nothing about the task asked for those, but nothing in the context forbade them either.

Stack Overflow's guidance for agent coding standards frames the gap as onboarding without tacit knowledge: a human junior learns conventions by watching nearby code and absorbing patterns nobody wrote down, while an agent arrives with none of that and takes nothing for granted (stackoverflow.blog). If your front end uses Express, an agent with no context may produce React, because both are plausible completions of "build a web UI."

The scope problem is the same problem

The pattern shows up in autonomous pipelines too. One practitioner running parallel implementation agents found that instruction-only requests like "only change what the task requires" helped a little and not nearly enough, because from inside the task, renaming a confusing variable feels like doing a good job. The conclusion is the useful part: instructions describe intent, while a guarantee needs a mechanism (dev.to). Conventions files are the intent layer. Hooks and diff budgets are the mechanism layer. You need both, and the intent layer has to be good enough that the mechanism does not fire constantly.

What belongs in a conventions file

The short answer is four categories, each written as a rule plus an example from your own repo. A style guide written for humans is a reasonable starting point, and one developer's approach is worth copying: document habits for a human audience first, on the theory that if it is human-readable enough, the model can handle it too (olano.dev).

CategoryWhat to encodeWeak versionStrong version
NamingVariables, functions, classes, files, tests"Use clear names""Functions are verbNoun (fetchUser, parseConfig). Booleans start with is, has or should. Test files are <module>.test.ts next to the module."
StructureWhere code lives, module boundaries, test placement"Keep files small""Handlers in src/handlers/, pure logic in src/lib/, tests beside the module as *.test.ts. No barrel files. One export per file in src/lib/."
StyleImports, formatting, comments, error handling"Follow the existing style""Imports grouped stdlib, third party, local, separated by blank lines. No comments that restate the code. Errors returned as a Result type, never thrown from src/lib/."
ScopeWhat an edit may touch"Only change what is needed""Do not rename, reformat or refactor code you did not have to change. If you spot an improvement, note it in notes/parking-lot.md."

The fourth row matters more than most teams expect. The Karpathy-derived guidelines skill makes surgical edits a named rule: do not improve adjacent code, do not refactor things that are not broken, match existing style even if you would do it differently, and mention unrelated dead code instead of deleting it (SKILL.md). The same skill states the test that belongs in every conventions file: every changed line should trace directly to the user's request.

Show, do not describe

Adjectives are the main failure mode of conventions files. "Clean, readable code" is unactionable. The Stack Overflow piece recommends guidelines that are more explicit, more demonstrative of patterns and more obvious than human-facing standards, because the agent has no shared history to fill the gaps (stackoverflow.blog). In practice, that means every rule carries a short snippet from your repository, the real one, not an idealized version.

Keep it small enough to be read

A giant conventions file has the opposite problem: the model skims, the rules rot, and the token cost lands on every request. Discussion of instruction files that grow unchecked recommends recording the same correction only after it has been needed more than twice, on the grounds that context pollution from unnecessary rules costs more than the missing rule (news.ycombinator.com). The same conversation notes that a large root instruction file is a poor fit for long-lived guidance because it is loaded eagerly and tends to decay, and the alternative proposed is smaller, targeted artifacts plus design documents read at the right moment (youtube.com).

Extract conventions from the repo instead of inventing them

Most teams already have the rules, scattered across linter configs, review comments and tribal memory. The job is extraction, not authoring. Four passes get you most of the way.

  1. Mine review comments. Search merged pull requests for the phrases reviewers repeat: "please rename", "extract this", "we don't do that here", "use the helper". Each recurring comment is a rule missing from your file.
  2. Read the linter config as documentation. If ESLint or Ruff enforces import order and line length, the conventions file should say so in one line and point at the config, not repeat the settings. Automatable formatting should be automated away; the parts worth writing down are the ones that spill into design, like how code is distributed across files and how things are named (olano.dev).
  3. Sample two files per module type. Pick a handler, a service, a test and a component, and describe what they have in common: exports, error shape, how dependencies arrive.
  4. Interview the reviewer with the most rejections in the last quarter. Thirty minutes produces more rules than a wiki audit.

A worked measurement

Suppose your agent rewrites a function to fix one bug. You estimate the minimal fix at about 12 changed tokens. The agent's diff is 240 changed tokens. Your diff budget for bug fixes is 80 changed lines per task, and this task is well past it. Two numbers give you a decision rule: if the agent's edit distance exceeds the true minimal edit by more than roughly half, send it back rather than reviewing it. The BigCodeBench study normalizes by token count and compares the model's edit distance against the ground-truth minimal edit, exactly so you can separate "fixed the bug" from "rewrote the file" (nrehiew.github.io).

At team scale, the cost lands on review attention. One autonomous setup reports that a five-line fix takes a minute to verify while a twelve-file diff with the fix buried inside costs real attention, and that parallel agents collide precisely on the unrequested edits, because two agents never fight over their assigned task, only over the shared utility both decided to tidy (dev.to).

Feed the rules at the right moment

Writing the file is half the job. The other half is delivery: the agent has to see the relevant rule before it writes the code, not after the diff exists.

Order of loading, cheapest first:
1. System prompt / agent config      -> the 10 rules that always apply
2. Task spec (per ticket)            -> allowed paths, and which module docs to read
3. On-demand skill or doc            -> language or framework specifics, loaded when relevant
4. Hook feedback                     -> the rule it violated, read at the moment it is blocked

Layer 1: always-on context

Put the short version in whatever file your agent reads automatically at session start. Keep it to rules that would cause damage if missed: naming, file layout, error handling shape, and the surgical-edit rule. Use the imperative mood and positive framing, because a rule the model can follow beats a rule it has to interpret.

Layer 2: the task spec

Longer conventions do not need to be in the system prompt if every task carries a pointer. A task spec with a scope block, allowed paths and a size budget gives the agent both the pattern to follow and the fence around the work (dev.to). A minimal version:

{
  "id": "task-0412",
  "goal": "Fix off-by-one in pagination helper",
  "read_first": ["CONVENTIONS.md", "src/pagination/README.md"],
  "scope": {
    "allowed_paths": ["src/pagination/**", "tests/pagination/**"],
    "max_files": 4,
    "max_changed_lines": 80
  }
}

The read_first list is the delivery mechanism for the conventions file, and the scope block is the enforcement. Note the design preference behind the numbers: bug fixes get tight budgets, feature work gets wider ones, and refactors are their own task type with an explicitly large budget, so refactoring is never smuggled inside a fix (dev.to).

Layer 3: on-demand skills

Rules that apply to one framework and not the rest of the repo belong in a skill or a doc the agent loads only when relevant. A skill in the Agent Skills format is a Markdown file whose name and description sit in the system prompt while the body loads on the first matching request, so an idle skill costs nothing and a swapped model still reads the same instructions (typingmind.com). That is the structure that keeps a conventions system from becoming one bloated file.

Layer 4: hooks that return the rule

If a rule matters enough to argue about in review, enforce it mechanically and have the hook explain itself. A pre-edit hook that receives the tool call as JSON can block a write that lands outside the task's allowed paths, and the feedback channel is the whole trick: the agent is told why and what to do instead, including parking the idea for a follow-up task (dev.to). Be honest about the limits: a path hook does not cover edits made through shell commands, so the post-run check on diff size stays necessary. A packaged version of this guard exists as a plugin, which is a reasonable place to start before writing your own (github.com).

Reviewing the result against conventions

Conventions only hold if review checks them. Git is the instrument here, because a task that started from an unclear working tree cannot be judged fairly. The ESP-IDF agent workflow recommends running git status and git diff before asking for a substantial change, branching per task with prefixes like feat/, fix/ and refactor/, and committing small verified checkpoints so review compares behavior between steps (developer.espressif.com). A prompt worth keeping in the file: ask the agent to review the current diff, identify any changes unrelated to the task, summarize the rest and propose a commit message, without staging anything.

Parallel work needs its own isolation, since two agents sharing a working directory can see each other's uncommitted changes. Git worktrees give each task its own directory over one shared history, so an agent can run in the background while you keep editing, and the branch merges like any other (nx.dev). Sources that track agent sessions through Git hooks are moving the same way, capturing what happened in a session so a reviewer can see how a commit was produced rather than only what changed (github.com).

The review checklist that follows from the rules

CheckPass conditionRule it enforces
Every changed line traces to the requestYes, or explainedSurgical edits
Files touchedInside allowed pathsScope
Diff size vs. minimal fixUnder budget, or extension requestedDiff budget
New namesMatch verbNoun, isX patternsNaming
New filesIn the documented directoriesStructure
Unrelated improvementsIn the parking lot, not the diffScope

Record any convention the agent violated without being told, then add it to the file with a one-line example. Corrections are the raw material; the file is the artifact. That loop is why teams that invest in it report the same correction rarely recurring once it is written down (news.ycombinator.com).

Budgeting tokens for all this context

There is a real cost to keeping conventions in front of the model, and it is worth sizing before you write 900 lines. A study across four languages and ten models found that removing formatting elements such as indentation, whitespace and newlines cut input tokens by an average of 24.5% with negligible loss of performance on fill-in-the-middle completion (arxiv.org). The lesson is not to strip your source, it is that context budget is measurable and that structure carries real tokens, so a conventions file competes with source code for the same window.

Use that to set a target. Keep the always-loaded section under a page, put framework specifics in on-demand skills, and let hooks carry the rules that must never be skipped. If a rule has to be in the always-on block, it has to earn its place by preventing a mistake you have actually seen.

What to try first

Start with one repository and one week of corrections. Write the file with the four categories, add the task-spec pointer and the diff budget, and record violations as they happen. The first five rules will come from your linters and are nearly free. The rules that matter most, the ones about surgical edits and naming, come from review comments.

For teams running agents in parallel, the next step after conventions is consistent model access and reusced skills across the whole team, so every agent reads the same instructions and hits the same APIs. Quanta Inference provides one OpenAI-compatible API key for text, image, video, audio and embedding models, so a conventions file written once applies identically across every model your agents call. The conventions you write this week are the cheapest investment you can make in every agent session that follows.

FAQ

FAQ

Why does an agent rewrite code that already works?

The model has no memory of your repository and no tacit knowledge of your conventions, so it continues with the most statistically common pattern it has seen, which is often more defensive and more verbose than your code. When nothing in the context forbids extra validation, renaming or reformatting, the model treats those as part of doing a good job (dev.to). Making the conventions explicit and loading them before the edit removes the ambiguity.

Does a stronger prompt fix over-editing?

Rarely on its own. Practitioners report that instruction-only requests to change nothing else helped a little and not nearly enough, because the agent's own cleanup feels related from inside the task. The reliable combination is a conventions file for intent plus a mechanism for enforcement, such as allowed paths in the task spec and a post-run check on diff size (dev.to). Treat the prompt as one of four layers, not the whole system.

How long should the conventions file be?

Short enough that it is worth loading on every task. A page of always-on rules covering naming, structure, style and scope, with framework specifics moved into on-demand skills, is a workable target. Add a rule only after you have had to explain the same thing more than twice, since unnecessary rules pollute context and cost more than they save (news.ycombinator.com).

How do I measure whether the conventions are working?

Compare the agent's edit distance against the true minimal edit for each task, and count how often the diff exceeds its budget. If the model's edit is far larger than the smallest correct change, the conventions are not landing, and the specific lines that diverge tell you which rule is missing. Track unrelated files touched per pull request as a secondary signal.

Can the coding agent write its own conventions file?

It can draft one, and that draft is useful as a starting point, but it must be reviewed by someone who knows the codebase's deliberate choices. A drafted file reflects what the model saw in recent context, not the decisions the team made, and it will not know about rules that exist only as review habits. Treat the draft as a questionnaire and fill in the answers from merged pull request comments and the reviewer with the most rejections.

Sources

Sources

  1. Coding Models Are Doing Too Much - wh
  2. Over-editing refers to a model modifying code beyond what is ...
  3. Building shared coding guidelines for AI (and people too)
  4. How I Stopped My AI Coding Agent's Scope Creep With a Diff Budget
  5. My programming style guide
  6. skills - karpathy-guidelines - GitHub
  7. Why Your AI Coding Agent Keeps Writing Bad Code (It's Not the Prompt)
  8. Karpathy Guidelines by multica-ai, AI Skill for Any LLM | TypingMind
  9. GitHub - atoolz/scope-guard: Stop AI scope creep. A Claude Code plugin ...
  10. AI agent coding for ESP-IDF workshop - Optional: Git workflow for agent ...
  11. How Git Worktrees Changed My AI Agent Workflow | Nx Blog
  12. GitHub - entireio/cli: Entire CLI hooks into your Git workflow to capture AI ...
  13. How Code Formatting Silently Consumes Your LLM Budget
About the author

About the author

Antonio Evans
Antonio Evans

Antonio Evans is the founder of Quanta Intelligence and a fractional CTO who builds HIPAA-ready AI systems for health and life-science companies. Before that he was technical co-founder of FriendsEAT for twenty years, CEO of Socialdraft, and a data engineer at IBM. Antonio lives with his dog Santino in Lisbon, Portugal.

All articles