Writing a CLAUDE.md That Actually Changes What the Model Does
By Waseem Ahmad — Full Stack Developer & AI Engineer ·
TL;DR
- CLAUDE.md is context loaded into the model's attention window, not enforced configuration. The model can and will skip instructions when the file is bloated or vague.
- The official hard limit is 200 lines; adherence starts degrading well before that. Every rule you add makes every other rule slightly less likely to be followed.
- Rules that must happen without exception belong in a
PreToolUsehook, not in CLAUDE.md. Text instructions are guidance. Hooks are enforcement. - Scope your instructions: project root for shared team conventions,
~/.claude/CLAUDE.mdfor personal defaults, subdirectory files for module-level overrides. - The fastest fix if Claude ignores your file: check the length, cut anything inferable from the code, and move mechanical rules to hooks.
Every Claude Code project I open has a CLAUDE.md. Most of them read like a new-hire handbook written by someone who has never onboarded a new hire: paragraphs of philosophy, vague intentions, and aspirational promises about code quality. They read like a new hire handbook written by someone who has never onboarded a new hire. The agent reads the file, learns nothing actionable, and proceeds to guess. You get mediocre code. You blame the model.
The model is not the problem. The file is. Here is how to fix it.
What is CLAUDE.md actually doing under the hood?
CLAUDE.md files are markdown files that give Claude persistent instructions for a project, your personal workflow, or your entire organization. You write these files in plain text; Claude reads them at the start of every session. The key word is reads, not enforces. Claude treats them as context, not enforced configuration. To block an action regardless of what Claude decides, use a PreToolUse hook instead.
That distinction matters more than any other sentence in this article. The moment you write "never do X" in CLAUDE.md and expect deterministic compliance, you have put the wrong rule in the wrong place. "Never do this" in CLAUDE.md is the wrong tool. Claude will follow the instruction most of the time, but when under pressure, in a long session or an ambiguous situation, or due to a prompt injection in a file accessed as part of the task, the model can fail to follow a prompted rule. A real guardrail needs to be deterministic, and the enforcement methods are hooks and permissions.
Why does length kill compliance?
The model has a finite attention budget per turn. Claude isn't malicious — it's running out of attention. Past roughly 80 lines you'll notice rules dropping; past 200 lines, large blocks get ignored entirely. The official Claude Code docs make this a hard guideline: keep it concise. For each line, ask: "Would removing this cause Claude to make mistakes?" If not, cut it. Bloated CLAUDE.md files cause Claude to ignore your actual instructions.
Recent research confirms what production users keep finding: instruction-following degrades non-linearly with rule count. The arxiv paper 2507.11538 on instruction-following capacity shows adherence per rule drops as you stack more. Translation: every rule you add makes every other rule slightly less likely to be followed.
Boris Cherny, who shipped Claude Code at Anthropic, keeps his own file lean. Boris Cherny's CLAUDE.md at Anthropic has around 2,500 tokens (~100 lines). The consequence: every line has to earn its place. According to an InfoQ interview in January 2026, Boris' own CLAUDE.md has just 2,500 tokens (around 100 lines) and his team shipped Claude Code itself.
What earns attention vs. what wastes tokens?
| Content type | Put it in CLAUDE.md? | Where it actually belongs |
|---|---|---|
Build commands (pnpm test, pnpm build) |
Yes | CLAUDE.md root section |
| Architectural decisions not obvious from the code | Yes, with the reason why | CLAUDE.md, brief |
| "Write clean code" / "be consistent" | No | Cut it. Claude already wants this. |
| Rules that must happen 100% of the time (lint, test, secret redaction) | No | PreToolUse or PostToolUse hook |
| Facts already in package.json or tsconfig | No | Reference with @path/to/file, don't copy |
| Module-level conventions for one subdirectory | No | .claude/rules/<name>.md with a glob |
| Personal workflow preferences (your editor, commit style) | No | ~/.claude/CLAUDE.md global scope |
| Multi-step procedures used for specific tasks | No | A Skill in .claude/skills/ |
The rule about explaining why is not optional padding. Explain why every rule matters. The "why" isn't fluff — it's how Claude decides edge cases. A rule with a reason ("we hit 8s LCP from over-clienting") generalizes to similar situations. A rule without a reason gets ignored the moment context shifts.
The scope system: one file is not enough
Unlike AGENTS.md or .cursorrules, CLAUDE.md is not just loaded and concatenated. Claude Code has a layered discovery system: global, organization, project, local, and subdirectory scopes, each with different precedence.
The mental model that works: project files describe the project, global files describe you. In practical terms:
- Global (
~/.claude/CLAUDE.md): your personal coding style, preferred patterns, language. Loads on every project. - Project root (
./CLAUDE.md): build commands, stack, conventions. Commit this to git so the team shares it. - Local (
./CLAUDE.local.md): personal notes about this repo. Add to.gitignore— never shared. - Subdirectory (
./src/payments/CLAUDE.md): module-level overrides. CLAUDE.md files cascade. In a monorepo, both root/CLAUDE.md and root/services/billing/CLAUDE.md load while you're working the billing service. Handy when folder conventions diverge.
For rules that only apply in a specific path, skip the cascade entirely. rules/*.md is path-gated. Guidance specific to your migrations folder shouldn't bloat every session through CLAUDE.md, rather it belongs in .claude/rules/migrations.md with a glob.
Hooks: when CLAUDE.md is the wrong tool entirely
Text instructions are guidance. Hooks and plugins are enforcement. This is the line that most setups get wrong. A hook fires at a specific lifecycle event — before a tool call, after a file write, at session end — and can return an exit code that blocks the operation entirely.
PreToolUse is the only hook that can block actions. Hooks now have three types: command (directly runs shell script), prompt (LLM evaluation, not 100% reliable), and the newly added mcp_tool (April 2026, directly calls a tool on an already-connected MCP server). In PreToolUse events, exit code 2 blocks the operation; PostToolUse's exit code 2 can't retroactively prevent an already-executed action, only feeds stderr back to Claude.
Common candidates to move from CLAUDE.md to a hook:
- "Never commit secrets" — a
PreToolUsecommand hook that runs a secret-scanner on the diff - "Always run tests before finishing" — a
Stophook that exits code 2 until the test suite passes - "Do not touch the production database config" — a
PreToolUsehook that matches the file path and blocks
One caveat: not every preference needs a hook. If the cost of the model occasionally not doing something is low, CLAUDE.md guidance is lighter weight and easier to maintain. Over-hooking has its own tax: more shell processes, more latency, more things to debug when they misbehave.
The auto memory layer: useful, but separate
As of v2.1.59, Claude Code also writes its own memory. Auto memory notes Claude writes itself have been on by default since v2.1.59. These live at ~/.claude/projects/<project>/memory/ and are separate from your CLAUDE.md. The official contract is that Claude loads only the first 200 lines of MEMORY.md, or the first 25KB, at startup. Topic files are not startup-loaded wholesale; they are read on demand when the current task makes them relevant. That is a useful design, because it stops the startup context from becoming a giant junk drawer, but it also means a file existing in the memory folder is not the same thing as that file being in the current turn.
The practical consequence: do not assume auto memory will carry your CLAUDE.md instructions forward across sessions. The two systems serve different roles. CLAUDE.md is for durable intent you write deliberately. Auto memory is for patterns the model learns from your corrections. Treat CLAUDE.md as the place you write down what you'd otherwise re-explain. Add to it when a new teammate would need the same context to be productive.
How to audit a broken CLAUDE.md
When instructions are not landing, run /memory inside the session. /memory and /context stop being optional nice-to-know commands and become real debugging tools. /memory shows which CLAUDE.md, CLAUDE.local.md, and rules files are loaded in the current session. /context shows the live context breakdown.
Then ask three questions:
- Is the file over 200 lines? Cut it. Move anything mechanical to hooks and anything scope-specific to rules files.
- Do the rules say what to do, or how to feel about code? "Server components by default; add
use clientonly when event handlers are needed" is testable. "Write clean code" is not. - Does each rule carry its reason? A rule without a reason gets dropped when context shifts.
On the Biz365 AI project, the agent was ignoring formatting and test conventions mid-session. The file was not wrong, it was too long, and the conventions for one module were fighting with the top-level rules. Splitting into scoped rules files and moving the "always run tests" rule to a Stop hook fixed the drift without adding a single new instruction.
If you work on AI-heavy codebases regularly and want a structured setup for this, the AI development workflows service covers CLAUDE.md architecture, hook configuration, and Skill design as part of the engagement. For teams running LangChain-based pipelines alongside Claude Code, the RAG system build guide shows how the same scoping discipline applies when your codebase grows to include retrieval infrastructure.
FAQ
How long should a CLAUDE.md actually be?
Under 200 lines is the official guidance. Scope the rest into .claude/rules/. In practice, Claude attends to roughly 150 instructions reliably. Every line earns its place. If you are starting from scratch, the /init command will scaffold a baseline from your codebase, and you should curate that output down rather than adding to it.
Why does Claude keep ignoring a rule I added?
If Claude ignores your file, 90% of the time it's length, vagueness, or a missing "why." Check the total line count first. Then check whether the rule describes an observable, testable behavior. If it passes both tests and still gets ignored, the rule probably belongs in a PreToolUse hook, not a text instruction. It's context, not enforcement. Use a PreToolUse hook for must-happen rules; make instructions specific.
Should the project CLAUDE.md go in git?
Yes, the project-root file should be committed. The project-specific ./CLAUDE.md belongs in Git for team consistency. Personal notes and secrets belong in ./CLAUDE.local.md, which sits in .gitignore. The global scope file ~/.claude/CLAUDE.md remains local anyway. Treat the committed file as onboarding documentation for every teammate, human or agent, who opens the repo.
Can I use @import to split a long file?
CLAUDE.md supports @import with a maximum of 4 recursion hops. This is useful for monorepos where different packages share some rules but diverge on others. Reference existing files (package.json, tsconfig) with the @path/to/file syntax rather than copying their contents into the instructions. Reference, don't duplicate: point to package.json and tsconfig — don't copy. Use @path/to/file syntax.
What is the difference between a Skill and a CLAUDE.md rule?
Claude Code Skills are folder-based instruction packs that Claude Code loads on demand to turn a general assistant into a specialist for your codebase, workflow, or domain. Each Skill is a directory containing a SKILL.md file plus optional helper scripts and assets; Claude Code reads the folder name and description on every session, and pulls in the body when the current task matches. CLAUDE.md rules are always in context; Skill bodies are loaded on demand. Multi-step procedures — a deploy workflow, a database migration checklist — belong in a Skill, not as a wall of steps in CLAUDE.md.
Hire me for similar projects
Looking for a developer who can build what you just read about? Let's talk.
Get in Touch