You wrote 150 lines of rules in your CLAUDE.md file. Every line exists because Claude did something wrong and you swore it would never happen again.
Then Claude does it again.
You are not alone. GitHub issues, Reddit threads, and blog posts are full of developers hitting the same wall: Claude Code reads your instructions, acknowledges them, and then quietly ignores them when generating code. It is the single most frustrating part of AI-assisted development.
The good news: this is a solvable problem. After months of daily Claude Code usage and a lot of trial and error, I found 5 patterns that dramatically improve instruction compliance. None of them require special prompts or hacks — just a better understanding of how large language models process instructions.
Why Claude Ignores Your Rules in the First Place
Before the fixes, you need to understand the root cause. Large language models do not "remember" your instructions the way a human would. Every time Claude responds, it reads the entire conversation — system prompt, CLAUDE.md, your messages, its own previous replies — as one long text document.
Two things happen as that document grows:
- Primacy/recency bias. Instructions at the very beginning and very end of the context get more attention. Everything in the middle fades.
- Cognitive load. Research shows frontier models reliably follow about 150-200 discrete instructions. Claude Code's own system prompt uses roughly 50 of those slots. That leaves you 100-150 slots for your rules.
If your CLAUDE.md has 200 lines of detailed instructions, you have already blown past the budget. Claude is not being stubborn — it is overloaded.
Pattern 1: The 30-Line Rule
Before: A 200-line CLAUDE.md covering every edge case you have ever encountered.
After: A 30-line CLAUDE.md covering only the things Claude cannot infer from your code.
# Project: acme-dashboard
Next.js 14 app with Tailwind, Prisma (PostgreSQL), NextAuth.
Deploy target: Vercel.
## Commands
- Dev: `pnpm dev`
- Test: `pnpm vitest run`
- Lint: `pnpm biome check --write .`
- DB migrate: `pnpm prisma migrate dev`
## Code Style
- camelCase variables, PascalCase components, UPPER_SNAKE_CASE constants
- kebab-case file names
- Pure functions preferred. No classes unless wrapping a third-party SDK.
- All API routes return `{ data, error }` shape.
- Never use `any`. If the type is unknown, use `unknown` and narrow.
## Conventions
- Tests go in `__tests__/` next to the source file.
- Every PR needs at least one test for the changed behavior.
- Error messages must include the function name: `[functionName] what went wrong`
- No default exports. Named exports only.
That is 25 lines. For each line, apply this test: "If I remove this, will Claude make a mistake?" If the answer is no, delete it.
Why this works: fewer instructions means each one gets more attention weight. A focused 30-line file outperforms a comprehensive 200-line file every time.
Pattern 2: Positive Instructions Over Negative Ones
This is the single highest-leverage change most people miss.
Language models struggle with negation. When you write "Do NOT use semicolons," the model has to process the concept of semicolons and then apply a negation to it. The concept itself gets activated either way.
Before (negative):
- Do NOT use default exports
- Do NOT use `any` type
- Do NOT put tests in a separate `tests/` folder
- Never use console.log in production code
- Don't use relative imports from parent directories
After (positive):
- Use named exports exclusively
- Type everything explicitly; use `unknown` and narrow when unsure
- Place tests in `__tests__/` next to the source file
- Use the logger utility (`src/lib/logger.ts`) for all logging
- Use path aliases (`@/`) for all imports
Each rule now tells Claude what TO do instead of what to avoid. The model does not need to resolve a negation — it just follows the positive instruction directly.
In my testing, flipping 10 negative rules to positive equivalents cut rule violations by roughly half.
Pattern 3: Anchor Critical Rules at the Top and Bottom
Remember the primacy/recency bias? Use it deliberately.
Structure your CLAUDE.md so that the rules Claude violates most often are at the very top (first 5 lines) and the very bottom (last 5 lines). Put the less critical rules in the middle.
# CRITICAL — Read these first
- Named exports only. No default exports anywhere.
- Every function must have explicit return types.
- Run `pnpm vitest run` before considering any task complete.
# Project context
Next.js 14, Tailwind, Prisma, PostgreSQL, Vercel.
# Commands
...
# Code style
...
# CRITICAL — Read these last
- Named exports only. No default exports anywhere.
- Every function must have explicit return types.
- Run `pnpm vitest run` before considering any task complete.
Yes, you are duplicating 3 rules. That is intentional. The rules that Claude violates most often deserve two placement slots — one at the beginning where primacy bias is strongest, and one at the end where recency bias kicks in.
This feels redundant, but it works. The most important rules get double the attention weight.
Pattern 4: Use Hooks for Hard Enforcement
Here is the uncomfortable truth: prompt-level instructions are suggestions. No matter how you phrase them, there is always a probability that Claude will skip a rule. If a rule absolutely must be followed every time, do not rely on the CLAUDE.md — enforce it with code.
Claude Code supports hooks that run shell commands at specific lifecycle points. For example, you can block any commit that contains console.log:
// .claude/settings.json
{
"hooks": {
"PreCommit": [
{
"command": "grep -r 'console\\.log' src/ && echo 'ERROR: Remove console.log before committing' && exit 1 || exit 0"
}
],
"PostWrite": [
{
"command": "pnpm biome check --write $CLAUDE_FILE_PATH"
}
]
}
}
The PostWrite hook runs your formatter every time Claude writes a file. The PreCommit hook blocks commits that violate your rules. Claude cannot skip these — they are enforced by the system, not by the prompt.
Rule of thumb: If you have told Claude not to do something 3 times and it keeps doing it, move that rule from CLAUDE.md to a hook. Prompt instructions are for preferences. Hooks are for requirements.
Pattern 5: Scope Rules to Subdirectories
Most people put everything in the root CLAUDE.md. But Claude Code actually supports CLAUDE.md files at multiple levels:
~/.claude/CLAUDE.md # Global (all projects)
project/CLAUDE.md # Project-wide
project/src/CLAUDE.md # Only for src/ files
project/src/api/CLAUDE.md # Only for API route files
When Claude works on a file in src/api/, it loads all four files. When it works on a root config file, it only loads the first two.
This is powerful because it lets you keep each file short while still being specific:
# project/src/api/CLAUDE.md
API route rules:
- Always validate request body with zod schema before processing
- Return { data: T } on success, { error: string } on failure
- Log every request: logger.info(`[${method}] ${path}`, { userId })
- Rate limit: use `rateLimit()` middleware on all public endpoints
These 4 rules only matter for API routes. Putting them in the root CLAUDE.md would add noise for every other file Claude touches. Scoping them to src/api/ keeps the root file lean and gives Claude precise, relevant instructions exactly when they apply.
Putting It All Together
Here is the checklist:
| Pattern | Action | Time to Implement |
|---|---|---|
| 30-Line Rule | Audit your CLAUDE.md. Delete anything Claude can infer. | 15 minutes |
| Positive Instructions | Rewrite every "don't" as a "do" | 10 minutes |
| Anchor Critical Rules | Move your top 3 violated rules to line 1 and the last line | 5 minutes |
| Hooks | Move hard requirements to PreCommit/PostWrite hooks | 20 minutes |
| Subdirectory Scoping | Split domain-specific rules into scoped CLAUDE.md files | 15 minutes |
Total time: about an hour. The payoff is immediate — fewer corrections, less frustration, and a coding agent that actually does what you tell it.
The Bigger Lesson
The instinct when Claude ignores a rule is to add more rules. Longer explanations, more examples, bolder formatting. But the problem is almost never that Claude did not understand your rule — it is that your rule got lost in a sea of other rules.
Less rules, better structured, enforced by code where it matters. That is the entire strategy.
If this helped, follow @docat0209 — I write weekly about AI-assisted development and developer tools.
Top comments (0)