Claude Code loaded your CLAUDE.md. Why isn't it following it?
Two failures look identical from the prompt. In the first, the file never reached the model: wrong directory, shadowed by another instruction file, skipped by a setting, or loaded on demand and never triggered. In the second, the file reached the model and the model did something else. The first is a loading problem. This page is about the second.
The fixes are different. More emphatic wording will not fix a file that never loaded. A different file location will not fix a rule the model read and then lost to a conflict, a long context, or a vague instruction.
Run claude --version if you are comparing your session with a report; the exact wrapper and limits move between releases.
Checked against Claude Code, Codex, OpenCode, Gemini CLI, and Qwen Code documentation on 27 October 2026.
Status, 27 October 2026: the memory page says Claude treats CLAUDE.md as context, not enforced configuration, with no guarantee of strict compliance. A May 2026 report documented the text arriving inside a system reminder that plays down its relevance, while an inner header says to follow the instructions exactly (#56760). It was closed as not planned and later locked, so treat the exact wrapper as version-specific.
First, did it load?#
Open a session and run /context. Under Memory files you should see the CLAUDE.md and CLAUDE.local.md files that loaded at launch. If the file is not there, the model cannot follow it.
| What you see | What it means | Where to go |
|---|---|---|
| The file is missing from Memory files | It never loaded | Why your nested CLAUDE.md never loaded |
| The file is there, but the rule is ignored | It loaded; something else won | This page |
| It works in the main session, not in a subagent | The subagent (a separate agent the main session starts for a scoped job) started without it | The subagent note below |
| It worked earlier, then stopped | The session may be using an older copy, or a nested file has not reloaded | The stale-copy and compaction notes below |
For a log, register an InstructionsLoaded hook. It fires when a CLAUDE.md or .claude/rules/*.md file loads, at session start or during the session, and reports a reason such as session_start, nested_traversal, path_glob_match, include, or compact. That is the check for "when did this load, and why".
A file can also be loaded and still not be the copy you edited. Project-root and user-level CLAUDE.md files are read at session start and held in memory. A mid-session edit does not change the copy the model is using; it waits for the next /clear, /compact, or restart. If you changed the file five minutes ago and the behavior did not change, rule this out first.
If the rule is in a nested file#
A subdirectory CLAUDE.md and a path-scoped rule both load on demand, when Claude reads, writes, or edits a file in the right place. If that never happens, the rule never reaches the model. The nested CLAUDE.md guide covers the trigger; the short version is to open a file in that subdirectory with Read, or put the rule where it loads at launch.
A project-root CLAUDE.md over 4 MiB is skipped entirely. A subdirectory file or a path-scoped rule has a smaller per-file limit; over it, the start is delivered with a note to read the rest. If the rule is at the bottom, check wc -m first.
What "loaded" actually means#
Claude Code's memory page says:
> Claude treats them as context, not enforced configuration. To block an action regardless of what Claude decides, use a PreToolUse hook instead.
The troubleshooting section is even more specific:
> CLAUDE.md content is delivered as a user message after the system prompt, not as part of the system prompt itself. Claude reads it and tries to follow it, but there's no guarantee of strict compliance, especially for vague or conflicting instructions.
That is the mechanism: the file is text after the system prompt, not a rule engine. The model can read a line and still not act on it.
The May 2026 report makes the same point from the other direction: the content was wrapped in a reminder that says the context may not matter, inside a header that says to follow it (#56760). That matches the documented delivery: context competes with everything else.
This is why "the model is ignoring me" is usually the wrong frame. It may be following a later instruction, a built-in behavior, or its own reading, and a permission mode may allow what your file warns against.
Why long files and vague rules lose#
The docs give three reasons adherence drops:
Length. The target is under 200 lines per CLAUDE.md. Longer files consume more context and reduce adherence. Imported files do not help: an import loads with the file that imports it, so it does not reduce the context cost. A long file is not more authoritative; it is more competition.
Conflict. If two instructions contradict each other, Claude may pick one arbitrarily. That can be a user-level file and a project file, two project files, a CLAUDE.md and a rule, or a CLAUDE.md and Claude Code's built-in guidance. Review the whole set periodically. On v2.1.283 or later, run /doctor prompt-audit to find outdated or conflicting instructions; on older versions, review the files by hand.
Vagueness. The docs contrast "Format code properly" with "Use 2-space indentation", "Test your changes" with "Run npm test before committing", and "Keep files organized" with "API handlers live in src/api/handlers/". A rule that names the action, the command, or the path is easier to follow and easier to check.
Claude Code also adds guidance of its own. If your file sets commit or pull-request rules, the built-in instructions may say something different. includeGitInstructions can turn the built-in ones off. "The file is loaded" does not mean "the file is alone".
When the rule must hold every time#
Some rules are boundaries. Use the mechanism the client enforces, not the one that asks the model nicely.
| What you need | Use | What it gives you |
|---|---|---|
| Never run a command or touch a path | Permission deny rules, plus the sandbox, which isolates commands at the OS level | Claude Code blocks the call before it runs; the model cannot argue past it |
| Run a check before or after a tool call | PreToolUse or PostToolUse hook | A shell command at a fixed lifecycle point, regardless of what the model decides |
| Org-wide policy | Managed settings, including managed permission rules | Settings the user and project cannot override |
| Stable working style | CLAUDE.md or a path-scoped rule | Guidance; no guarantee |
The permission docs are explicit about the split:
> Permission rules are enforced by Claude Code, not by the model. Instructions in your prompt or CLAUDE.md shape what Claude tries to do, but they don't change what Claude Code allows.
A permissions.deny rule for Bash(git push *), a sandbox, or a managed policy is a boundary. A line in CLAUDE.md is a request.
Hooks are the second boundary, with a caveat. A PreToolUse hook can block a tool call, and the docs say hooks run at fixed lifecycle events "regardless of what Claude decides to do". But matching is best-effort for shell patterns, so use permissions for a hard allow or deny.
The --append-system-prompt flag is a third option. The docs recommend it "for instructions you want at the system prompt level". Stronger than a user message, but still an instruction, not enforcement; use it for a stable style or automation, not a security boundary.
No wording guarantees obedience. A shorter file, a clearer rule, and a system-prompt position improve the odds, but do not make a model a policy engine. If the rule cannot fail, use the enforced layer.
If it is only failing in one place#
In a subagent. The built-in Explore and Plan agents start without your CLAUDE.md files, and a custom subagent can set omitClaudeMd (subagent docs). Check its definition and context; the parent's did not come with it.
After /compact. A project-root CLAUDE.md survives: Claude Code re-reads it from disk and re-injects it. Nested files and path-scoped rules load again on demand. If a rule disappeared, it was probably conversation-only or in a nested file that has not reloaded.
Only in one directory. The hierarchy changes with the directory where the session started: files above it load at launch, files below it on demand.
Only when a particular tool runs. That is usually a hook or permission question. A PostToolUse hook is a check; a deny rule is a boundary.
Codex, briefly#
Codex has the same shape. It reads AGENTS.md files before doing any work, builds one chain from the global file through the project root to your current directory, and concatenates them. Files closer to your current directory appear later, and the docs say they "override earlier guidance because they appear later". That is positional, not a judgment about importance.
The check is the same split. codex debug prompt-input shows the model-visible prompt. If the rule is there, the problem is conflict, position, or vagueness; if not, the Codex AGENTS.md guide covers the chain and truncation. For a command that must not run, use approval and sandbox settings; the approval guide covers that layer.
OpenCode, briefly#
OpenCode has two lines with different instruction models. V1 loads global and project AGENTS.md and falls back to CLAUDE.md when no AGENTS.md exists. V2 loads the global file, then project ancestors, then configured instructions, and recognizes AGENTS.md only; its instructions page says it combines files without resolving conflicts. A rule can load and still lose to another file.
The OpenCode AGENTS.md guide shows how to prove what loaded. For a rule that must hold, permissions are the enforced layer; the permission guide covers the ordered rules and the V1/V2 field differences.
Gemini CLI, briefly#
Run gemini --version before you compare a session; this section describes v0.65.0. Gemini CLI has the same two failures, and a different check. /memory list prints the paths of the context files in use; /memory show prints their concatenated text. If the rule is in GEMINI.md and it appears in /memory show, the file loaded. If it is absent, the Gemini AGENTS.md guide covers the global, workspace, and just-in-time load order. A nested file that no tool has touched is not in /memory show yet.
Status, 27 October 2026: an open report says non-trivial GEMINI.md instructions are ignored while a trivial instruction usually works (#13852, open, updated 24 September 2026). A closed report describes a repository file saying never commit and the model following what it called its global instructions instead (#15037, closed as not planned 15 March 2026). Both describe the second failure: the file was there, and the model chose something else.
Gemini CLI's documentation calls these files instructional context, which is the same split. The file competes with the built-in system prompt, the other context files, and the conversation. A long file dilutes the lines that matter, and when two context files conflict the prompt documents a precedence: subdirectory files outrank the workspace root, which outranks extensions and the global file. The compaction guide explains why a rule loaded at the start can fade after a long session.
When the rule must hold, use the layer Gemini CLI enforces.
A policy deny rule. Put a TOML file in ~/.gemini/policies/, not .gemini/policies/: the policy page says the workspace tier is currently non-functional (#18186, open). A rule can match the tool and the command:
[[rule]]
toolName = "run_shell_command"
commandPrefix = "git commit"
decision = "deny"
priority = 100
denyMessage = "Commit only when the user asks."/policies list shows the active rules. A user policy outranks the session approval the dialog writes, so a dialog choice cannot override it. A deny rule without an argument pattern also removes the tool from the model's view, which is stronger than a prompt line; keep the pattern when you only want to block some commands.
A BeforeTool hook. BeforeTool fires before a tool call. The matcher is a regex on the tool name, so run_shell_command covers the shell tool and write_.* covers the tools whose names start with write_. Return a JSON object on stdout with a deny decision and a reason, and exit 0:
{"decision": "deny", "reason": "Do not commit; the user reviews first."}/hooks panel shows that the hook loaded; have the hook write a line to a log to prove it ran. If the folder is untrusted, hooks from the settings files are skipped. The Gemini CLI hooks guide covers the event names, exit codes, and the folder-trust gate.
If the rule is about a tool call, the policy engine is the first place to put it; the permissions guide covers the dialog and the other layers. The Gemini CLI guides cover the rest.
Qwen Code, briefly#
The first check is /context detail: it names each loaded context file under Memory files and gives its token cost, while /memory opens a memory panel that manages the QWEN.md files and auto-memory but is not a complete list of attached context files. Run qwen --version before you compare a session; this section describes the command line at v0.26.2 on 27 October 2026.
Qwen Code has both failures. It loads QWEN.md and AGENTS.md by default, plus .qwen/QWEN.local.md at the repository root. If the file is in the /context detail list, it loaded. If it is not, check where you started Qwen: discovery walks up from the working directory to the nearest .git entry and never down, so a nested packages/api/QWEN.md is not loaded from the repository root (#6101, open). context.fileName also replaces the default list, so setting it to ["AGENTS.md"] drops QWEN.md (the source).
The mechanism is the same as Claude Code's, with Qwen's order. assembleSystemPrompt builds the base system prompt, then the context files, then the append prompt, then auto-memory (the source). The context files are text attached to the system prompt, not a policy layer. Qwen's built-in tool guidance can still outweigh a prose ban. An open report documents a global QWEN.md saying not to use subagents for simple tasks; the model spawned the built-in Explore agent because the built-in prompt recommends it for broad exploration (#7679, open on 27 October 2026). The file loaded; the rule lost.
For a hard rule, use the layer Qwen enforces. A permissions.deny rule in settings.json blocks the call before it runs, and deny beats ask and allow. The tool names are Claude-like: Bash(git push *) blocks the shell command, and Edit covers edit, write and notebook edit. Qwen also applies Read, Edit, and WebFetch deny rules to equivalent shell commands, so cat.env cannot bypass a Read(./.env) deny (settings). A PreToolUse hook can return hookSpecificOutput.permissionDecision: "deny" with a reason; that is code, not a prompt line (hooks). There is no separate policy file to write, as there is in Gemini CLI. For review-only work, plan mode restricts the session to read-only tools; it is a mode, not a sandbox.
A subagent starts from the parent's loaded context text: Qwen passes getUserMemory() into its system prompt (the source). A custom agent can still narrow its tool list, and a fork inherits the parent conversation while a named subagent starts from a separate one. "It worked in the main session but not in the subagent" is a definition question before it is an adherence question.
After /compress, re-anchor. The summary is generated text; a rule that was only in the conversation can be summarized away. QWEN.md and AGENTS.md are part of the system prompt, not the conversation, so the summary does not replace them. Qwen's SessionStart hook has a compact source, so a handoff file can be put back after a compaction. The compaction guide has the snippet and the rest of the Qwen compression mechanics.
The Qwen Code guides cover instruction loading and permissions in more detail.
Where to go next#
- Claude Code guides — memory, sessions, subagents, permissions, hooks.
- Why your nested CLAUDE.md never loaded — when the file is missing, not ignored.
- Claude Code hooks that don't fire — when the rule must run.
- Why Claude Code keeps asking for permission — when a rule must block.
- Qwen Code guides — instruction loading, permissions, MCP, sessions.
- Do AGENTS.md files actually help? and how long a CLAUDE.md can be — what the file is worth, and the point where it stops loading in full.