{"slug": "your-claude-md-is-full-of-wishes-7-rungs-that-make-a-rule-stick", "title": "Your CLAUDE.md is full of wishes: 7 rungs that make a rule stick", "summary": "A developer analyzed 57 sessions with Claude and found that rules enforced by machine checks had zero violations in 3,131 opportunities, while rules held only in memory were violated 30–45% of the time, with one rule's compliance dropping from 60% to 31.8% over time. The developer proposes a seven-rung hierarchy of guardrails, from regeneration and action blocking to runtime detectors and documentation, to make rules stick.", "body_md": "You start a project with Claude. A few weeks in you have a file of rules, and every line got there because something went wrong once.\n\nThe agent pushed to main. *Never commit to main; always work on a branch.*\n\nA test reached the live API and moved real data. *Tests never call production.*\n\nA handler wrote to the database directly. *All writes go through the repository.*\n\nThat file is everything the project has learned, and it's the one part of it nobody ever checks.\n\nHere's the catch: **a dead rule and a live rule are the same sentence.** A line that's been ignored for weeks looks exactly like the line that's holding.\n\nThe first one is easy. Git has branch protection, you flip it once and stop thinking. Now look at the other two, and at everything under them in your own file. Which of those has a switch?\n\nOne question sorts the file: **if this rule is broken right now, does anything fail?** A test, a linter, a hook, a CI gate. Any of them. Nothing else predicts it, not the wording and not what the incident cost. If the answer is \"nothing fails, someone might notice in review,\" you wrote a wish, and wishes decay.\n\nI went through 57 of my own sessions and counted, for every rule that leaves a mechanical trace, how often I did the forbidden thing and how often I did the prescribed one. The file split in two, and the split had nothing to do with which rules mattered.\n\nRules with a machine check behind them: **0 violations in 3,131 opportunities.** One near-miss, in a test fixture.\n\nRules held in memory only: 30–45%, drifting down. One ran at 60% across the first half of my sessions and 31.8% across the second, and the file gave me no hint of that.\n\nHalf of that zero is tautology, and I'd rather say so first. If the hook refuses the command, the violation never reaches the transcript I'm counting. That's the whole point of a guard, but it means the number describes my machinery, not my discipline.\n\nIt's the start of one. Guards come in rungs, and you're probably standing lower than you have to.\n\n| # | Rung | What it does | Breaking it |\n|---|---|---|---|\n| 1 | Regeneration | the artifact is rebuilt; the edit is erased | impossible |\n| 2 | Blocked at the action | a hook rejects the tool call before it runs | impossible |\n| 3 | Will not compile | the wrong call has no valid shape | impossible |\n| 4 | AST guard | a test parses structure, not text | caught in CI |\n| 5 | Cross-artifact guard | two artifacts must agree with each other | caught in CI |\n| 6 | Runtime detector | production logs an error you can see | caught after the fact |\n| 7 | Written where it always loads | the only option for meaning-rules | visible if you look |\n\nThe top three don't detect a violation. They make it impossible or refuse it outright. Everything below reports afterwards.\n\nSome files aren't written by hand at all: a routing table built from an API spec on every build, a client library generated from a schema.\n\nWhen the rule is \"do not edit this file by hand,\" nothing needs to enforce it. The agent edits the file, the next build regenerates it, the edit is gone. Every rung below detects a violation once it has happened. This one means it never persists, so the rule has no job left to do.\n\nBefore writing \"never hand-edit X,\" ask whether X could be generated from something you already have. It costs a source of truth, a build step, and a header line in the generated file saying so. Skip the header and the agent watches its change vanish on the next build with no idea why.\n\nA hook sees the proposed tool call before it runs and can refuse it. The agent decides to force-push, your script reads the command, matches it against a short list, returns a refusal. The push never happens.\n\nThe refusal should carry a reason. The agent reads it and takes another route; a bare \"no\" gets the same command retried a second later.\n\nAn interception doesn't have to end in refusal. It can substitute. A hook catching plain-text search can route the request to a code-navigation service instead, so the agent gets a real answer where it would have got a wall of matches. That hook makes the work better while it stands guard.\n\nThe failure mode is a pattern that's too broad. A hook matching `push`\n\nwill eventually refuse something you wanted, and you'll find out mid-task with no way to say \"yes, this one.\" Write the match narrow and read the refusal log for a week.\n\nSometimes a rule can be replaced by a shape the language won't accept.\n\nSay the rule is \"never build a file path by gluing strings together.\" Written down, that's a wish. Give the function a parameter type that only a properly constructed path satisfies, and a glued string stops being a mistake someone might catch in review. It stops being expressible.\n\n``` php\n# rung 7: a sentence in a file\ndef read_config(path: str) -> Config: ...\n\n# rung 3: the wrong call has no shape\ndef read_config(path: SafePath) -> Config: ...\n```\n\nThe compiler enforces it on every call and there's nothing left to maintain.\n\nThe second rule from the top of this article lives here too. *Tests never call production* stays a wish as long as the test can build any client it likes. Give the harness a client type with no production constructor and nobody has to remember the rule.\n\nThis rung is only as real as your type checking. If the checker doesn't run in CI, or your tests sit in a directory it skips, rung 3 does nothing.\n\nA test that parses the syntax tree and asserts a structural property: no handler calls the database driver directly. That's the third rule from the top of this article, moved off the page and into CI, and it took one test. The same shape catches a route carrying a secret in a path parameter, or a log field carrying a biometric vector.\n\nStructural checks survive renaming and reformatting. Text search doesn't. A guard checking that a feature flag had been removed searched for the flag's name as a substring and missed its own deletion, because a longer variable still contained that name as a prefix.\n\nA cross-artifact guard asserts that two *different* files agree: every environment flag the code reads is declared in the deployment file, every job kind in code is admitted by the database constraint. Both sides can be internally consistent and still disagree, and that bug survives review, survives the linter, survives the suite, then turns up in staging as a config key nobody set.\n\nA runtime detector covers what depends on real data no fixture reproduces. Pick a condition that's impossible rather than unusual: a few stored references failing to resolve against a rebuilt document is normal, but if *every* reference fails, the thing they point into changed shape underneath them. Fire on \"all of them failed,\" stay quiet on \"some did.\"\n\nThen the bottom rung, where most rules live today. \"Do not treat a cache miss the same as a cache error\" can't be checked by any parser, because both are a function returning without data and the difference is intent. Rules about meaning will always exist and no ladder reaches them. Text is the only mechanism left, which makes *where you put that text* a separate problem. In my audit, these are the ones that decayed.\n\nOpen your rules file. For each line, ask what fails today if it's broken, then how far up the ladder it could go. Most of mine sat two rungs below where they could have.\n\nThe two cheapest moves: anything protecting a file that could be generated belongs on rung 1, and anything phrased as \"never run\" or \"never touch\" belongs on rung 2, where the hook is a few lines of script.\n\nThen check the file against what you actually did:\n\n```\nRead my session transcripts for this project.\n\nPick two or three rules from my instructions file that leave a\nmechanical trace: a forbidden command, a banned import, a tool\nI am supposed to use instead of another one.\n\nFor each rule, count two things:\n  how many times I did the thing the rule forbids\n  how many times I did the thing it prescribes\n\nReport both raw numbers, never a percentage on its own.\nThen split my sessions in half by date and report each half\nseparately.\n```\n\nThe last instruction is the one that earns its keep. One figure tells you where you are; two halves tell you which way you're moving. A decaying rule looks healthy in the average.\n\nTwo rules in my file, written the same week by the same person, with the same conviction behind both. One held 3,131 times. The other lost half its compliance and I didn't notice. The only thing that differed was whether anything would have failed.\n\n*From an audit of 57 of my own agent sessions, 23,226 tool calls. Compliance was matched over command text, so read those counts as directional; the 0-of-3,131 and the 60%/31.8% split were checked case by case.*", "url": "https://wpnews.pro/news/your-claude-md-is-full-of-wishes-7-rungs-that-make-a-rule-stick", "canonical_source": "https://dev.to/michael_rakutko/your-claudemd-is-full-of-wishes-7-rungs-that-make-a-rule-stick-2nc1", "published_at": "2026-08-21 18:56:20+00:00", "updated_at": "2026-08-21 19:15:16.074285+00:00", "lang": "en", "topics": ["artificial-intelligence", "developer-tools", "ai-agents", "ai-safety"], "entities": ["Claude"], "alternates": {"html": "https://wpnews.pro/news/your-claude-md-is-full-of-wishes-7-rungs-that-make-a-rule-stick", "markdown": "https://wpnews.pro/news/your-claude-md-is-full-of-wishes-7-rungs-that-make-a-rule-stick.md", "text": "https://wpnews.pro/news/your-claude-md-is-full-of-wishes-7-rungs-that-make-a-rule-stick.txt", "jsonld": "https://wpnews.pro/news/your-claude-md-is-full-of-wishes-7-rungs-that-make-a-rule-stick.jsonld"}}