DEV Community

Docat
Docat

Posted on

5 Patterns That Make Claude Code Actually Follow Your Rules (2026)

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:

  1. Primacy/recency bias. Instructions at the very beginning and very end of the context get more attention. Everything in the middle fades.
  2. 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.
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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.
Enter fullscreen mode Exit fullscreen mode

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"
      }
    ]
  }
}
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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)