AGENTS.md, Kept True: Stop the Rot Step by Step (and Watch Your Agent Trust It)
Step 1 - Start from the truth, not a template
Before you write a line, list what's actually real:
cat package.json | jq .scripts # your real commands
ls src/ # your real entry points
ls .eslintrc* tsconfig.json 2>/dev/null # your real conventions (the configs)
Rule for the whole file: if it isn't in the repo, it doesn't go in the AGENTS.md. No aspirations, no "we should probably." Facts only.
Step 2 - Write the commands copy-pasteable, then RUN them
Don't type npm build from memory. Run it, and paste what actually works:
npm run build && npm test
Put the exact strings in the file. If the command in your AGENTS.md doesn't run, your agent's first move fails - and it won't know why. Tests go above build: they're the agent's only way to check its work against reality.
And wrap every tool and command name in backticks - mypy, ruff, npm test. A formatted token reads as a literal to run, not a vague suggestion the model can paraphrase away when the context is saturated.
Step 3 - Point at the config; don't restate it
You already have a linter and a formatter. So don't write "use 2 spaces, prefer const, strict types." Write:
## Conventions
- Style is enforced - run `npm run lint`. Obey the config, don't hand-format.
- TypeScript strict mode (`tsconfig.json`).
Restating a rule your linter owns is how the file goes stale (you change the config, the prose lies). Point at the source of truth instead. One line, can't rot.
Step 4 - Guardrails in three tiers + a Definition of Done
Give the agent a safety map and a finish line:
## Guardrails
- **Always:** read files, run the tests, build.
- **Ask first:** dependency installs, deletions, migrations.
- **Never:** force-push, push to `main`, commit secrets.
## Definition of Done
Done when: `npm run lint` exits 0 · `npm test` passes · committed with a conventional message.
Now the agent can know it's finished, not guess - and it knows which moves need a human.
One phrasing note that punches above its weight: lead with the enable, not the prohibition. "Branch and open a PR" hands the agent the safe path; a bare "don't push to main" hands it only the landmine - and a naked negative can prime the very move it's warning against. Say what to do, then the boundary.
Step 5 - The anti-rot rule: it changes in the same PR as the code
This is the step everyone skips, and it's the whole game. Make drift a bug, not a someday:
- Add it to your PR template: "Touched build/test scripts? Update
AGENTS.md." - Or a CI check that fails if
package.jsonscripts changed butAGENTS.mddidn't. - Or - the honest endgame - regenerate the file from the repo so it can't drift (more on that below).
Treat AGENTS.md like code, because your agent already does.
Step 6 - Verify: point your agent at it and watch
Give the agent a small, real task ("add a tested /health endpoint"). Watch it: read the file, run the tests you listed, respect the guardrails, hit your Definition of Done. If it does the wrong thing - wrong command, ignored convention - your file lied. Fix the line, not the agent.
That loop - task, watch, fix the line - is how an AGENTS.md earns trust. A true one becomes the most reliable thing in your repo.
Where to go deeper
The series: 1 · the field guide → 2 · build one, hands-on → 3 · why it goes stale → you're on 4.
- The
AGENTS.mdstandard - agents.md (the spec itself). - Section-by-section definitions + a field guide - faf.one/agents (what earns a line, ordering, length, and the anti-patterns).
- Why "generated from truth" beats hand-writing and AI-slop - the research and the deeper dive, same place.
Keep it honest, and your agent stops guessing. That's the whole point of the file.
Comments
No comments yet. Start the discussion.