The instruction file is the highest-leverage file in your repo
Every coding agent now reads a project instruction file. The names differ — AGENTS.md
is the cross-vendor convention used by Codex, Cursor, VS Code, Copilot's coding agent,
Gemini CLI, Aider, Zed, Jules, Devin and dozens more; Claude Code reads CLAUDE.md;
Copilot also honours .github/copilot-instructions.md; Cursor adds .cursor/rules/*.mdc
— but the job is identical. It's the README for agents: a predictable place to put what
a new teammate would need to know.
The format is open-ended. There are no required fields, no schema, no linting. Which means most of these files are bad, and the badness is consistent enough to be worth naming.
Why it's the highest-leverage file
An agent working in your repo is doing inference under uncertainty about a hundred small decisions: which test runner, where tests live, whether to add a dependency, whether to write a migration, what your error-handling convention is, which directory is generated and must not be edited by hand. It will guess. It will guess plausibly, using the most common convention on the internet, which is frequently not yours.
Every line in the instruction file that resolves one of those guesses converts a coin flip into a certainty — for every session, forever, for every agent and every teammate. Nothing else you can write has that leverage-per-line.
What actually changes behaviour
The commands that really work
The single most valuable section. Not "run the tests" — the exact invocation, including the flags, including the one that only matters on your setup:
## Commands
npm run build # whole workspace; also compiles the CSS
npm test # full suite; keep green before finishing
npm test -- --grep Xyz # a subset
npm run db:migrate # required after any schema change
An agent with a working build/test loop can verify itself and iterate. An agent without one is writing code blind and telling you it's done. This section alone is worth more than everything else in the file combined.
Include the failure modes too, if you have a known one: "When the dev server is
running it locks bin/, so build the test project to its own output folder instead."
That's the kind of thing that costs an agent — and a new hire — forty minutes.
The architecture facts that aren't in the code
Not a directory listing; the agent can run ls. Write the things that are decisions:
- Which layer may depend on which, and what has no dependencies at all.
- Where the single source of truth lives for a rule that's easy to re-derive wrongly.
"Never restate a visibility rule in a query —
PublicOnly()owns that predicate." - Which files are generated and must not be hand-edited.
- What must ship together. "A model change must ship with a migration."
The test for this section: would an agent that ignored this sentence write code that compiles, passes tests, and is still wrong? If yes, the sentence is earning its place. If a linter would have caught it, delete it and let the linter do the work.
Conventions stated as rules, not preferences
"Prefer clean code" is noise. "Use Result<T> for expected failures; exceptions are for
bugs only" is a rule. The difference is whether someone could look at a diff and agree
on whether it complied.
The traps
The most valuable and most-skipped section: the mistakes this codebase has actually caused. Real ones, with the symptom:
Attribute-quote trap (bitten us twice): when a Razor attribute value contains a
", the inner quote terminates the attribute early — you get a parse error or a silently broken component. Use single-quote delimiters for that attribute.
An agent that has read that doesn't rediscover it at your expense. This section grows naturally: every time you correct an agent twice for the same thing, that correction belongs here.
What's decoration
Praise and vibes. "Write high-quality, maintainable code." No decision changes.
Restating the framework's docs. The model knows what a React hook is. It doesn't know
that your team banned useEffect for data fetching. Write the second thing.
A directory tree the agent can generate. Unless the reason for the structure is non-obvious — in which case write the reason, not the tree.
Aspirational rules nobody follows. If the codebase contradicts the file, the agent gets conflicting evidence and picks unpredictably. A rule you don't enforce is worse than no rule.
Everything, exhaustively. The file is read at the start of every session and competes for attention with the actual task. A tight one-page file that is entirely load-bearing beats a five-page file with three good paragraphs in it.
Structure and precedence
For a monorepo, put an AGENTS.md inside each package. Agents read the nearest file in
the directory tree, so the closest one wins — package-specific conventions go in the
package, and only the genuinely global rules go at the root. Explicit instructions in the
chat override the file, always; the file is the default, not a law.
Where the tools diverge, the pragmatic move is one real file plus thin pointers:
| File | Read by |
|---|---|
AGENTS.md |
Codex, Cursor, Copilot coding agent, Gemini CLI, Aider, Zed, Jules, and more |
CLAUDE.md |
Claude Code |
.github/copilot-instructions.md |
GitHub Copilot (repo-wide) |
.github/instructions/*.instructions.md |
GitHub Copilot, scoped by an applyTo glob |
.cursor/rules/*.mdc |
Cursor, always-on / glob-attached / by name |
Path-scoped rules are underused and worth the setup: your React conventions shouldn't be in context while the agent edits a SQL migration, and a glob is how you say so.
Maintaining it
Generate the first draft, then edit it by hand. /init in most agents will scaffold
something. The scaffold is a starting point with roughly the right sections and roughly
no insight — the value comes from the twenty minutes you spend replacing generic lines
with true ones.
Update it from corrections, not from planning sessions. The best instruction files are written incrementally, one correction at a time. When you catch yourself explaining the same thing again, stop and add the line.
Delete aggressively. When a rule becomes enforced by a test or a linter, remove it from the file. Its job is now done by something that can't be ignored.
Review it like code. It ships in the repo, it changes behaviour, and a stale line in it will cost someone an afternoon. It deserves a reviewer.
A minimal file that works
# AGENTS.md
## Stack
Go 1.23, Postgres, sqlc. No ORM — queries live in `db/queries/*.sql` and are generated.
## Commands
make build # regenerates sqlc, then builds
make test # full suite; requires Docker for testcontainers
make lint # golangci-lint; CI fails on any finding
## Rules
- Never hand-edit `db/generated/` — change the .sql file and run `make build`.
- Every exported function returns an error; no panics outside `main`.
- New endpoints need a test in `handlers/*_test.go`. No exceptions.
## Traps
- `make test` without Docker running fails with a confusing DNS error. Start Docker first.
- The `time` package is banned in business logic; inject a Clock so tests can control it.
Twenty lines. Every one of them changes what an agent does. That's the bar.
Comments (0)
Sign in to join the conversation.
No comments yet.