Claude Code Ignores Your CLAUDE.md? It's the Delivery Mechanism, Not a Bug (2026 Fix)
Boris Cherny, the author of Claude Code, once said in a tweet that went viral (8M views) that his own CLAUDE.md setup is "surprisingly vanilla."
That made me think. Here at Shareuhack, we run a content system powered by 8 autonomous agents, with a CLAUDE.md over 300 lines, dedicated skills directories, and per-agent operational memory. Is that complexity actually worth it for the average developer? And for those who keep adding rules to CLAUDE.md but still find Claude ignoring them — what's actually going wrong?
The answer in this article surprises most people: instructions being ignored isn't a bug, it's a design you need to understand. Once you grasp the mechanism, you'll realize most people are solving the wrong problem.
Timeliness note: This article is based on Claude Code documentation and community practices as of May 2026 (latest version v2.1.126, released May 1, 2026). Claude Code updates frequently, with major hooks improvements, Agent Teams, and new slash commands added in April-May 2026. Use alongside the Anthropic official docs.
TL;DR
- Rules getting ignored? CLAUDE.md is delivered as a user message, not system config. Claude judges relevance and may skip rules it deems unrelated to the current task. This is by design, not a bug
- Want 100% enforcement? Move mechanical rules to
hooks(shell-level, bypasses LLM). Keep only implicit knowledge and architectural context in CLAUDE.md. Usesettings.jsonfor security blocks. The conditionaliffield andmcp_tooltype added in April 2026 make hooks even more precise and practical - Not sure what to write? Start with
/init, then cut anything Claude would figure out from your code. A 50-line CLAUDE.md with real Gotchas beats a 300-line doc full of obvious instructions (research confirms: bad context files perform worse than no context files)
"Instructions Ignored" Isn't a Bug: The Delivery Mechanism You Need to Know
Here's the most common misconception.
CLAUDE.md content is delivered to Claude as a "user message after the system prompt" — not as a system-level forced configuration. That means Claude actively judges whether the CLAUDE.md content is relevant to the current task, and may skip it if it judges otherwise. GitHub issue #18660 makes this explicit in community discussion: "Claude acknowledges the rules exist, but task completion takes priority over process compliance."
This is not a problem you can solve by writing more rules.
The more critical issue is uniform instruction degradation: according to HumanLayer's analysis and multiple community developers' observations, an LLM's reliable instruction-following upper limit is around 150-200 instructions (a community estimate, not official data). Claude Code's own system prompt already occupies roughly 50 slots, leaving only 100-150 slots available for CLAUDE.md. Past that threshold, degradation is uniformly distributed — every low-value rule added dilutes the compliance probability of every high-value rule equally.
Important note: The "200 line limit" is community consensus (validated by HumanLayer and multiple high-vote Reddit discussions), not an official Anthropic hard limit. There's no hard cutoff where 201 lines causes collapse, but the degradation trend is real, and Anthropic also recommends keeping within 200 lines.
Token cost context (for developers paying for the Claude API): CLAUDE.md consumes roughly 500-800 tokens per 100 lines, loaded in full at every session start, not incrementally. A 100-line CLAUDE.md on Claude Sonnet 4.6 adds roughly $0.0003-$0.0006 per session. Not a lot, but if your automation agents run dozens of times daily, it accumulates. Worth noting: Claude Opus 4.7, released in April 2026, uses a new tokenizer that can produce up to 35% more tokens for the same input text. While the API unit price remains unchanged ($5/$25 per MTok), actual costs may increase.
Decision point: When you encounter ignored instructions, ask yourself: is this a delivery layer problem, or a rule quality problem?
A quick diagnostic: paste that rule directly into the first message of your session (not through CLAUDE.md, manually type it). If Claude follows it now, it's a delivery layer problem — consider upgrading to hooks or --append-system-prompt. If Claude still ignores it, the rule itself needs to be written more specifically.
Three Tiers: "Accumulation" Not "Override" — The Right Way to Use global/project/local
Many people assume project CLAUDE.md "overrides" global CLAUDE.md, like CSS specificity. That's wrong.
All three tiers are read and their content accumulates:
| Tier | Path | What to put here | Git commit? |
|---|---|---|---|
| Global (personal) | ~/.claude/CLAUDE.md | Personal preferences, cross-project tool habits | No |
| Project (team) | ./CLAUDE.md or ./.claude/CLAUDE.md | Architecture decisions, code standards, build/test commands | Yes |
| Local (personal override) | CLAUDE.local.md | Personal preferences for this project (deprecated, official docs recommend @imports instead) | No (add to .gitignore) |
| Managed Policy | /Library/Application Support/ClaudeCode/CLAUDE.md (macOS) | Enterprise compliance enforcement | Managed by IT |
A few common pitfalls:
Subdirectory CLAUDE.md files are lazy-loaded. On startup, Claude Code only fully loads CLAUDE.md files in the working directory and its ancestor directories. CLAUDE.md files in subdirectories are loaded on demand when Claude's tools actually access that subdirectory. If you put important rules in a subdirectory CLAUDE.md, Claude genuinely may not see them initially.
HTML comments don't consume tokens: If you want to leave human-readable maintenance notes in CLAUDE.md, use <!-- maintenance note: this rule was added because of X --> block-level comments. Claude Code automatically strips these before loading, so they don't consume your instruction budget.
CLAUDE.md Essential Structure: From Minimum Viable to Full Template
Claude Code's /init command analyzes your codebase and auto-generates a CLAUDE.md with tech stack, build commands, and existing conventions. It's a good starting point, but the generated content is often packed with things "Claude would know anyway."
What CLAUDE.md actually needs is implicit knowledge Claude can't derive from the code.
Essential section structure (ordered by scan efficiency — headers + bullet points are far faster to process than prose):
- WHAT: One sentence describing the project, tech stack (language, framework, primary tools)
- HOW: Specific build/test/deploy commands (
npm run dev,npm test, etc.) — don't make Claude guess - Code Style: Your most important code preferences, must be specific and executable ("functions max 30 lines, split if longer" — not "write clean code")
- Gotchas: Landmines and non-obvious design decisions Claude can't see from the code ("don't modify the
src/generated/directory — it's auto-generated by Prisma")
Minimum viable template for indie makers (the first step after /init):
- Tech stack + core commands: Framework version, start/test/deploy commands
- Your single most important code preference: Pick the one you care most about, write it specifically, include a counterexample
- One real Gotcha: Something you stepped on last week or last month — don't let Claude repeat it
Start with these three things. Don't try to plan out a perfect future in CLAUDE.md.
Ready-to-copy minimum viable template:
# [Your Project Name]
## Tech Stack
Next.js 15 + TypeScript + PostgreSQL + Prisma
## Commands
- Dev: `npm run dev`
- Test: `npm test`
- Build: `npm run build`
## Code Standards
- Use function declarations for components, not arrow function exports
- All API routes must do input validation with zod
## Gotchas
- The `src/generated/` directory is auto-generated by Prisma — don't edit manually
- Environment variables live in `.env.local` — never commit to git
Replace the content with your project details and you have a valid starting point.
Advanced modularization (only consider when a single CLAUDE.md exceeds 300 lines): Keep the main file lean, use @imports or .claude/rules/ for layered structure. Files under .claude/rules/ are loaded on demand when Claude accesses the corresponding directory (e.g., frontend.md triggers when Claude reads src/components/). Side projects don't need this layering — it's complexity only worth maintaining for multi-person teams or multi-agent scenarios.
settings.json vs CLAUDE.md: Two Systems, Two Types of Enforcement
These two are commonly confused, but their responsibilities are completely different:
settings.json = Firewall (technical enforcement, bypasses LLM)
- Executed directly by the Claude Code client, Claude's judgment can't intervene
- For: security controls (
permissions.denyblacklist), sandbox configuration, env var injection
CLAUDE.md = Employee Handbook (behavioral guidance, through LLM judgment)
- Delivered as text context, shapes Claude's behavior
- For: architectural context, code style standards, workflow explanations, non-obvious Gotchas
Decision flow:
- Need to absolutely block an action (e.g., forbid
rm -rf, prevent direct prod DB modifications) →settings.json permissions.deny - Need to inject API keys or environment variables →
settings.json env - Need Claude to understand and follow a working style → CLAUDE.md
One sentence: settings.json protects the system, CLAUDE.md educates Claude.
Rules vs Hooks: Division of Responsibility, Not Either/Or
Reddit user u/DevMoses (536 pts) nailed the observation: "I stopped adding rules to CLAUDE.md and started building infrastructure." His case: rules grew from 45 lines to 190 lines, but compliance actually decreased.
The reason: he was putting "mechanical rules" into a "behavioral guidance" system.
What hooks are for: Physical enforcement (shell execution, bypasses LLM judgment). For objectively determinable rules: format checking, test coverage, specific command interception. Hooks now have three types: command (directly runs shell script), prompt (LLM evaluation, note: still depends on LLM, not 100% reliable), and the newly added mcp_tool (April 2026, directly calls a tool on an already-connected MCP server, e.g., auto-posting to Slack when a task completes). 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.
Major hooks updates in April-May 2026:
- Conditional
iffield (v2.1.85+): Uses permission rule syntax to precisely filter when a hook fires.matcherselects the tool name,ifnarrows to specific invocations, e.g.,Bash(git *)matches only git commands,Write(src/**/test_*.py)matches only test file writes PostToolUseoutput replacement (v2.1.121+): Replace any tool's output viahookSpecificOutput.updatedToolOutputPreCompacthook (v2.1.105+): Fires before context compaction; exit code 2 blocks compressionPermissionDeniedhook (v2.1.89+): Fires after auto mode classifier denials; return{retry: true}to retryduration_msfield (v2.1.110+):PostToolUseandPostToolUseFailurenow include tool execution time for performance monitoring
Three-step routing decision:
- Can Linter/CI do it? → Give it to the Linter, don't burn instruction budget
- Objectively determinable, no context needed? →
hooks command(shell enforcement) - Needs LLM to understand architectural intent or business logic? → CLAUDE.md
Minimum working hooks configuration example (in settings.json's hooks field):
{
"hooks": {
"PreToolUse": [
{
"matcher": "Bash",
"hooks": [
{
"type": "command",
"command": "npm run lint 2>&1 | head -20"
}
]
}
]
}
}
This example runs a lint check before every Bash command Claude executes. When lint fails, it returns a non-zero exit code and Claude stops to fix the issue before retrying.
Advanced example: conditional hook + MCP tool notification (v2.1.85+):
{
"hooks": {
"PreToolUse": [
{
"matcher": "Bash",
"if": "Bash(rm *)",
"hooks": [
{
"type": "command",
"command": "echo 'File deletion blocked' >&2 && exit 2"
}
]
}
],
"Stop": [
{
"hooks": [
{
"type": "mcp_tool",
"server": "slack",
"tool": "send_message",
"input": { "channel": "#dev", "text": "Claude finished the task" }
}
]
}
]
}
}
The first hook uses the if condition to only intercept delete operations (not all Bash commands). The second uses mcp_tool to auto-send a Slack notification when the task ends.
Techniques for making rules more respected without hooks (alternatives if you're not comfortable with shell scripts):
- Be specific, include counterexamples: Instead of "write clean functions," say "functions over 30 lines must be split (❌ don't keep stuffing logic into existing functions, ✅ extract to a separate function and update callers)"
- Flag consequences: Add "when this rule is violated, stop and ask me rather than deciding on your own" to important rules
- Trim to only what matters: Fewer rules written specifically beats many rules written vaguely
Hooks caveat:
commandhooks have shell environment dependencies (PATH, env vars), so in cron scheduling or remote execution scenarios they may fail due to different environments. On the positive side, unrecognized hook event names no longer invalidate the entire settings file (fixed in v2.1.89+), but sticking to officially documented event names is still recommended.
Multi-agent Fleet Design: A Real-World Look at Shareuhack's 8-Agent System
We run this kind of system ourselves, so we can share first-hand design insights.
Shareuhack's 8 autonomous agents (CEO/Researcher/Scout/Writer/Reviewer/Developer/Auditor/Data Analyst) share a project CLAUDE.md as a "constitution." This constitution defines the hard rules every agent must follow (no fabrication, internal link format, frontmatter standards, etc.) and the information architecture of the entire system.
Actual directory structure:
project CLAUDE.md ← shared rules for all agents (constitution)
.claude/skills/ ← each agent's skill definitions (individual SKILL.md)
agents/memory/ ← per-agent operational memory (individual learnings, no cross-contamination)
agents/system-state.yaml ← system state (maintained by CEO)
Technical backing from Anthropic Docs: Project CLAUDE.md is shared via git, giving all subagents their base context. Each subagent can maintain its own Auto Memory without contaminating the main agent's memory. Since v2.1.117, forked subagents can be enabled on external builds with CLAUDE_CODE_FORK_SUBAGENT=1, and named subagents support @ mention autocomplete.
Agent Teams: Multi-session collaboration beyond subagents (experimental, launched February 2026):
When your scenario requires multiple agents working in parallel and communicating with each other, Agent Teams offer a more advanced option than subagents. The core difference: subagents run within a single session and can only report results back to the main agent. Agent Teams members each have their own independent context window (1M tokens each), communicating directly via a mailbox system and shared task list without routing through the team lead.
To enable: set CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS=1 in settings.json or environment variables (requires v2.1.32+). In my testing, Agent Teams work well for large tasks requiring cross-domain coordination (e.g., frontend and backend agents syncing API contracts), but for solo developers, subagents remain the more practical starting point.
Special considerations for zero-HITL scenarios: In unmonitored cron-scheduled scenarios, the risk of ignored instructions is higher. Key techniques:
--append-system-promptparameter: elevates instructions to system prompt level, significantly increasing enforcement strength. Note: this parameter must be passed on every invocation, suitable for CI/CD or cron scripts. CLI flags can change between versions, verify against the latest official docs before use- hooks are more reliable than CLAUDE.md rules (hooks are mechanically executed, don't depend on LLM judgment)
- v2.1.120 added
claude ultrareview [target]for non-interactive comprehensive code review from CI/scripts
Configuration recommendations by scale:
| Scale | Recommended setup |
|---|---|
| Solo developer | project CLAUDE.md (under 300 lines) + 1-2 subagent skills + /recap for session memory |
| Small team | project CLAUDE.md (git-shared) + .claude/rules/ module categories + /ultrareview for code review |
| Multi-agent fleet | Constitution layering + skills directory + per-agent memory + Agent Teams (experimental) |
An 8-agent fleet isn't what every developer needs. The key principle is scaling proportionally, a solo developer can start with a project CLAUDE.md under 300 lines and 1 subagent skill. The concept of a subagent skill is simple: create a .md file in .claude/skills/ defining a frequently repeated task (e.g., "code review" or "draft blog post") and Claude will automatically load that guidance when executing the task. One skill gives you the same architectural benefits without copying the entire fleet. v2.1.121 also added a type-to-filter search box in /skills, making it easy to find what you need even with a long list.
Useful new slash commands from April 2026:
/recap: Get a quick summary of what you were doing when returning to a session after a break, no need to re-read the entire conversation/ultrareview [target]: Comprehensive parallel multi-agent code review via cloud/usage: Merged the old/costand/statsinto a single view for token usage and costs/effort: Interactive slider to adjust reasoning depth; Claude Opus 4.7 supports a newxhighlevel
Multi-tool note: If you use Cursor, Zed, or other AI tools alongside Claude Code, they use AGENTS.md (the cross-tool standard). Claude Code doesn't read AGENTS.md by default, but you can reference it in your CLAUDE.md with @AGENTS.md, then append Claude-specific settings.
Avoiding Over-Engineering: The Right Architecture Matches Your Scale
Back to the opening question: Claude Code's author uses a "surprisingly vanilla" setup, with just three core components: past errors + conventions + rules.
There's a well-known Hacker News case: someone went from a 10,000-line semantic memory system back to 1,500 lines of CLAUDE.md + bash scripts, and got a 10x speed improvement. The costs: uniform instruction degradation, exploding token consumption, conflicting rules.
Three signals that suggest simplification:
- CLAUDE.md exceeds 300 lines (single file)
- Claude starts frequently ignoring rules you know you've written
- You can't remember whether a given rule is still working
Simplification process:
- Review each rule: "What specific mistake would Claude make without this line?" If you can't answer, delete it
- Return static checks (formatting, lint) to your Linter or hooks, freeing instruction budget
- Split overly long CLAUDE.md into
@importsor.claude/rules/for on-demand loading
Practical limit for side projects: A single CLAUDE.md under 300 lines is completely sufficient. .claude/rules/ layering is complexity worth maintaining only for multi-person collaboration or multi-agent scenarios.
Conclusion
CLAUDE.md is "the highest leverage point for educating Claude" — HumanLayer's words, and I fully agree. But the highest leverage point is also the easiest place to waste effort on low-quality rules.
A rule worth keeping must be "implicit knowledge Claude can't derive from the code and context." Everything else: give it to the Linter, give it to hooks, or delete it entirely.
If you're using Claude Code (as of May 2026, latest version v2.1.126), here's my recommended starting point:
- Use
/initto generate your base CLAUDE.md - Filter out half the content using "would Claude make a mistake without this line?"
- Add the Gotchas you've actually stepped on
- Identify which rules should be promoted to hooks, and use the conditional
iffield for precise trigger control - When managing multi-session memory, use
/recapto quickly recover context
Start with these five steps, and let your CLAUDE.md grow organically from there. As features like Agent Teams, mcp_tool hooks, and /ultrareview continue to mature, CLAUDE.md's role will increasingly focus on "implicit knowledge only humans have," with mechanical rules handled by hooks and subagents. This is a trend worth watching in the second half of 2026.
What does your CLAUDE.md look like right now? What mistakes have you made? Share in the comments.
FAQ
Is the CLAUDE.md generated by /init good enough? How do I improve it?
/init scans your codebase and auto-generates a CLAUDE.md with tech stack, build commands, and existing conventions — a solid starting point. The problem is it tends to include a lot of 'obvious common sense' that Claude would know anyway. The recommended improvement strategy: aggressively delete sections Claude would figure out on its own, keep only implicit knowledge and Gotchas that aren't visible in the code. Then adopt an 'organic growth' approach — whenever Claude makes a wrong assumption, immediately tell it 'add this to my CLAUDE.md' and let the document reflect real mistakes, not hypothetical rules.
Does the # key shortcut for updating CLAUDE.md still exist?
It was officially removed in Claude Code v2.0.70. The standard approach now is to tell Claude directly in natural language: 'add this to my CLAUDE.md', or use the /memory command to edit inline. The recommended habit is 'organic growth' — update immediately when you discover issues in a session, rather than doing periodic batch cleanup.



