Writing CLAUDE.md
Project context files that make AI coding agents follow your rules.
Last updated
Workflow1. The Instruction Budget
Frontier LLMs follow roughly 150–200 instructions total before compliance degrades. Claude Code's own system prompt consumes around 50 of those, leaving 100–150 for your CLAUDE.md. Every line you add competes for finite attention.
A production CLAUDE.md should land between 60 and 200 lines. Shorter files get higher per-instruction compliance; longer files dilute each rule's weight. ETH Zurich research found that auto-generated context files reduce task success by 0.5–2% while increasing token costs 20–23%. The lesson: each rule must earn its place through observed failure, not speculative coverage.
2. What to Include vs Exclude
Include
- Bash commands Claude can't guess (
make dev,pnpm test:e2e) - Style rules that differ from defaults (tab width, import ordering)
- Testing instructions and required coverage thresholds
- Repo etiquette (branch naming, commit message format)
- Architectural decisions the codebase doesn't make obvious
- Dev environment quirks (required env vars, Docker prerequisites)
- Common gotchas specific to your project
Exclude
- Anything Claude can figure out from reading the code
- Standard language conventions (PEP 8, Go formatting)
- Detailed API documentation — link to it instead
- Frequently changing information (version numbers, endpoint URLs)
Architectural overviews "did not reduce navigation time" in testing — agents explore codebases on their own. Focus on what they cannot infer from the code itself.
3. Progressive Disclosure
Keep your root CLAUDE.md lean. Place task-specific documentation in agent_docs/ or .claude/skills/ and reference it with @path/to/import syntax. Claude loads only what's relevant to the current task.
Five loading levels
| Level | Path | When loaded |
|---|---|---|
| Global | ~/.claude/CLAUDE.md | Every session |
| Project root | ./CLAUDE.md | Every session in this repo |
| Parent dirs | ../CLAUDE.md | Monorepo packages inherit parent |
| Child dirs | ./src/CLAUDE.md | On-demand when working in that dir |
| Rules | .claude/rules/ | Auto-loaded, glob-matched by path |
Skills (.claude/skills/) load only when the agent determines they're relevant. This keeps the active instruction count low while making deep knowledge available on demand.
@docs/api-conventions.md) rather than embedding snippets that go stale when the source changes.
4. AGENTS.md Cross-Tool Standard
AGENTS.md is the cross-tool equivalent of CLAUDE.md, adopted by the Linux Foundation (AAIF) and present in over 60,000 GitHub repos. It works across Codex, Cursor, Copilot, Aider, Gemini CLI, Windsurf, Zed, and 55+ other tools.
The symlink pattern
If your repo serves multiple AI agents, make CLAUDE.md a symlink to AGENTS.md so both tools read the same file:
ln -s AGENTS.md CLAUDE.md
Three-tier boundary system
| Tier | Behavior | Example |
|---|---|---|
| Always | Do this every time, no exceptions | Lint before commit |
| Ask First | Pause and confirm with the user | DB schema changes |
| Never | Hard block, refuse to proceed | Commit secrets, force push |
project_doc_max_bytes and keep critical instructions in the first 32 KiB if you target Codex.
5. Hooks vs Instructions
CLAUDE.md is advisory — agents can ignore it under pressure, context limits, or ambiguity. Hooks are deterministic: they execute as code every time the specified event fires, with guaranteed behavior.
Rules that "must happen every time with zero exceptions" belong in hooks, not CLAUDE.md. The common pattern: use CLAUDE.md for preferences and guidance, hooks for enforcement and gates.
Example: block force-push via hook
// .claude/settings.json
{
"hooks": {
"PreToolUse": [
{
"matcher": "Bash",
"hook": ".claude/hooks/block-force-push.sh"
}
]
}
}
#!/bin/bash
# .claude/hooks/block-force-push.sh
# Reads tool input from stdin, rejects force-push commands
INPUT=$(cat)
if echo "$INPUT" | grep -qE '(--force|push\s+-f)'; then
echo "DENY: force-push is not allowed" >&2
exit 2
fi