Home / Articles / A Practical Playbook for Writing an Effective CLAUDE.md File

This article is published in English.

A Practical Playbook for Writing an Effective CLAUDE.md File

Learn 21 concrete, checkable rules for trimming a bloated CLAUDE.md file so Claude Code stays reliable, predictable, and easy to trust in long sessions.

3938 words

Last month, a developer trimmed 340 lines out of a CLAUDE.md file that had been growing for a year.

The file had expanded steadily. Every time Claude Code did something irritating, a new rule got added. Every time a rule failed to stick, a longer version got stacked underneath it. By August the file sat at 400 lines, and Claude's behavior was noticeably worse than when the file had been a lean 60 lines.

After cutting it down to 61 lines, the improvement showed up the same day.

This isn't really a lesson about personal discipline. It's a lesson about what a rules file is for. It's not a wish list you build up over time. It's a set of instructions the model reads at the start of every session, and each additional line has to compete for attention with everything else already in there.

What follows are the 21 rules that made it through the cut, along with the reasoning behind each one.

The Real Cost of a Bloated CLAUDE.md

In August 2026, someone in the Claude Code community decided to test something that seems obvious but nobody had actually verified: whether Claude really follows the CLAUDE.md instructions it's given.

An initial pass found that 55.7% of the rules in a typical file were even checkable in principle. A manual review then dropped that number to 18%, then to 8.75%, and it eventually settled at 6.67%.

Sit with that number for a second. In a typical CLAUDE.md, only about one rule out of fifteen can actually be verified. The remaining fourteen are essentially vibes: "write clean code," "follow best practices," "be careful with performance." No one, not the model and not you, can determine whether these were actually followed.

That's the real cost of a bloated file. It isn't just that unverifiable rules get ignored. It's that they still occupy space in the context window on every single turn, crowding out the rules that could have actually mattered.

Around the same time, Anthropic's own engineers made a related observation about their system prompts: beyond a certain length, adding more instructions degrades performance instead of improving it. Their newest models now ship with system prompts that are a fraction of the size they used to be.

Your CLAUDE.md file follows the exact same pattern. The 21 rules below are designed to stay on the productive side of that curve.

Rules 1–7: Stop the Damage

These first rules exist to prevent Claude from turning a simple task into a disaster.

Rule 1: Make surgical edits only

## Editing
Change the minimum number of lines needed.
Do not reformat, reorder, or rename anything you were not asked to change.
Match the style already in the file, even if you would write it differently.

Why it works: Without this constraint, Claude tends to "improve" every file it touches. You request a one-line fix and end up reviewing a 200-line diff with your actual fix buried somewhere inside. This is probably the most common complaint about coding agents, and also one of the easiest to solve.

Before: You ask for a fix to an off-by-one error inside a callback. Instead, the code gets converted to async/await, three variables get renamed, and the original bug is still there.

After: A single line changes. Reviewing it takes about four seconds.

Rule 2: Never rewrite my tests

## Tests
Do not edit existing tests to make failing code pass.
If a test fails, fix the code.
If you believe the test itself is wrong, say so and stop. Do not edit it.

Why it works: A model instructed to make tests pass will always take the shortest route available, and rewriting an assertion is shorter than actually fixing the underlying bug. This rule removes that shortcut entirely.

Before: Three tests turn green. Two of them are now asserting something incorrect.

After: Claude reports that a test expects 404 while the code returns 500, then asks which one is actually wrong.

Rule 3: Do not add a dependency

## Dependencies
Do not add packages. Use what is already in package.json.
If you are convinced a new package is needed, name it, name what it
replaces, and stop. Wait for approval.

Why it works: Every coding agent reaches for a new library the same way a junior developer might. Left unchecked, you end up with three separate date-handling packages and a bundle size nobody can explain.

Before: A simple four-line date formatting task turns into a new dependency plus a lockfile change.

After: The same four lines, built using the Intl API that was already available.

Rule 4: No error handling for things that cannot happen

## Error Handling
Handle errors that can actually occur here.
Do not add try/catch around code that cannot throw.
Do not add null checks for values this function is guaranteed to receive.

Why it works: Defensive code written to guard against impossible states isn't actually safety, it's clutter. It buries the two checks that genuinely matter and doubles the length of a function for no benefit.

Before: A 12-line function padded with four guard clauses, three of which can never be triggered.

After: The same 12-line function, keeping only the one check that could realistically fail.

Rule 5: Do not touch what you were not asked to touch

## Scope
Work only on what was asked.
Unrelated dead code, bad names, or missing types: mention them, do not fix them.
Remove imports and variables that YOUR change made unused. Nothing else.

Why it works: Scope creep hidden inside a diff stays invisible until someone reviews it, and by then it burns real time. Spelling out the boundary up front removes the guesswork about what counts as fair game.

Rule 6: Never commit secrets

## Security
Never write a key, token, password, or connection string into a file.
Never commit .env, .env.*, or any credentials file.
If a value is needed, reference the environment variable by name.

Why it works: This is one of the rare cases where a single slip is unrecoverable. The instruction is short, unconditional, and easy to verify, which is exactly the shape a good rule should take.

Rule 7: Ask before anything destructive

## Destructive Actions
Stop and ask before: dropping a table, deleting a branch, force pushing,
rewriting history, deleting a file you did not create, or running a
migration against anything that is not local.

Why it works: A model has no built-in sense of what can and cannot be undone. From its perspective, force-pushing over history and formatting a text file are the same kind of action: just another tool call. This rule hands it a category of risk it would otherwise have no way to recognize on its own.

Rules 8-14: Write Rules It Can Actually Follow

This is the section that addresses the underlying problem behind that low compliance number. These rules aren't about behavior directly, they're about how to phrase the rules that govern behavior.

Rule 8: Every rule must be checkable

Bad:  Write clean, maintainable code.
Good: Functions over 40 lines must be split.

Why it works: If you can't glance at the output and answer yes or no, the rule isn't doing anything besides taking up space in context. Before adding a line to this file, ask yourself what evidence would prove it had been violated. If you can't answer that, don't add the rule.

Before: An instruction like "write clean, maintainable code" sits unused in your file for months. It never once influences an output, and you can never point to a case where it was broken.

After: A 61-line function appears in a diff, and you can point directly at the rule that it violates. From there, either the rule gets respected or it gets removed. Either outcome moves things forward.

Rule 9: One rule, one line

Bad:  When you are working on components, please try to keep them
      focused and reasonably small, and generally avoid mixing data
      fetching with presentation where that makes sense.
Good: Components do not fetch data. Fetch in the route, pass props down.

Why it works: A rule buried in hedging language reads like a soft suggestion. Suggestions lose out every time to whatever the model was already inclined to do.

Rule 10: Name the file, not the feeling

Bad:  Follow our API conventions.
Good: New routes follow the shape in src/api/users/route.ts.

Why it works: A phrase like "our conventions" only means something to you, the human. A file path is something the model can actually open and read. Pointing to real, existing code beats any amount of prose describing that code.

Rule 11: Forbid instead of encourage

Bad:  Prefer simple solutions.
Good: Do not add an interface with one implementation.
      Do not add a config option for a value that never changes.

Why it works: Words like "prefer" only kick in as a tiebreaker, and only when the model is already uncertain. "Do not" functions as a hard stop instead. Nearly every rule that fails in real use fails because it was framed as encouragement rather than prohibition.

There's a simple test for this: read the rule and ask whether a model determined to do the thing you're trying to prevent could still technically follow the rule as written. If yes, what you've written is a preference, not a rule.

Rule 12: Put the rule where the work happens

Core rules live in the root CLAUDE.md, not only in path-scoped rule files.

Why it works: This one is easy to miss and can cause a real bug if you do. In August 2026, an issue was filed against Claude Code describing how path-scoped rule files can silently fail to load when the agent modifies files via shell commands rather than its built-in edit tool, since rule injection is tied to that edit pathway. Other users reported the same failure for rules kept in nested subdirectory files.

The lesson holds regardless of whether that particular bug gets patched. Anything you truly cannot afford to have skipped needs to live in the root file that always gets loaded, not tucked away in a conditional file that only sometimes does.

Rule 13: Cap the length of the file

CLAUDE.md stays under 60 lines. If you need line 61, delete something first.

Why it works: This is the rule that most improved one team's actual setup, and it runs against intuition. Stretching the file to 400 lines does not translate into 400 rules the model can act on. It just produces a dense block of text where the critical instructions blend into the filler.

Sixty lines is not some magic threshold. What matters is the constraint itself: adding a new rule should cost you an old one, so only the rules worth keeping stay in.

Rule 14: Keep rules, skills, and workflows in separate places

CLAUDE.md      : rules that apply to every single task
.claude/skills : reference material, read only when relevant
.claude/commands : fixed step sequences, invoked by name

Why it works: Most oversized rules files got that way because they're actually three different kinds of documents stuffed into one. A description of your database schema is not a rule. Your deployment sequence is not a rule either. Once you relocate that material, the rules that remain become visible again instead of getting buried.

Rules 15 through 21: Making Behavior Last Through a Long Session

A rule that the model follows on turn three but forgets by turn forty was never really a rule. This set of guidelines is about making instructions stick for the duration of a session.

Rule 15: Keep rules in the file, not just in conversation

Any instruction that must hold for the whole project belongs in this file.
Instructions given in conversation apply to the current task only.

Why it works: Long sessions get compacted at some point. When that compression happens, the details of the conversation get summarized away while files get reloaded in full. One account from August 2026 illustrates this exactly: a user told the model in turn two never to bump the package version, compaction occurred partway through, and by turn forty the version had been bumped anyway. Nothing crashed or threw an error — the instruction had simply ceased to exist in the model's working context.

If you catch yourself restating the same instruction in chat more than once, treat that as a signal. It belongs in the file, not in your typing.

Rule 16: Reload the rules file after compaction

After any context compaction, re-read CLAUDE.md before the next edit.

Why it works: It's a cheap safeguard against exactly the failure described in Rule 15, and it's one of the few rules where you can directly confirm compliance just by scanning the transcript.

Rule 17: Specify the precise command used to verify the work

## Verification
Before saying a task is done, run:
  npm run typecheck && npm test -- --run
Paste the final line of output. If it fails, fix it. Do not report success.

Why it works: An instruction like "make sure the tests pass" gives the model nothing concrete to execute. A literal shell command does, and requiring the pasted output means the claim of success can be checked at a glance instead of taken on faith.

Rule 18: Spell out what "done" actually means

## Done
A task is done when: the change is made, typecheck passes, tests pass,
and you have stated in one sentence what changed and why.
Not done: "this should work", "you may want to verify".

Why it works: Left undefined, the model will supply its own definition of done, and that definition is usually just "I generated some text." This single rule does more than any other to cut down on the number of times you discover, an hour later, that the build is actually broken.

Rule 19: Limit feedback to a single actionable change

When something did not work, name ONE thing to change and why.
Do not list five options.

Why it works: Offering five different options when something fails is really a way of dodging a decision. It also makes it impossible to track what actually fixed the problem, since you can't isolate which of the five suggestions mattered.

Rule 20: Ask rather than guess

If you need information you do not have, output:
MISSING: <exactly what you need>
and stop. Do not assume a plausible value and continue.

Why it works: This might be the single most valuable line in the entire file. Nearly every serious incident with an agent traces back to it filling in a missing detail with confidence instead of pausing to ask. A refusal costs you thirty seconds. A confidently wrong assumption costs an afternoon, and you usually don't notice until several commits later.

Before: The model needs a queue name you never specified. It defaults to something like default, builds an integration that looks correct, and the jobs pile up in a queue nothing is consuming. You find out days later.

After: It outputs MISSING: the queue name for the retry consumer. You supply the answer in five seconds, and the resulting code is correct from the start.

There's a simple way to test whether this rule is actually active: ask for something that depends on information you've deliberately withheld. If the model answers anyway instead of flagging the gap, the rule exists only on paper.

Rule 21: Keep Pruning, One Rule a Month

Once a month, remove any rule you have not seen violated recently.

Why it works: Rule files tend to expand endlessly, since adding a new one feels like progress while removing one feels like a gamble. But if a rule hasn't come into play in the past couple of months, it's either no longer needed or was never actually being followed. Either way, it's draining attention on every single interaction. Cutting it is the cheapest performance gain you'll find.

Five Rules That Got Cut

The trimming mattered more than anything that got added, so here are five entries that used to live in a 400-line file and are missing from the current 61-line version. If any of these sound familiar, you can probably remove them tonight.

"Think through the problem step by step before coding." This is already the default behavior. Current versions of Claude Code plan out their approach before touching files, with no prompting needed. This line was a holdover from older habits, and all it did was take up space.

"Watch out for performance issues." This fails the checkability test outright — careful relative to what baseline? It got swapped for two specific, testable rules about database access, and those actually catch real problems.

A 90-line writeup of the database schema. That's documentation, not a rule. It belongs in a skill file that gets pulled in when the model is doing database-related work, not in the file it reads before every task, including something as trivial as a CSS tweak. Pulling this section out was the single largest reduction.

"Never use any in TypeScript." This one wasn't wrong, but it was redundant — the linter already blocks it. Anything the toolchain already enforces doesn't need to occupy space in the rules file. If a violation can be caught in CI, let CI be the one to catch it.

"Add helpful comments." Every attempt at phrasing this produced comments that just repeated the line of code above them. The fix was to flip it: don't explain what the code does, only explain why it does it. That version is both more effective and a line shorter.

The pattern is consistent across all five. Two duplicated something the model or the tooling already handled on its own. Two couldn't be verified in any concrete way. One was reference material dressed up as a rule. Look for these same four categories in your own file, and the candidates for deletion will surface quickly.

The Full File, Ready to Use

# CLAUDE.md
## Stack
Next.js 15 App Router, TypeScript strict, Postgres via Drizzle, Vitest.## Editing
Change the minimum number of lines needed.
Do not reformat, reorder, or rename anything you were not asked to change.
Match the style already in the file.## Scope
Work only on what was asked.
Mention unrelated problems, do not fix them.
Remove imports your change made unused. Nothing else.## Abstractions
Do not add an interface with one implementation.
Do not add a config option for a value that never changes.
Functions over 40 lines must be split.## Tests
Do not edit existing tests to make failing code pass.
If a test is wrong, say so and stop.## Dependencies
Do not add packages. Use what is in package.json.
To add one: name it, name what it replaces, stop, wait.## Error Handling
Handle errors that can actually occur here.
No try/catch around code that cannot throw.## Patterns
New routes follow src/api/users/route.ts.
Components do not fetch data. Fetch in the route, pass props down.
Database access goes through src/db/queries/. Never inline SQL.## Security
Never write a key, token, password, or connection string into a file.
Never commit .env or .env.*.
Reference environment variables by name only.## Destructive Actions
Stop and ask before: dropping a table, deleting a branch, force pushing,
rewriting history, deleting a file you did not create, running a
migration against anything not local.## Verification
Before reporting done, run:
  npm run typecheck && npm test -- --run
Paste the final line. If it fails, fix it. Do not report success.## Done
Done means: change made, typecheck passes, tests pass, and one sentence
saying what changed and why.## When Stuck
If you need information you do not have, output:
MISSING: <what you need>
and stop. Do not assume a value and continue.## Reporting
Name ONE thing to change. Not five options.## Persistence
Rules live here, not in chat. After compaction, re-read this file.

That's the entire file — sixty-one lines.

What Changed

After trimming the file from 400 lines down to 61:

  • File rewrites stopped. The surgical-edit rule existed in the bloated version too. It only started being respected once it wasn't buried around line 213.
  • The MISSING: rule became active. It now triggers roughly twice a week, pausing to ask rather than fabricating a config value. Previously, both of those situations would have produced silent, incorrect output.
  • Long sessions stopped drifting. The version-bump issue, along with three comparable problems, disappeared once the rules were anchored in the file instead of scattered across earlier chat messages.
  • Reviews got quicker, simply because diffs got smaller. That's the entire mechanism — nothing more sophisticated than that.

There's no tidy before-and-after benchmark to offer here, and none will be manufactured for the sake of a clean story. What exists instead is a file that takes a minute to read, paired with behavior that actually lines up with what it says.

Next Steps

  1. Open your existing CLAUDE.md and count the lines.
  2. Go through it once, flagging every rule where you couldn't point to a concrete violation if one occurred. Remove those.
  3. Convert every "prefer" and "try to" into a hard "do not."
  4. Swap out any reference to "our conventions" for an actual file path.
  5. If you don't have anything resembling Rule 20, add it. It's the one rule that justifies doing this whole exercise.

After that, leave the file untouched for a month. When you return to it, find one more thing to delete.

The rules that actually hold up share the same qualities: short, absolute, and checkable. Everything else is just a note to yourself that the model ends up rereading hundreds of times a day for no benefit.