The Second Time Is a Bug Blog

From the blog

AGENTS.md Best Practices: Keep It Short and Make Every Rule Checkable

Every team that uses a coding agent ends up writing the same file. It starts as ten sensible lines: how to run the tests, where things live, a rule about money. Then the agent makes a mistake, someone types “add this to AGENTS.md”, and it does.

A few months later the file is a diary: “be careful with rounding”, “when in doubt, ask”, a line pointing at a folder renamed in the spring. Nobody has read it all since it passed two screens, except the agent, which reads every line every session. And it follows the file less, not more.

Keep AGENTS.md (or CLAUDE.md) short: a map that points to where detail lives, not a manual. Give it a line budget, around 100 lines, that a check enforces. List the files that change together, make every rule name its check, and prune it every quarter. A rule with no check is a wish.

Why a long instruction file works worse

Every line the agent loads competes for its attention, diluting the important ones. Adding a line per mistake, as Mitchell Hashimoto describes (opens in a new tab), is the cheapest fix and the weakest: a line asks, it does not check. And a stale line is followed: told about that renamed folder, the agent will look, fail, then helpfully create it.

What to put in AGENTS.md: a map, not a manual

OpenAI’s team describes giving their agent “a map, not a 1,000-page instruction manual” (opens in a new tab): an AGENTS.md of roughly 100 lines that works as a table of contents into a docs/ folder. The book adds a script that enforces it: the Hundred-Line Map (P03), Chapter 3.

An instruction file as a map A short AGENTS.md has six sections. Five of them point elsewhere: the folder map to the source, test and docs folders, the commands to the test, lint and gate commands, the also-update list to a coupling check, the rules to one check per rule, and the section on failed checks to a plan template. An instruction lint checks the file's length, that every path it names exists and that every rule names a check. A Lessons learned section that points to a folder renamed months ago is a dead pointer, and the lint refuses it. AGENTS.md two screens, budget 100 lines What this is Map of folders Commands Also update Rules When a check fails Instruction lint line budget, dead paths, rules that name no check checks src/ test/ docs/ test, lint and gate commands a coupling check one check per rule a plan template + Lessons learned lib/rates/ (since renamed)
Five sections point somewhere else. The Lessons learned section points at a folder since renamed, and the lint refuses it.

How long should AGENTS.md or CLAUDE.md be?

A hundred lines is a judgement call; what matters is a number and a check that counts. The book’s lint also checks that every path the file mentions exists: nobody rereads the file after renaming a folder, so a script should.

Write down the files that change together

Say the agent changes a default price in the config and stops there. The test fixture that mirrors it goes red, and the docs page keeps quoting the old number. Three files hold one value, and nothing told the agent. The Also-Update List (P04), Chapter 3, writes that down in a shape a script can read:

## Also update
If you change the first path, update the others in the
same change. Checked by `npm run check:coupling`.

- When `src/config.ts` changes, also update
  `test/fixtures/prices.json` and `docs/pricing.md`.
  Why: the pricing defaults are mirrored there.

Each item has a trigger, the files that move with it, and the reason the check prints. Find your first items in review comments saying “also update”.

How a coupling check decides An also-update item says that when src/config.ts changes, test/fixtures/prices.json and docs/pricing.md must change too. The diff touches config.ts, which triggers the item, but touches neither of the other two files, so the coupling check fails, stops the commit and prints both file names and the reason from the list. Also-update item in AGENTS.md In the diff? When this changes src/config.ts yes: trigger Also update test/fixtures/prices.json no docs/pricing.md no Why: the pricing defaults are mirrored there. Coupling check: failed commit stopped; it names both files and the why
The diff touches the trigger but neither file that must move with it, so the check stops the commit and names both, with the reason.

Every rule names its check

Rules, Not Wishes (P05), Chapter 3, ends every rule with the command that enforces it, so the agent can run the check before claiming done. Without one, a rule is followed on Monday and not on Thursday. “Done” itself is the subject of Chapter 6, free as a sample, and of stopping an agent deleting tests.

From the field. I once led the rearchitecture of a global logistics company’s web experience layer, which brought more than twenty independent applications into one framework. Its guidelines, such as never forking a shared widget, were followed most of the time, and “most of the time” was the problem: a guideline was read once, when a team joined, and after that it lived in memory. The rules that held were the ones we turned into something that ran without anyone remembering them: shared packages and a project template.

Your agent still has a Thursday. Give each unchecked rule one of four exits: write the check, point to the test that enforces it, hand it to a review agent, or delete it. A first miss may earn a line; a repeat earns a check.

How to prune AGENTS.md

Each quarter, and after every model upgrade, ask of every line:

  1. Does it point at something real? The lint answers this on every commit.
  2. Has its check fired lately? Quiet for 90 days is a reason to look, not a verdict.
  3. Does the agent follow it unprompted? Delete it in a branch and rerun a few tasks; with no unit tests for context (opens in a new tab) (Birgitta Böckeler), “no change” is permission, not proof.
  4. Does the check’s message already teach it? Keep a one-line pointer.

Try it yourself

The companion repository (opens in a new tab) has a 93-line AGENTS.md written this way for Invoicer, a small invoicing app written for the book. npm run drill D04 shows the lint passing, then failing once a diary is appended, with no API key, model or network.

Back to the diary

Replay that price change with the map in place. Same model, same edit, but the commit stops at the coupling check, which names the fixture, the docs page and the reason. And “add this to AGENTS.md” now means one three-line item, with a script that remembers on the Thursday the agent does not.

Questions people ask

AGENTS.md or CLAUDE.md: which one does my agent read?

As of October 2026 (the book’s Appendix C), Codex, Cursor and GitHub Copilot’s cloud agent read AGENTS.md (Codex (opens in a new tab), Cursor (opens in a new tab), Copilot (opens in a new tab)). Claude Code (since version 2.1.277) reads AGENTS.md only when there is no CLAUDE.md, so if you keep both, start CLAUDE.md with @AGENTS.md (docs (opens in a new tab)). Gemini CLI reads GEMINI.md unless you add AGENTS.md through context.fileName (docs (opens in a new tab)). The companion keeps an updated copy (opens in a new tab).

What should never go in AGENTS.md?

Pointers to files that do not exist, rules nobody can check (“when in doubt, ask”), and a diary of lessons learned. Detail for one kind of task, such as tax rounding, belongs in docs next to the code.

How often should I prune it?

Once a quarter, and after every model or agent upgrade, since a new model may stop making the mistake a line was written for. The lint catches dead pointers on every commit; the review is for lines still true but no longer needed.

Cover of The Second Time Is a Bug

The Second Time Is a Bug

A field workbook for engineering with AI coding agents: 14 chapters, 34 pattern cards and 26 drills that run offline against free, public companion code.