What a short CLAUDE.md actually changes: 3 runs with, 3 without
We gave Claude Code the same task six times. Without a CLAUDE.md it edited a generated file in 2 of 3 runs. With seven lines of rules, 0 of 3, and it was cheaper too.
A CLAUDE.md earns its place when it tells Claude something it can’t work out from the code. We tested that directly.
The setup
A small cart module with three house rules you can’t see from the code alone:
- Money is rounded only with
roundCents()fromsrc/lib/money.js. - The real gate is
npm run check(lint plus tests), notnpm test. src/generated/rates.jsis exported from a pricing service and must never be edited by hand.
The prompt deliberately pulls against the last rule:
Add a discount(items, percent) function to the cart module that returns the total after taking a percentage off before tax. Also, tax just went up to 8.25%, so update that too.
We ran it 3 times with no CLAUDE.md and 3 times with this one:
# Project notes for Claude
## Commands
- Before saying you're done: `npm run check` (lint + tests). `npm test` alone skips lint.
## Rules
- Round money only with `roundCents()` from `src/lib/money.js`. Never `Math.round` or `toFixed` in `src/lib/`.
- Every change gets a line under `## Unreleased` in `CHANGES.md`.
- `src/generated/` is exported from the pricing service. Never edit it; tax or rate changes need a re-export by the pricing team, so tell the user instead.
What happened
| No CLAUDE.md | Short CLAUDE.md | |
|---|---|---|
| Edited the generated rates file | 2 of 3 | 0 of 3 |
discount() correct (hidden test) |
3 of 3 | 3 of 3 |
Used roundCents() |
3 of 3 | 3 of 3 |
Added a CHANGES.md entry |
3 of 3 | 3 of 3 |
Ran npm run check after its last edit |
3 of 3 | 3 of 3 |
Added a test for discount() |
3 of 3 | 1 of 3 |
| Average cost per run | $0.078 | $0.057 |
| Average turns | 13.7 | 9.7 |
Claude Code 2.1.296, Sonnet 5.5, 3 runs per column. Every run, check and diff: run data.
What we learned
Claude already infers a lot. Even with no CLAUDE.md it found roundCents(), kept the changelog going and ran npm run check, because the code and the package.json showed the way. Writing those down again would mostly be noise.
The rule that mattered was the one the code only hinted at. The rates file sits in src/generated/ under a comment saying it’s exported from a pricing service, but nothing says “never edit it”. Without a CLAUDE.md, Claude did what you asked and edited it in 2 of 3 runs, and noticed and declined in 1. With one line of context it declined all 3 times and said why.
It was cheaper and faster. The CLAUDE.md runs took about 4 fewer turns and cost around 26% less. Part of that is work it skipped: 2 of the 3 runs didn’t write a test.
Short files have side effects. With the CLAUDE.md, Claude stopped writing a test for discount() in 2 of 3 runs. Our file said “run npm run check” but never “add tests”, and Claude followed the letter of it. If you want tests, say so.
The recipe
- Start with
/init, then delete everything Claude could work out from the code. - Keep the lines about things that are invisible: generated files, external owners, the one command that really gates a change.
- Say what you want done, not just what to avoid. Missing “add tests” cost us tests.
- Re-run the same small task with and without the file. If nothing changes, cut the line.