Your CLAUDE.md only grows. Every incident adds a rule, every preference becomes a paragraph, and six months in you have a file that reads like a wiki — and an agent that follows maybe half of it.
The uncomfortable mechanics: CLAUDE.md is loaded into context automatically, which means every line is a tax on every single request, whether it's relevant or not. And instructions are advisory — the more of them there are, the weaker each one pulls. I've watched my own rules drift off quietly in long sessions and only caught it in the diff.
So the real question isn't "what should I write in CLAUDE.md?" It's "what has earned a permanent seat in context — and where does everything else live?"
Claude Code gives you four places to put guidance, and they have very different cost models:
| Destination | Loaded | Costs tokens | Enforcement |
|---|---|---|---|
| CLAUDE.md | every session, automatically | always | advisory |
| Skill | body only when the task matches | on demand | advisory, but scoped |
| Hook | never enters context as prose | ~zero | deterministic |
| docs/ file | when the agent (or a rule) points at it | on demand | none — it's reference |
Here's the sorting test I use, one sentence per destination.
The one-sentence test
Keep it in CLAUDE.md if it's true on every turn, cheap to state, and expensive to violate. Build commands, naming conventions, "tests live in test/, mirrored by path", the tone your commit messages use. If you'd want the rule active even in the middle of an unrelated refactor, it's an invariant — that's what the always-loaded file is for.
Move it to a skill if it starts with "when doing X". Deploy checklists, a review rubric, the release-notes format, your migration playbook. A skill's name and description stay visible so the agent knows it exists, but the body only loads when the task actually matches. That's exactly the deal you want for situational expertise: discoverable, but not billed on every request. (Format details: how to write a SKILL.md that actually triggers.)
Move it to a hook if the sentence contains "never" or "always" and a machine could check it. Formatting before commit, protected paths, "don't touch .env", "block pushes to main". Don't ask a language model to remember what a shell script can enforce — a hook fires deterministically whether the context is fresh or fifty files deep. (Hook config structure and matchers.)
Move it to a docs file if it's something the agent should read, not obey. Architecture overviews, API quirks, the history of why the billing module is weird. Put it in docs/, and leave one line in CLAUDE.md saying when to read it: "Touching billing? Read docs/billing-history.md first." Reference material rents context only when it's relevant.
Why the default answer is "not CLAUDE.md"
Three costs stack up on the always-loaded path:
- You pay it every request. A 4,000-token CLAUDE.md is 4,000 tokens on every prompt, every tool call round-trip, all day. I ran this audit on my own setup recently: half the file only mattered on release days. Moving that half out cut every request's overhead and nothing broke.
- Attention dilutes. Twenty rules each get a sliver of the model's compliance budget. Five rules get real weight. This isn't a documented parameter — it's the consistent shape of what I see in practice: lean files hold, bloated ones get sampled like suggestions.
- Long sessions erode prose. As context fills with diffs and tool output, early instructions fade — and after compaction, what survives is a summary, not your exact wording. (What survives compaction, and how to keep rules alive.)
Hooks dodge all three. Skills dodge the first two. Docs dodge all three but enforce nothing. CLAUDE.md is the only slot that pays full price — spend it on the few rules that deserve it.
What a lean CLAUDE.md looks like
# myproject — agent guide
## Commands
- Build: `pnpm build` / Test: `pnpm test` (single file: `pnpm test path/to.test.ts`)
- Never run `pnpm deploy` directly — use the deploy skill.
## Conventions (always)
- TypeScript strict; no `any`. Errors are returned, not thrown, in `src/core`.
- Tests mirror source paths. New modules need a test file in the same PR.
- Commit messages: imperative mood, reference the issue.
## Enforced by hooks (listed so you know they exist)
- Format-on-edit, protected paths (`.env`, `migrations/`), test gate before commit.
## Where things live
- Architecture: `docs/architecture.md` (read before cross-module changes)
- Billing quirks: `docs/billing-history.md` (read before touching `src/billing`)
## When unsure
- Prefer asking over guessing on anything in `migrations/`.
That's the whole shape: commands, invariants, a pointer to what's machine-enforced, a map, and an escalation rule. One screen. The "enforced by hooks" section is deliberately redundant — the hook does the enforcing, the mention just stops the agent from being surprised.
Migrating a bloated file in ~20 minutes
- Measure it. Paste your CLAUDE.md into a token counter. Write the number down — this is your before.
- Label every block with one of four words: always (true every turn), situational ("when doing X"), never-event (machine-checkable prohibition), reference (explains, doesn't instruct).
-
Move everything that isn't always. Situational →
.claude/skills/<name>/SKILL.mdwith a description that names the trigger. Never-events → hooks or CI checks. Reference →docs/, with a one-line pointer left behind. -
Add a canary. One harmless, visible rule — "start responses touching
src/billingwith the word BILLING" — so you can tell at a glance whether the file is being honored at all. (More ways to verify what actually ran.) - Re-measure and re-audit monthly. The file will try to grow back. When a new rule wants in, make it pass the one-sentence test first — most candidates are situational or machine-checkable, and belong downstream.
One honest caveat: none of this makes prose rules reliable. Advisory is advisory. What the sort gives you is a small enough always-loaded core that the model can actually hold it, plus deterministic enforcement for the things that genuinely can't be violated. If a rule keeps breaking after all this, that's your signal it wanted to be a hook all along.
If you're not sure how your rules files get read in the first place — CLAUDE.md, AGENTS.md, and Cursor's rules all load differently — start with how each tool actually loads your project rules.
I'm Rulestack — I build and maintain drop-in rule, skill, and hook packs for Claude Code, Cursor, and Codex, at rulestack.gumroad.com. I post working AI-coding tips on Bluesky at @ai-shop.bsky.social — follow along if this was useful.
Top comments (9)
The "earned a permanent seat in context" framing is the useful one. Bloated CLAUDE.md files quietly turn into soft suggestions mid session, and the only place that shows up is when you read the diff and notice a naming rule or a protected path got ignored. Moving the "when doing X" material into skills and the hard "never" rules into hooks matches what actually holds under load. Advisory prose is fine for invariants. Deterministic checks are what stop an agent from rewriting something you thought was already settled.
The 'only shows up when you read the diff' part is exactly what pushed me to hooks for the hard rules — by then you've already merged two violations. And in my experience the decay isn't binary: rules lose force gradually, which is why I've started auditing which rules actually fired vs got ignored instead of trusting them. Curious how this plays out in your multi-agent terminal — does each agent get the same CLAUDE.md, or do you scope instructions per agent?
I appreciate the sorting test you've outlined for determining where guidance should live in a Claude Code project, particularly the distinction between CLAUDE.md, skills, hooks, and docs. The idea that CLAUDE.md should only contain invariants that are true on every turn, cheap to state, and expensive to violate resonates with my experience of maintaining large codebases. I've found that moving situational expertise to skills and deterministic rules to hooks can significantly reduce the overhead of context loading. Have you found any challenges in maintaining a balance between conciseness in CLAUDE.md and ensuring that essential rules are not lost in skills or hooks?
Yes — the failure mode I hit most is a rule that's important but rarely relevant: too rare to justify CLAUDE.md, but once moved to a skill it silently stops firing because the description doesn't match how the situation actually presents itself. Two things helped: (1) treat recurring violations as a signal to promote the rule from prose to a deterministic gate (a hook or a CI check) rather than moving it back into CLAUDE.md — prose that failed once will fail again; (2) audit skills by their firing history, not their content: a skill that never triggers usually has a description problem, not a knowledge problem. The honest cost: 'essential but non-deterministic' rules have no perfect home — those stay in CLAUDE.md and I accept the token spend.
This is a great breakdown of how to manage AI coding instructions effectively. I especially like the distinction between CLAUDE.md as a small set of always-needed invariants and skills/hooks/docs as specialized layers. In large projects, context quality becomes just as important as code quality, and reducing unnecessary instructions can significantly improve agent reliability.
The point about moving "never/always" rules to deterministic hooks is especially valuable. AI agents are powerful, but critical constraints like security checks, protected files, formatting, and deployment rules should not depend on model memory.
I'm curious how you handle team-scale adoption of this approach. When multiple developers contribute, how do you prevent personal preferences from turning into unnecessary CLAUDE.md rules while still preserving important project conventions?
Great question — the filter that works for us: a shared rule has to name the failure it prevents, ideally one that happened more than once. 'It broke, here's the incident' earns a line in CLAUDE.md; 'I prefer X' stays in the contributor's user-level memory or a local override that never hits the repo. We also try to prune on a schedule, though we haven't fully cracked the cadence — how are you drawing that line on your team today?
That incident-based filter is a really practical way to keep shared AI instructions healthy. I like the distinction between “a failure we need to prevent” and “a preference someone happens to have” — it mirrors how we should design reliable engineering systems in general.
For larger teams, I think the next challenge is making these rules observable: tracking which skills are actually triggered, which hooks catch violations, and which CLAUDE.md entries no longer provide enough value for their context cost. Treating AI configuration like production code with ownership and maintenance seems like the right direction.
I’d be interested to hear how you’re approaching reusable rule/skill packs for teams. Are you currently working with companies or developers who need help setting up AI coding workflows at scale? I’d love to connect and explore possible collaboration opportunities.
Tracking which entries still earn their context cost is the part I keep circling too — the incident-based filter tells you what to add, but nothing in the loop tells you what to retire. Closest I've got is reviewing rules against recent sessions and demoting anything that hasn't prevented a failure in weeks. On packs: everything I publish is at the Rulestack shop (link in the article footer), and the easiest way to reach me is right here in the comments or on Bluesky @ai-shop.bsky.social. Not taking on consulting engagements at the moment, but happy to keep comparing notes in public.
Thanks for sharing that perspective. I think the point about treating AI configuration like production code is becoming increasingly important as teams move from experimenting with agents to relying on them in real workflows.
The idea of measuring rule effectiveness through actual failures, trigger history, and maintenance cycles feels like the next evolution beyond simply writing better prompts. Similar to observability in software systems, AI workflows need visibility into what instructions are influencing behavior and what should be retired.
I’m exploring similar areas around LLM agents, developer workflows, and reliable AI systems, so I’d definitely enjoy continuing the conversation and exchanging ideas as this space evolves. Thanks for sharing these practical insights! 🚀