A reader asked, at the end of an unusually good comment on one of our CLAUDE.md posts:
"The bigger question for me is: should agent instruction files eventually be treated less like documentation and more like executable configuration—with schemas, validation, ownership, and automated linting?"
— @crdtcto
We've been running one answer to that for months, so rather than speculate: here are three postures you can take toward a CLAUDE.md / AGENTS.md file, what each actually buys, and the exact line where the third one stops working.
A: it's documentation
The default. You write prose, the agent reads it, nothing checks anything. This is not a strawman — it's where every instruction file starts, including ours.
The failure mode isn't that people ignore the file. It's that nothing ever ages out of it. The same commenter put it better than we would have: the instruction file "slowly becomes a second codebase, except without the compiler, tests, or clear ownership." Ours reached 548KB before we did anything about it, and cutting it back to 34KB took a measurement pass over what actually loads into context (the numbers are here).
Under posture A, the file's only feedback loop is a human noticing something is wrong. When the agent also writes to the file — ours appends changelog entries and new rules — "a human notices eventually" isn't a loop. It's a hope with a long period.
B: documentation plus periodic audits
You keep the prose, and you add review: a monthly reread, a checklist item asking whether the file is still accurate, someone eyeballing the size. This is a genuine improvement and it's where most teams sensibly land.
Its limit is cadence. Audits run weekly; commits run all day. Every interval between audits is a window in which the file is simply whatever the last commit made it, and if an agent is doing the committing, that window is exactly where the damage accumulates. An audit finds the breakage; it doesn't prevent the breakage from being the live instruction set for six days first.
There's a second problem specific to agent-maintained files: the audit is usually performed by the same party that wrote the text. A model reviewing prose it produced last week tends to ratify the shape it just made. We still run audits — they just can't be the enforcement layer.
C: the file is configuration, and the commit gate is its compiler
This is what we run. test/ops/claude-md-structure.test.ts reads the real files on disk and asserts six things. It runs inside pnpm test, which is a precondition for every commit, so these aren't guidelines — a rules file that violates them cannot be committed.
-
Size ceiling.
CLAUDE.mdmust be at or underCLAUDE_MD_SIZE_WARN_BYTES. That constant is45_000, and it's imported fromsrc/ops/health-check.ts— the same number the runtime health check warns on. One definition, two consumers, so the advisory layer and the enforcing layer cannot drift apart. -
No dangling skill references. Every skill the body names must exist on disk with a
SKILL.md. - No orphaned skills. Every skill directory that exists must be reachable from the body's trigger tables.
- Every
SKILL.mdhas a non-emptydescriptionin its frontmatter. - Every
SKILL.mdis under 500 lines. -
Every file in
.claude/rules/declares apaths:list in frontmatter with at least one entry.
Two of those deserve unpacking.
The schema is a naming convention, not a YAML file. There is no schema document anywhere. The "declaration" is the phrase <name> skill appearing in the prose, and the parser is one regex:
/(?<![A-Za-z])([a-z][a-z0-9-]{2,}) skill(?!s)/g
Anywhere the body writes "publish-product skill" or "incident-response skill", that counts as a reference the gate will resolve. The instruction file stays readable English; the machine-checkable structure is layered on top of how we already write.
Check 3 is the one that surprised us. Check 2 (dangling reference) is the obvious direction, and it exists because we broke it for real: during the restructure that split procedures out of the body, a publish-product reference was left pointing at nothing. But check 3 runs the other way — a skill that exists with no trigger in the main file. Skills only load when a task matches their description, so an obligation with no path back from the body doesn't produce an error. It just silently stops being executed, forever, and the file still looks fine. That's the failure a periodic audit is worst at finding, because there's nothing to notice.
We currently have nine skills and one rules file under this gate.
What C cannot check, stated plainly
Our commenter anticipated this too — "a smaller file can still contain contradictory, duplicated, or low-value rules" — and proposed a CI check for contradictory instructions, not just size. We don't have that, and I'd rather be precise about why than call it a roadmap item.
Three things sit outside the gate's reach:
Whether an instruction is true. The gate confirms that product-review skill resolves to a real SKILL.md. It holds no opinion on whether the procedure inside is still the procedure. Structure is verifiable; currency is not.
Whether two instructions contradict. Deciding that two sentences conflict is a semantic judgment. You can get one from a model — we do, in other contexts — but a model reviewer is not a gate. It's non-deterministic, and a check that sometimes passes the same input is a suggestion with a CI badge.
Whether the agent follows any of it. No amount of linting touches compliance. That's observed in behavior, not in the config, and it's the largest gap by far.
We got burned by the first one concretely. We once recorded a freeze decision — stop generating monthly reports — as a sentence in the body. The sentence survived the next structural edit; the intent didn't. What we did about it wasn't general contradiction detection. We promoted that one fact out of prose into state/monthly-report-freeze.json, with typed fields (frozen, frozenAt, instruction, reactivationCondition), a loader, and its own test. One semantic claim earned its own type because it had already cost us something.
That's the realistic shape of posture C: the gate is a shape checker, not a truth checker, and you migrate individual facts across the line as they prove expensive.
The layering
Instructions stay prose because the consumer is a model, and you cannot express a judgment call in YAML. But the container — size, reference integrity, required frontmatter, whether a trigger path exists — is fully mechanical.
So the content is documentation and the container is code. Treat the file as something reviewed by tests rather than a wiki page, and the "ownership" the question asks about arrives for free: the gate is the reviewer of record whenever no human reviews the commit, which for us is most commits.
Our governance rules live alongside it in prose, deliberately: change means delete rather than append, the changelog keeps only the current version plus two, and weakening or removing an obligation requires explicit approval recorded with purpose, measured evidence, impact, and risk. Those are prose rules about prose. The gate enforces only the subset with a mechanical shadow — and knowing which of your rules casts one is most of the work.
The costs, in the order they hit us
Rigidity is real. Last time I checked, CLAUDE.md was 44,982 bytes against a 45,000-byte ceiling. Eighteen bytes. At that point the gate stops being a size check and becomes editorial policy: every new rule must displace an old one. That's precisely what the append-only prohibition intends — and it also means a genuinely necessary rule arrives when the budget is full, and the fastest available path is to put it somewhere unmeasured.
A gate creates a gradient. Whatever is measured gets tidy; whatever isn't absorbs the overflow. Size caps push prose into skills, skills have their own 500-line cap, and below that nothing checks whether the sentences are true. Goodhart applies to your own rules file, and the pressure points away from the gate by construction.
The gate is code and inherits code's problems. Ours parses natural language, so it carries a hack: the extractor requires a non-letter before the match and excludes the plural "skills", because our product catalog contains the phrase "Claude Code skills" and an earlier version cheerfully matched ode skill inside it. Any convention you enforce over prose will have its own version of that, and it needs its own tests.
So: yes, but "eventually" is doing too much work
The move worth making isn't reclassifying instruction files as configuration wholesale. It's splitting one file into the part with a mechanical shadow and the part without, gating only the first, and promoting individual facts across that line as they earn it.
Schemas: for shape, yes; for the instructions themselves, no — the reader is a model. Validation: mechanical properties only. Ownership: the gate owns what no human reviews. Automated linting: yes, and it's the cheapest of the four to build.
What you don't get is a compiler for meaning. A 20KB file with two rules telling the agent opposite things will commit cleanly under our gate. What won't commit is a file pointing at a procedure that no longer exists, or a procedure that exists with no way to be invoked — and those are the failures that never announce themselves.
This gate guards the pipeline behind Rulestack, where the rules files and agent skills we sell are built by the same system that runs on them.
Shorter notes, as the gate catches things: @ai-shop.bsky.social.
Top comments (0)