DEV Community

Cover image for Why Claude Code ignores CLAUDE.md, and what sticks.
Manpreet Singh
Manpreet Singh

Posted on Originally published at singhlabs.dev AI-assisted

Why Claude Code ignores CLAUDE.md, and what sticks.

Short answer: CLAUDE.md is a request, not a lock. Claude Code loads it as context and tries to follow it, and Anthropic's docs say plainly there's no guarantee. When I went through my own history, most of the rules I'd have blamed Claude for ignoring were never written down, or were written for something else. The few that truly must hold need a hook, not a better sentence.

Search "claude code ignores claude.md" and page one is GitHub issues. Rules in capitals. MANDATORY. NEVER. On anthropics/claude-code, 124 issues have CLAUDE.md and "ignore" in the title. Eight are open. 68 were closed as not planned.

Plenty of complaints, no answers. So I opened my own case file: my Claude Code history since July, every project's CLAUDE.md, and the git logs behind them.

A rule in CLAUDE.md is a request. If it must never break, it needs a hook, not a louder sentence.

First, check it read the file

Rule out the boring cause before blaming the model. The docs say Claude treats CLAUDE.md "as context, not enforced configuration", and that it arrives as a user message after the system prompt. So first, confirm it arrived:

  • Run /context and look under Memory files. Not listed means not seen.

  • A CLAUDE.md in a subfolder isn't listed at launch. It loads when Claude reads a file in that folder.

  • Loading has bugs too. #99032, filed last week: the VS Code extension skips an @import that points outside the project, while the terminal loads it.

Loaded and still ignored? Then it's one of the next four.

1. The rule isn't there

This one's embarrassing. toldya reads what you've typed to Claude Code and finds the corrections you keep repeating. Mine:

$ npx toldya --all --dry

toldya · 175 sessions (2 Jul – 9 Oct) · 3804 of your messages · 328 corrections

You keep telling your AI:
   1.  20×  keep it simple   (20 sessions)
   2.   8×  dont assume   (7 sessions)
   3.   8×  I don't like it   (7 sessions)
Enter fullscreen mode Exit fullscreen mode

toldya also flags a repeat that's already in your CLAUDE.md or AGENTS.md, with ← already in your rules, still repeated. I ran it in all 12 of my projects that have one of those files. It flagged nothing.

"Keep it simple" wasn't in the CLAUDE.md of any project where I kept typing it. Claude wasn't ignoring that rule. I'd never given it one.

One correction, found while writing this. When you resume a session, Claude Code copies the earlier messages into the new file, and toldya 0.3.2 counted every copy: it said 44. The fix shipped in 0.3.3, which made the run above. Still my top line.

2. The rule is for something else

Except I sort of had. Since 26 July I've run ponytail, a plugin whose session-start hook loads about 900 words of "build the simplest thing that works" into every session. Its text is in 187 of my 195 transcripts.

So I took toldya's two simplicity repeats ("keep it simple", "dont complex this"), dropped the copies, and kept the messages I typed with that text already loaded. There were 24. I read all of them:

  • 17 were about how it talked or wrote, not what it built. "Sorry, I didn't understand what you did. Keep it simple and explainable."

  • 5 were about the approach, closer to the plugin's turf.

  • 2 I couldn't place.

Ponytail says, in its own text, that it "governs what you build, not how you talk." It was loaded every time. It just wasn't the rule I kept asking for.

3. The rule is a wish

So when I started a new data project this week, its CLAUDE.md had the right rule from the first hour: "Explain simply." Within a day I'd asked for a simple explanation five more times. "I need to understand in very simple way how to use that app."

"Explain simply" is a wish. Nothing in it can be checked. The docs make the same point with better examples: "Use 2-space indentation", not "Format code properly". A checkable version of mine would name the thing: a line limit, an example first, no term left undefined. I haven't tested that yet, so I'm not promising it.

4. The rule is clear, loaded, quoted back, and broken anyway

The hard case. Another repo of mine opens its CLAUDE.md with a logging rule, under a heading that says non-negotiable: every change gets a CHANGELOG entry, timestamped from date -u, "never guessed or invented". Specific. Checkable. Line 40 of a 222-line file when it went in; the file is 311 lines now.

$ git log --format="%ad  %s" --date=short -S "Timestamps are UTC and real" -- CLAUDE.md
2026-08-16  Repo audit, project rules, and the documents needed to run this
$ git log --reverse --format="%ad  %s" --date=short -i -E --grep="(correct|fix).*timestamp"
2026-08-17  Correct a changelog timestamp I invented
2026-08-24  Correct a changelog timestamp that was written before date -u was read
2026-08-29  Fix a guessed timestamp, and write down how to stop guessing them
2026-09-09  Correct a guessed timestamp, for the third time
$ wc -l CLAUDE.md
311 CLAUDE.md
Enter fullscreen mode Exit fullscreen mode

Four guessed timestamps in the 24 days after the rule went in, each caught and fixed in its own commit. Claude wrote those fixes, and every one names the rule it had just broken. With the third fix the rule got sharper: read the clock in its own command, then write. Eleven days later it broke again. The fourth fix is titled "for the third time". Even the apology lost count.

That's four caught misses in about 150 commits that touched the log, so the rule mostly held. Mostly is fine for indentation. It's useless for a timestamp whose only job is to be right. Since 9 Sep there have been 44 more log commits and no fix, which means either the sharper wording landed or nobody checked. The history can't say which.

Why rules slip: the docs and the issues

My four cases line up with Anthropic's memory docs, its best practices, and the issue tracker:

  • Where it sits. CLAUDE.md arrives after the system prompt, as a user message. When it clashes with Claude Code's own guidance, the built-in can win. In #27032, plan mode suggested a plans folder in the home directory, and the model followed it over a CLAUDE.md rule to keep plans in the repo. The docs list this among the things to check.

  • Length. Target under 200 lines; longer files "reduce adherence". The best-practices page is blunter: "Bloated CLAUDE.md files cause Claude to ignore your actual instructions!" My logging rule lived in a file that grew from 222 lines to 311. What each line costs is in the length post.

  • Conflicts. If two instructions contradict each other, "Claude may pick one arbitrarily". Check your user file against your project file and any nested ones.

  • Shouting. The docs suggest "IMPORTANT" on the one line that keeps getting skipped, and warn that if you emphasise many, none stands out. #33603 is what happens next: a rule restated and strengthened after each violation, then broken in each of the next three sessions.

  • The model. #99704 counted a "reply in Korean" rule over one long session: no English replies on claude-opus-5, 33% English on claude-opus-5-5, same CLI. A rule that held last month proves nothing about this model.

  • Timing. If something must happen at a fixed point, before every commit or after every edit, the docs say to write it as a hook.

When a rule should be a hook

The best-practices page puts it in one line: CLAUDE.md instructions are "advisory", while hooks "are deterministic and guarantee the action happens". A PreToolUse hook sees the tool call before it runs, and can refuse it.

Here's slopguard's Bash guard, run from its plugin folder, fed the call Claude would make to commit a .env:

$ echo '{"tool_name":"Bash","tool_input":{"command":"git add .env && git commit -m wip"}}' \
  | node scripts/guard-bash.mjs \
  | node -p "JSON.parse(require('fs').readFileSync(0)).hookSpecificOutput.permissionDecisionReason"
SLOPGUARD blocked this command — [SG-1] credential file staged for commit.

fix: Add it to .gitignore. Anything committed is in the history permanently, even after a later delete.

Rule text lives in AGENTS.md.
Enter fullscreen mode Exit fullscreen mode

The sentence version of that rule is #2142, open since June 2025: Claude Code "repeatedly ignores CLAUDE.md security guidelines and exposes API keys to version control". A hook doesn't give it the chance.

Two limits:

  • A hook only enforces what a script can check. In #99642, hooks that checked the form (a table exists, the logs were read) were satisfied while the work they stood for was skipped.

  • A hook that only adds text is still a request. Ponytail's hook prints its rules at session start, and the hooks guide says that output just joins Claude's context. Same odds as CLAUDE.md. #99642's reminder hook injected its instruction on every turn, and the model never acted on it.

So the test is: could a script say yes or no? A .env in a commit: yes, hook it. A log timestamp that doesn't match the clock: yes, and that's the hook my logging rule should have been. I haven't written it yet. "Explain simply": no. That one stays a sentence, as concrete as I can make it, and gets counted.

Count whether it stuck

A rule you never re-check is a rule you're hoping about. toldya does the counting, on your machine, sending nothing:

$ npx toldya --dry    # the report only, changes nothing
Enter fullscreen mode Exit fullscreen mode

Run it without --dry and it asks about each repeat: y writes it into CLAUDE.md, n skips it, e lets you reword it first. A week later, run it again. Each rule it added gets a line like "Keep it simple." said 20× before · 0× since. If "since" isn't near zero, the rule is a wish, or it needs a hook.

Honest status: I can't show you a real "since" yet, because I never added my repeats through toldya. That line is from a test run a minute after adding one, so its zero means nothing. The ponytail count above is the same check done by hand, with toldya's matcher.


This is how we build. In the agents we build for businesses, a must-never is a check in code, not a line in a prompt. The prompt gets the style. The code gets the rules that can't bend.

Sources: every terminal block is a real run on my machine on 9 Oct 2026; the toldya report (0.3.3) is trimmed to its first three lines. Copies were found by matching each message's timestamp and text, and the 24 messages were read and sorted by hand. The git log is from one of my own repos. The slopguard run feeds its hook script the JSON a tool call sends. Docs: Claude Code's memory, best practices and hooks guide. Issues are on anthropics/claude-code, read through the GitHub API the same day; the 124 is a search for CLAUDE.md and "ignore" in issue titles.

Where this fits: memory and context, layer 2 of the Agent Ops Stack.

Read next: How long should CLAUDE.md be? I priced every line. · The best CLAUDE.md rules are hiding in your chat history.


Originally published at singhlabs.dev.

Top comments (0)