The rule: what happens if the agent does not know this?
Every coding agent reads a Markdown file such as AGENTS.md before it works, and many tools will write one for you. A 138-repository study reports that auto-generated files lowered success by about 3% and raised cost by more than 20%. Those are the write-up's figures; we have not reproduced them.
We tested a sharper question: which lines earn their place? Ask it of each line in your file.
- Would a test, type checker or linter catch the break, with a clear message? Cut the line. The agent meets the failure and fixes it.
- Does the code already show it? Cut the line. The agent reads the code.
- Neither? A naming convention, a log format, a "never touch the migrations folder". Keep the line. Nothing else will tell the agent.
The evidence for each answer follows.
The evidence
| Projects | Two sample projects written for this test, not public repositories: tinyledger, commit b330a0d2ea903ef22e454757a3a2018e6328be0d (experiment 1), and the same project extended with a tax module, commit ac17225fb1913d7b3a67f1ed664bbd8396e1b900 (experiment 2) |
| Agent and model | Claude Code 2.1.316, claude-sonnet-5-5, run non-interactively on 1 November 2026 |
| Conditions | No file; auto-generated (the agent's own output for "Analyze this codebase and create an AGENTS.md", untouched); trimmed (hand-written, only what the code cannot show) |
| Runs | Experiment 1: 5 tasks, 3 conditions, 3 repetitions, 45 runs. Experiment 2: 3 tasks, 3 conditions, 3 repetitions, 27 runs. Each run starts from a fresh copy of the project |
| Scoring | A script written before any run: correct (tests pass and the new behaviour works) and, in experiment 2, rule followed, checked by script and then against every diff |
Claude Code reads CLAUDE.md, so in the two conditions with a file we added a one-line CLAUDE.md containing @AGENTS.md.
Experiment 1: every rule had a test
The five tasks (add a currency, fix a rounding bug, add two functions, add validation) touched three traps: a generated file that must not be edited by hand, a test that every export is documented, and a stale-file check inside npm test. All three were enforced by npm test.
All 45 runs passed, 15 of 15 in every condition. In the nine "none" runs of the three tasks that touched a trap, the agent did what the files would have told it: it edited the data and regenerated the output together, and documented each new function. Our best explanation is that the failing test told the agent a turn later what the file would have said. We did not read transcripts, so that is an inference. Token differences between conditions were noise.
Experiment 2: rules nothing enforces
The obvious objection is that we had tested every rule. So we added three tasks that depend on rules no test checks. We chose them after seeing experiment 1, and two are arbitrary on purpose.
| Task and rule | Rule followed: none | Rule followed: auto | Rule followed: trimmed |
|---|---|---|---|
6. Functions returning true or false are named checkX, not isX | 0 of 3 | 0 of 3 | 3 of 3 |
7. Never edit src/vendor/; set tax rates in src/tax-overrides.js | 3 of 3 | 3 of 3 | 3 of 3 |
8. Log one line in the form [tinyledger] level=... event=... key=value | 0 of 3 | 0 of 3 | 3 of 3 |
| All three tasks | 3 of 9 | 3 of 9 | 9 of 9 |
Every one of the 27 runs was functionally correct and passed all tests. The break was in the convention only:
- Task 6. Without the hand-written file, all six runs named the function
isBalanced. With it, all three usedcheckZeroTotal. - Task 8. Without it, the six runs logged free text such as
convert: unknown currency: XXX/CAD, throughconsole.errorin five runs andconsole.warnin one. With it, all three wrote a line in the required form, with the levelwarnonce anderrortwice. - Task 7. Every run left
src/vendor/alone and used the overrides file, because the overrides file already sat beside the table in the code.
So the hand-written file decided the two rules that existed only in the file: 6 of 6 runs with it, 0 of 12 without it. Those two rules appear nowhere else, so the result also shows the imported file was read. The auto-generated file recorded the vendor rule, which the code shows, and nothing on naming or logging, which it does not. A generator can only write down what the repository shows, and the lines worth having are the ones it does not.
Token use again overlapped across conditions, so we make no claim about cost in either direction.
Run it on yours
- Pick tasks of both kinds
Real, merged work. Include some whose rules a test enforces and some whose rules nothing enforces; only the second kind can show a file helping.
- Write two scores per task before running
One script for whether the work is done, one for whether the rule was followed. Test each on a solution you wrote to comply and one you wrote to break the rule.
- Freeze everything but the file
Record the commit, agent version and model. Start every run from a fresh copy, then run each cell at least three times.
The runner is a short loop. This is the core of ours, trimmed:
# REP is the repetition number; proj/, cond/ and tasks/ hold the project, the three files and the prompts
for t in t1 t2 t3 t4 t5; do for c in none auto trimmed; do
W=work_${REP}_${t}_${c}; cp -r proj "$W"; cd "$W"
if [ -f ../cond/$c/AGENTS.md ]; then
cp ../cond/$c/AGENTS.md AGENTS.md
echo '@AGENTS.md' > CLAUDE.md # Claude Code reads CLAUDE.md; this imports the file under test
fi
s=$(date +%s)
timeout 600 claude -p --output-format json --model claude-sonnet-5-5 \
--allowedTools "Read Write Edit Bash(npm:*) Bash(node:*) Bash(ls:*) Bash(cat:*) Bash(grep:*)" \
< ../tasks/$t/prompt.txt > ../out/${REP}_${t}_${c}.json
e=$(date +%s)
if bash ../tasks/$t/check.sh > /dev/null 2>&1; then ok=1; else ok=0; fi
echo "$REP,$t,$c,$ok,$((e-s))" >> ../out/results_${REP}.csv
cd ..
done; doneLimits
- Two sample projects written by us, with rules chosen after the first results. A real repository may show more of its rules in code, and hide fewer.
- One agent, one model, one day, and eight tasks. Enough to see a rule followed or not, not enough to measure a small effect such as the study's 3%.
- We judged outcomes from the final changes and by running the code, not from transcripts.
Takeaway
Where tests enforce the rules, the file added nothing we could measure. Where nothing enforces them and the code does not show them, it was the difference between 0 of 12 and 6 of 6. Start with no file, run your real tasks, and add a line when the diff breaks a rule nothing flagged. Every line then earns its place once.
If you would like to practise this kind of measurement on your own setup, it is the core of our Customize your AI coding agent course.
Measure it, because it is easy to believe the file is working.
The first principle is that you must not fool yourself — and you are the easiest person to fool.
