Why Claude Code Ignores CLAUDE.md and How Hooks Enforce Invariants
CLAUDE.md is ingested as conversational user context after the system prompt, meaning the model treats instructions as non-binding advice. To reliably block dangerous behavior like leaking credentials, teams must replace markdown rules with deterministic PreToolUse hooks.

Why it matters
Inspect your instruction files with /context and migrate critical constraints to PreToolUse hooks to prevent silent model drift.
TL;DR
- 01CLAUDE.md operates as advisory context, not an immutable system-level configuration.
- 02Keep configuration files under 200 lines to prevent context degradation and skipped rules.
- 03Enforce zero-tolerance requirements like credential checks using deterministic PreToolUse hooks.
Key facts
- Recommended CLAUDE.md size
- < 200 lines
- Reported CLI ignore issues
- 124 GitHub issues
- CLAUDE.md injection position
- User message after system prompt
Context Injection vs. Deterministic Enforcement
Claude Code treats CLAUDE.md as contextual background rather than an enforced contract. The contents arrive as a user turn following the system prompt. Consequently, if project guidance conflicts with built-in model directives (such as directory structures suggested in plan mode), the default behavior often wins. Testing with /context confirms whether memory files are loaded, but inclusion does not guarantee execution.
Size Thresholds and Adherence Degradation
Empirical tests show that file size directly correlates with compliance degradation. Project files exceeding 200 lines exhibit lower instruction adherence. Furthermore, vague directives like "keep it simple" provide zero verifiable bounds. Shouting in all caps or stacking warnings after violations fails over multi-session horizons: empirical commit audits revealed repeated failures to format timestamps properly despite explicit rules added across iterations.
Intercepting Execution via PreToolUse Hooks
Rules that must never fail require hooks rather than prompt phrasing. A PreToolUse hook intercepts CLI tool calls before execution and evaluates arguments deterministically. For instance, using guard tooling like slopguard blocks commands matching staged .env files and instructs the agent to update .gitignore instead.
Try it in 2 minutes
echo '{"tool_name":"Bash","tool_input":{"command":"git add .env && git commit -m wip"}}' | node -p "JSON.parse(require('fs').readFileSync(0)).hookSpecificOutput.permissionDecisionReason"bash
✓ When to use
- Use hooks when committing secret files or API keys must be blocked 100% reliably.
- Use hooks when automated validations like tests or linters must run before every commit attempt.
✕ When NOT to use
- Do not write hooks for subjective tone or general explanation verbosity adjustments.
- Avoid adding heavy blocking scripts for early exploratory prototyping where fast iteration outweighs strict linting.
What to do today
- Run /context in Claude Code to verify which memory files are actively indexed.
- Trim repository CLAUDE.md files to fewer than 200 lines by removing vague stylistic requests.
- Implement a PreToolUse hook script to programmatically intercept and reject forbidden Bash commands.