I run coding agents across a fleet of repositories on a Mac Mini that stays on. Trading bots, a CRM with live customer data, a website, a home-services business that invoices real money. Most of those repos have a CLAUDE.md — a context file the agent reads before doing anything.
They started as notes. They are now the most load-bearing documentation I have, and the reason is unglamorous: an agent that lacks context does not stop and ask. It infers. Confidently, and at speed.
What actually goes wrong without one
Not what I expected. The failures were rarely bad code.
It rediscovers settled decisions. Without a record of why the CRM runs on tables named -dev that hold production data, an agent reads the name, concludes somebody made a mistake, and helpfully proposes a migration. Every time.
It optimises something load-bearing. I have a .gitignore that denies everything and then admits about twenty files by name. It looks like a mistake. It is the only thing standing between a public push and 14GB of secrets, venvs and twenty-eight nested repositories. Anyone tidying it — human or otherwise — is one edit from a very bad afternoon.
It cannot tell reversible from irreversible. Editing a file and sending an invoice look identical from inside a tool call. One of my automation modules creates real QuickBooks invoices and sends real email. Nothing in the code says "this is the one that touches money."
So what does the file need to contain?
Four things, in descending order of value.
A map. What lives where, and which of it is live. My fleet file opens by saying it is the map of the directory. For an agent landing cold, the difference between "there are 51 folders" and "these 51 folders, these six are in production" is most of the value.
The irreversible actions, named individually. Not "be careful" — a list. Which module sends email. Which one creates invoices. Which table has no backup. Which script needs --commit before it does anything, and which one doesn't and should. This is the section that has actually prevented damage.
The why, not the what. The diff shows what changed and can never show why. So the rule across my repos is that any non-trivial commit carries a line starting Why: — the reason, the alternative rejected, or the symptom being fixed. Why: mow billing double-charged when a work order was rescheduled is worth keeping forever. "fix bug" is worth nothing. That one line is the difference between history you can query and history you can only read.
Structural rules that read as arbitrary. Do not rename these folders, because cron and tmux reference absolute paths. Commit in the nested repo, not the parent. Every one of those looks like fussiness and every one of them is a scar.
Write it for a competent stranger
The mental model that made mine better: write for a competent contractor starting Monday who will not ask you anything.
That framing does the work. A competent stranger does not need the framework explained. They do need to know which of the four apparently-identical environments is the one customers touch, and they will absolutely not guess that -dev means production.
It also filters ruthlessly. Anything a good engineer could work out by reading the code does not belong in the file. What belongs is what the code cannot tell them: history, blast radius, and the decisions somebody already lost an afternoon to.
The thing I got embarrassingly wrong
I audited these files recently, and found that one of them — the harness for the CRM that runs a real business, the one full of this will send real email warnings — was in no repository at all.
The parent directory was not a repo. Two repos nested inside it, so everything that mattered looked version-controlled. And the fleet-level .gitignore denied everything by default, which is exactly the property I wanted, and which silently swallowed that file.
So the document whose entire purpose was preventing expensive mistakes existed on precisely one machine, with no history and no backup, while the code it described was pushed to a remote every day.
Worse: the fleet repository itself had no remote. The map, the automation scripts, the reboot-recovery — all of it local-only. I had been diligent about the projects and had never once thought about the harness that ran them.
What I changed
Every context file is now in a repository, admitted one file at a time rather than by loosening the deny-everything rule. Widening a publish allowlist by accident is the failure that rule exists to prevent.
The fleet has a private remote and an hourly job that commits and pushes it — silent when nothing changed, and it refuses rather than pushes when anything outside the allowlist appears, because the only way that happens is somebody weakened the .gitignore.
I treat these files as code. They get reviewed, they get the same Why: discipline, and when one turns out to be wrong that is a bug with a fix, not a note to tidy up eventually.
The part worth generalising
A coding agent is a very fast contractor with no memory and no fear. It will not hesitate before the irreversible thing, because from inside the tool call nothing marks it as irreversible.
The context file is where that marking lives. It is not documentation in the usual sense — nobody reads it for pleasure and it does not describe the system for a newcomer's benefit. It is a control surface. The bits that matter are the ones that say stop, and they only work if they are specific enough to match the moment the agent is actually in.
Which means the file deserves the same care as the code: version control, review, and a backup somewhere other than the machine it protects.
I am one engineer, and the whole fleet runs on this. Before taking my word for any of it, the free website check is a public unauthenticated endpoint that drives headless Chromium at an arbitrary URL from a stranger — an SSRF liability unless the boundary is real. It is a fair sample of how I build the parts nobody looks at.
If you are running agents against systems where a mistake costs something real and want another pair of eyes on the guardrails, tell me what you are running.




