CLAUDE.md as production infrastructure
ENGINEERING
SEPTEMBER 1, 2026

CLAUDE.md as production infrastructure

6 min read
BACK TO BLOG

What a coding agent's context file has to contain when the repos it touches are live, and the day I found the file preventing disasters had no backup.

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](/website-audit)** 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](/contact).
SHARE
6 min read
Read More

MORE ARTICLES

Two ECS failures that produce no useful error
Engineering
Engineering

Two ECS failures that produce no useful error

A readiness probe blocked by the task's own IAM role, and readonlyRootFilesystem silently killing ECS Exec. Both look like broken infrastructure.

How do you know when your AI feature is wrong?
Engineering
Engineering

How do you know when your AI feature is wrong?

Most teams ship an AI feature and have no answer past spot-checking. What an evaluation harness actually contains, and the failure it usually misses.

Don't put a model where you need a reproducible answer
Engineering
Engineering

Don't put a model where you need a reproducible answer

Three systems where I deliberately chose regex and a lookup table over an LLM, and the two questions that decide which one a problem needs.

A fact register: stopping an LLM inventing your statistics
Engineering
Engineering

A fact register: stopping an LLM inventing your statistics

Four invented statistics shipped to my own live website. The fix was not a better prompt — it was an allowlist of every number the copy may contain.