← All posts
BLOG · GUIDE

CLAUDE.md best practices (and where they quietly fail)

June 15, 2026 · 9 min read

CLAUDE.md is the file your coding agent reads before it touches your repo. It's where you tell Claude Code (or Cursor, via .cursorrules) how this project works. Write it well and CLAUDE.md becomes one of the most useful files in your codebase: it turns a generic model into one that writes code that looks like yours. This guide covers the practices that actually help, then the part most posts skip — where a context file quietly fails, and what to pair it with.

The good practices come first, because they are genuinely worth doing. The honest caveat comes after, because pretending a Markdown file enforces anything is how teams get surprised when it doesn't.

What is CLAUDE.md, and what is it for?

CLAUDE.md is a plain-Markdown file in your project root (or in a subfolder) that the agent loads at the start of a session. It is not config in any runnable sense — it's instructions, written for a reader who happens to be a model. Cursor calls its version .cursorrules or rule files under .cursor/rules; the format differs but the goal is the same. (We compare the two in Cursor rules vs MCP.)

The file's job is to close the gap between what the model assumes and what your project actually does. Without it, the agent reaches for the most common pattern it has seen. With it, you point the agent at your conventions before it writes a line.

Best practice 1: keep it short and specific

The most common mistake is a CLAUDE.md that reads like a company wiki — paragraphs of philosophy, values, and “we strive to write clean code.” The agent has to read all of it, and vague guidance produces vague behavior.

Every line should be something the agent can act on. If a sentence wouldn't change a single decision the agent makes, cut it. Forty specific lines beat four hundred soft ones.

Best practice 2: state conventions as rules, with examples

Don't describe your conventions — command them. Use plain imperative phrasing and back each rule with a one-line example so there is no room to guess. “We tend to use a repository layer” is a hint; “All database access goes through a repository class, never the ORM directly” is a rule. Here's the shape that works:

# Conventions

- Data access: go through a repository class in `src/repos/`.
  Never call the ORM directly from a route handler.
  Example: `UserRepo.findById(id)`, not `db.user.findUnique(...)`.

- Errors: throw `AppError` with a code; do not return `null` on failure.
  Example: `throw new AppError("NOT_FOUND", ...)`.

- HTTP handlers: validate input with a zod schema at the top of the
  handler before any logic. See `src/api/users/create.ts`.

Notice each rule has three parts: the convention, the thing to avoid, and a concrete example or file to copy. That triple is what makes a rule clear to a model that is pattern-matching, not reasoning from scratch.

Best practice 3: document the architecture and the “why”

Rules tell the agent what; the “why” stops it from cleverly working around them. Say “all timestamps are stored in UTC” with no reason, and an agent refactoring date logic may decide local time is “more user-friendly” and undo the decision.

Write down the key architecture decisions and the reason behind each: why you chose this boundary, what breaks if it's crossed, what you tried that didn't work. You don't need an essay — one line of reason per decision is enough to stop an agent from confidently undoing it.

A simple test: for every “don't do X” rule, ask whether a new contributor reading it would understand why not. If they wouldn't, the agent won't either, and it will eventually talk itself past the rule.

Best practice 4: point to exemplar files, and keep it current

The single best thing you can put in CLAUDE.md is a pointer to a file that already does it right. “New endpoints should follow the structure of src/api/users/create.ts” hands the agent a complete, working template to copy — far more reliable than prose describing the same thing.

Then the boring part: keep the file current. A stale CLAUDE.md is worse than no file at all, because the agent follows the wrong rule with full confidence. When you change a convention, change the file in the same commit. When you delete the file it points to, update the pointer. Treat it as code, not docs.

A weak CLAUDE.md
  • Long, vague, full of values and philosophy.
  • "We try to write clean, maintainable code."
  • Describes conventions as suggestions.
  • No reasons, so the agent overrides them.
  • Last updated months ago; some rules are wrong.
A strong CLAUDE.md
  • Short, specific, every line actionable.
  • "All DB access goes through a repository class."
  • States conventions as rules, with examples.
  • One line of reason per decision.
  • Updated in the same commit as the code.

Where CLAUDE.md best practices quietly fail

Here's the honest part. You can follow every practice above and still watch your codebase drift, because of one structural fact: CLAUDE.md is a suggestion, not enforcement. It's text in a prompt, weighed against everything else the model is juggling. The agent doesn't always honor it, and — this is the part that bites — nothing checks whether it did.

A CLAUDE.md says “use the repository pattern.” It cannot make the agent use the repository pattern.

That gap widens in three ways:

This is drift — behavior that slowly deviates because the guideline and the real code were never connected by anything that checks them. We dig into how this happens in keeping an AI codebase consistent. A context file is necessary, but it is not enough.

The complement: an in-loop check plus a drift scan

The fix isn't to drop CLAUDE.md — it's to give it teeth. Two pieces close the loop it can't close on its own.

1. Surface the rules where the agent will honor them

Instead of hoping the rules survive in context, have the agent re-read them at the moment it writes. An MCP server can expose your declared conventions as a tool the agent calls mid-task. VibeDrift's free, local, open-source MCP server does exactly this — install it in one line:

claude mcp add vibedrift -- npx -y @vibedrift/cli mcp

Its get_intent_hints tool reads the rules you declared in CLAUDE.md or .cursorrules and hands them to the agent on demand, so they stay in front of it instead of fading. And because text can't describe everything, sibling tools report what the codebase actually does: get_dominant_pattern (the repo's real convention for error handling, data access, auth), find_similar_function (so the agent reuses instead of reinventing), check_file_drift, and validate_change (would this edit introduce drift?). The tools run on your machine; your code never leaves it. Full setup is in the MCP guide.

2. Scan for the drift that slips through

Even with hints in the loop, some inconsistency gets in — from hand-edits, from other tools, from before you adopted the practice. A periodic scan catches it. The local scanner is one command and runs in about two seconds:

npx @vibedrift/cli .

It returns a Vibe Drift Score (0–100) and a grade, so “is the codebase still consistent with what we declared?” becomes a number you can track over time and gate in CI, instead of a thing you hope is true. Local scans are free and open source.

VibeDrift diagnoses; VibeLang prevents. If you want rules that genuinely can't erode, VibeLang is a sister language where intent is compiler-enforced — the strongest version of “a rule that can't be ignored.” A CLAUDE.md rule is a request; a compiler error is not.

The takeaway

Write the CLAUDE.md anyway, and write it well: short, specific, rules with examples, the architecture and the why, pointers to exemplars, kept current. It genuinely makes your agent better. Just keep the right expectation — it's the statement of intent, not the enforcement of it. Pair it with an in-loop check that reads the real codebase and a scan that catches drift, and the rules you wrote down become the rules your code actually follows.

Add the MCP server with the one-liner above, or just run the scanner on your repo to see where you stand:

npx @vibedrift/cli .

Frequently asked questions

What is CLAUDE.md?

CLAUDE.md is a plain-Markdown file in your repo that Claude Code (and similar agents) read for project context before working. It's where you declare conventions, architecture decisions, and constraints so the agent writes code that fits your project instead of generic defaults. Cursor has the same idea under .cursorrules or .cursor/rules.

What are the best practices for writing a CLAUDE.md?

Keep it short and specific. State conventions as imperative rules with a one-line example. Document the architecture decisions and the reasons behind them, not just the what. Point to exemplar files the agent can copy from. And keep it current — a stale CLAUDE.md is worse than none, because the agent will follow the wrong rule confidently.

Why doesn't the agent always follow CLAUDE.md?

Because CLAUDE.md is a suggestion, not enforcement. It's text in the prompt that competes with everything else the agent is weighing, and across long sessions and multiple contributors it gets diluted, contradicted, or ignored. Nothing reads the actual codebase to verify the agent honored it, so drift accumulates silently.

How do I make CLAUDE.md rules actually stick?

Pair the file with an in-loop check that reads the real codebase. VibeDrift's free, local MCP server exposes a get_intent_hints tool that surfaces the rules you declared in CLAUDE.md or .cursorrules so the agent honors them mid-task, plus tools that report the repo's actual dominant patterns. A periodic scan then catches the drift that slips through.


Local scans and the MCP tools are free and open source, forever. The free tier includes 1 deep scan a month; Pro is $15/mo for 12, and you can top up 5 more for $10 on any plan. Credits never expire.

Website · MCP guide · npm