Guardrails vs guidelines: why I left CLAUDE.md
TL;DR
A rule written in a CLAUDE.md, the agent eventually forgets: a few tens of thousands of tokens later, it's no longer in its window. A guardrail — a hook that refuses the action — doesn't forget. I moved the rules that matter from markdown to about fifteen hooks. Here's what it changes, and what it really costs.
A rule the agent can ignore isn’t a rule. It’s wishful thinking.
On human-written code, a wish was enough: a convention in a doc, a team culture, an attentive reviewer. A missed guideline got caught at review. The pace left time for it.
With a coding agent generating code several times faster, that net tears. The human reviewer becomes the bottleneck, and the real cost of AI shows up: not the license, but the verification tax — the time spent re-reading code that looks dangerously like correct code. The DORA 2025 report puts it its own way (the more AI adoption rises, the more delivery instability rises — unless you invest in your platform); I’m reporting that, I haven’t measured it myself. But the mechanism, I live it every day.
A guideline gets forgotten, a guardrail refuses
The shift fits in one example. “Don’t commit .env”, written in a CLAUDE.md: it holds for two or three sessions, then it falls out of the context window and one fine day the key ships with the commit. The same rule as a hook — a script that scans the staged diff and exits with an error on a match — never forgets. The system refuses the action, period.
That’s the difference between a guideline (a rule you hope gets read) and a guardrail (a constraint the system enforces). It’s not cosmetic, it’s structural: one depends on the agent’s memory, the other doesn’t.
What I enforce by gate (not by hope)
In daily use, on my personal projects — tested, not theoretical:
- a commit is blocked until a review has run;
- a push is blocked unless
tsc→ lint → tests pass, in that order; - a
.envor a secret never leaves the working dir; - a handful of destructive shell commands are refused outright;
- and the review doesn’t return a gut-feel opinion but a machine verdict (a YAML block): if CRITICAL or HIGH findings remain, it’s
iterate; otherwiseship. The model’s “felt” quality score gates nothing — it informs, it doesn’t decide.
That’s the mental shift: you no longer just code with the agent, you code the environment around the agent. The harness becomes the product; the hooks are the harness.
What it costs (because it costs)
A guardrail isn’t free, and pretending otherwise would be selling a dream.
You have to maintain it: every gate is code, with its own bugs. And a gate that produces false positives is worse than no gate at all — because you start stepping around it, and a guardrail you hop over by reflex is nothing but security theater. The threshold is narrow: strict enough to protect, fair enough that you don’t try to disarm it.
There are also cases where it isn’t worth the candle: a throwaway script, a solo one-shot, a test repo. Putting three gates on a file you’ll delete tonight is over-engineering — and I’ve caught myself doing it more than once.
The day my own gate slipped through my fingers
A small confession, because a guardrail that never failed doesn’t exist. I had a review hook meant to stamp a commit after the review. Except that by chaining the stamp and the commit in the same shell call, the gate’s logic got lapped: the action went through as “validated” when it wasn’t. My first theory — “the hook is broken” — was wrong. The real blocker was my own sequence, swallowed by a too-clever one-liner. I documented the trap in the hook’s own refusal message and added a write check. A guardrail gets debugged like production code, because that’s what it is.
To ask before writing the next rule
The useful question, before drafting your next “best practices with the agent” note: can I turn it into a check? A lint rule? A hook? A policy? If yes, do it — it will hold forever instead of three sessions. If no, it’s often because it’s too vague to be useful, even to a human.
A guideline is trust you renew every session. A guardrail is trust you no longer need to grant. On code generated at scale, the second one scales better — and incidentally, it sleeps better at night.
One consequence remains that rarely gets priced in: if the harness is the product, a deliberate share of what you pay — subscription, tokens — should fund the harness itself, not just the tokens that crank out code. The right percentage, I can’t pin down — but I know it isn’t zero. That deserves its own dispatch; this one stops here.