Why Claude Code ignores your CLAUDE.md (and how to fix it)
Originally published at getlockstep.dev . Your CLAUDE.md says "Never commit directly to main." Claude Code commits directly to main. You add the rule again in capital letters. You add "IMPORTANT" in front of it. Two days later it happens again, and now you wonder whether Claude reads the file at al

Posted on Nov 5 • Originally published at getlockstep.dev
Originally published at getlockstep.dev.
Your CLAUDE.md says "Never commit directly to main." Claude Code commits directly to main.
You add the rule again in capital letters. You add "IMPORTANT" in front of it. Two days later it happens again, and now you wonder whether Claude reads the file at all.
It usually does. The problem is what Claude Code does with that file, and it has specific, checkable causes. This guide walks through each one, using Anthropic's own memory documentation and compaction table, checked on 4 November 2026.
Claude Code ignores CLAUDE.md instructions because the file is context, not configuration. It arrives as a user message after the system prompt, and Anthropic's documentation says there is no guarantee of strict compliance, especially for vague or conflicting instructions.
Within that limit, an ignored instruction almost always has one of seven causes:
Each cause has a different check. Start at the top, because the first one is the fastest to rule out.
Ignored CLAUDE.md instructions are one of the most reported problems in the Claude Code issue tracker. A few examples:
Comment counts as of 4 November 2026. Two of the five are about compaction, which is cause 2 below.
Claude can't follow a file it never received. Run /context and look under Memory files. If your CLAUDE.md isn't listed, nothing you write in it matters yet.
When a long session compacts, Claude Code summarizes the conversation to free space. Some memory comes back from disk. Some doesn't.
The fix depends on the row. If a rule must hold for the whole session, move it to the project-root CLAUDE.md or remove its paths field. If you gave the instruction in chat, it was never memory: write it into CLAUDE.md.
For context that must come back after every compaction, Claude Code supports a SessionStart hook with a compact matcher. Whatever the command prints is added to Claude's context after compaction:
{ "hooks": { "SessionStart": [ { "matcher": "compact", "hooks": [ { "type": "command", "command": "cat.claude/after-compact.md" } ] } ] } } Enter fullscreen mode Exit fullscreen mode Keep that file short. It is a reminder, not a second CLAUDE.md.
A long CLAUDE.md is followed less reliably than a short one. Anthropic recommends under 200 lines per file, and Claude Code shows a warning at startup and in /status when a file is over that length, or when several files add up past a combined limit.
Splitting the file with @imports does not fix this. Imported files load together with the file that imports them, so the context cost is the same. What does help:
Claude Code concatenates every CLAUDE.md and rules file it loads. Nothing overrides anything. If two instructions conflict, the documentation says Claude may pick one arbitrarily.
Conflicts hide in places you don't look together: your personal ~/.claude/CLAUDE.md, the project file, a nested file in a package, a rule written months ago. "Use npm" in one and "use pnpm" in another produces exactly the inconsistent behavior that feels like being ignored.
Run /doctor prompt-audit (Claude Code v2.1.283 or later). It looks for contradictions, outdated instructions, and references to files or commands that no longer exist, and changes nothing until you approve the edits.
Claude follows instructions it can check. Compare:
Capital letters and "IMPORTANT" are not a substitute for precision. If you can't tell from a diff whether the rule was followed, Claude can't either.
Claude Code adds its own instructions about git commits and pull requests. If your CLAUDE.md sets different commit or PR rules, the two compete.
The documentation's fix is to turn off the built-in git guidance with the includeGitInstructions setting, and to set attribution text with the attribution setting, so your rules are the only ones in play.
CLAUDE.md files in subdirectories and path-scoped rules have a per-file size limit. Past it, Claude receives only the start of the file, with a note to read the rest. Until it does, the later instructions aren't in context.
The limit is 40,000 characters on a 200K context window, and 150,000 to 200,000 characters on a 1M window depending on the model. Check a file with wc -m path/to/CLAUDE.md. If it is over, split it into several rules files, which each count separately.
Some instructions are not preferences. "Never edit applied migrations" or "never touch.env " should not depend on a model's judgment. For those, Claude Code has two enforcement tools that run outside the model:
A small hook that blocks edits to applied migrations:
#!/bin/bash #.claude/hooks/protect-migrations.sh FILE_PATH = $( jq -r '.tool_input.file_path // empty' ) if [[ " $FILE_PATH " == * "db/migrations/" * ]]; then echo "Blocked: applied migrations are read-only. Create a new migration." > &2 exit 2 fi exit 0 Enter fullscreen mode Exit fullscreen mode Make it executable with chmod +x, then register it in.claude/settings.json:
{ "hooks": { "PreToolUse": [ { "matcher": "Edit|Write", "hooks": [ { "type": "command", "command": " \" $CLAUDE_PROJECT_DIR \" /.claude/hooks/protect-migrations.sh" } ] } ] } } Enter fullscreen mode Exit fullscreen mode The script uses jq to read the tool input. Anthropic's hooks guide has a fuller version for protecting several paths.
Keep the line in CLAUDE.md too. The hook stops the action; the instruction tells Claude why, so it plans around the rule instead of running into it.
When Claude Code ignores an instruction, go down this list:
For the full picture of what loads, when, and how much, see how Claude Code memory works.
Some ignored instructions aren't load or wording problems. They are decisions that changed after someone wrote them down.
A CLAUDE.md line says "exports never include the email field." Last week the product lead approved an exception for internal admins in a Slack thread. The file still says never, a teammate's agent follows the file, and the new feature ships without the exception. Nothing was ignored. The file was simply out of date, and nobody owned updating it.
CLAUDE.md has no owner per line, no status, and no record of what replaced what. It works for stable instructions about how a repository works. It does not work well for product and architecture decisions that change, involve people outside the repo, and need to reach every teammate's agent at once.
Lockstep keeps that second kind of instruction. Decisions are captured from PRDs, Slack, and pull requests, and become binding when their owner approves them. Claude Code is briefed on the decisions that apply at the start of each session, and when a decision is replaced, the old version is marked as replaced rather than left in a file to contradict the new one.
It does not make Claude Code obey anything, and it does not replace CLAUDE.md or hooks. Keep repository instructions in CLAUDE.md and hard limits in hooks. Use Lockstep for the decisions your team makes outside the repo. Session briefings ship for Claude Code today. Try it on one repository with npx lockstep-cli onboard.
For every memory file and limit in one place, read how Claude Code memory works. For what to save between sessions, see Claude Code keeps forgetting context?. For what belongs in the file at all, see CLAUDE.md vs agent memory.