The Anatomy of a Great CLAUDE.md File (2026 Guide)
Your CLAUDE.md is the highest-leverage file in any Claude Code project. The five rules, a real example dissected, when to split with .claude/rules/, and a linter skill that audits your own file.
Your `CLAUDE.md` is the single highest-leverage file in any project that uses Claude Code. Written well, it makes every session smarter: Claude knows your build commands, respects your conventions, and stops reinventing patterns you already settled on. Written poorly, it is context tax — tokens you pay for on every session that deliver nothing.
Most developers who use Claude Code have never seriously designed their `CLAUDE.md`. They ran `/init`, kept what it generated, and moved on. That works, but it leaves 80% of the value on the table. This article walks through the five rules that separate a useful `CLAUDE.md` from a great one, deconstructs a real one from a live project, shows when to split into `.claude/rules/`, and hands you a bonus skill that audits your own file for common problems.
If you have not yet set up Claude Code at all, start with our Claude Code hub guide for the 30-minute quickstart. This article assumes you already have a working installation.
Why CLAUDE.md is not a system prompt
A common misconception: because `CLAUDE.md` controls Claude's behavior, it must be the system prompt. It is not. `CLAUDE.md` content is delivered as a user message, delivered after the system prompt, at the start of every session. That distinction matters. System prompts are enforced by the model provider. User messages are context — Claude reads them, tries to follow them, but there is no guarantee of strict compliance, especially for vague or conflicting instructions.
The practical consequence: `CLAUDE.md` shapes behavior, it does not enforce it. For real enforcement (blocking dangerous commands, requiring tests before commits), you use hooks or managed `permissions.deny` settings. Both are deterministic. `CLAUDE.md` is not.
This is also why specificity matters so much. If you write 'format code properly', Claude makes its best guess about what you mean. If you write '2-space indentation, single quotes, trailing commas', Claude has nothing to guess about. The stronger your wording, the more consistent the output.
The four scopes — where CLAUDE.md files live
Claude Code walks up the directory tree from your current working directory, concatenating every `CLAUDE.md` and `CLAUDE.local.md` it finds. More specific locations take precedence over broader ones. Understanding the scopes lets you put each rule where it belongs.
CLAUDE.md scopes, from broadest to narrowest
- Managed policy — deployed organization-wide by IT or DevOps via MDM, Group Policy, or Ansible. Location: `/Library/Application Support/ClaudeCode/CLAUDE.md` on macOS, `/etc/claude-code/CLAUDE.md` on Linux, `C:\Program Files\ClaudeCode\CLAUDE.md` on Windows. Cannot be excluded by users.
- User personal at `~/.claude/CLAUDE.md` — your preferences across every project on your machine. Good place for code style defaults, shortcut abbreviations, 'always prefer pnpm over npm.'
- Project team at `./CLAUDE.md` or `./.claude/CLAUDE.md` — committed to git, shared with teammates. This is where your build commands, architecture, and project conventions live.
- Project local at `./CLAUDE.local.md` — gitignored, your per-project personal notes. Sandbox URLs, test credentials, WIP notes. Never commit.
Because all discovered files concatenate rather than override, you can layer them cleanly. Your personal `~/.claude/CLAUDE.md` says 'I prefer concise commit messages'; your project `./CLAUDE.md` says 'use conventional commits format'; both load, both apply, the project one wins on any direct conflict because it comes later in the walk-up order within the project directory.
The five rules of a great CLAUDE.md
After writing dozens of these files and reviewing many more, a pattern emerges. The good ones share five properties. The bad ones break at least one of them.
Rule 1: Under 200 lines
Anthropic's official guidance is clear: target under 200 lines per `CLAUDE.md` file. Longer files consume more context and — counterintuitively — reduce adherence. Claude starts to miss rules buried in the middle of long sections. If your file is over 200 lines, you have two splitting options: use `@path/to/file` imports to pull in referenced files on demand, or move path-specific rules into `.claude/rules/` (covered below).
Rule 2: Specific instead of general
Every sentence in your `CLAUDE.md` should be concrete enough to verify. If you cannot answer 'did Claude follow this?' with yes or no, the rule is too vague.
Rewrites that matter
- 'Format code properly' → 'Use 2-space indentation, single quotes, no trailing semicolons'
- 'Test your changes' → 'Run `npm test` before committing; all tests must pass'
- 'Keep files organized' → 'API handlers live in `src/api/handlers/`. Types in `src/types/`. Utilities in `src/lib/`'
- 'Use modern JavaScript' → 'Target ES2022. No `var`. Prefer `for...of` over `forEach` when mutating. Use optional chaining over manual null checks'
Rule 3: Structure like a human reads
Claude scans `CLAUDE.md` the way humans scan documentation: top-down, looking for section headers, falling into bullet lists. Dense paragraphs get skimmed. Use markdown headers to group related rules. Use bullet lists for enumerations. Keep paragraphs to 2-3 sentences. If a section runs longer than 15 lines, break it into sub-sections with `###` headers.
Rule 4: No contradictions
When two rules contradict each other, Claude picks one arbitrarily. Review your `CLAUDE.md` files — including nested ones in subdirectories and any `.claude/rules/` — periodically, hunting for contradictions. The most common sources: a rule added last year that the team now does differently, a personal `~/.claude/CLAUDE.md` that disagrees with a project `./CLAUDE.md`, two imports that each define the same convention differently.
If you maintain a large project, schedule a quarterly `CLAUDE.md` review the same way you would review dependency versions. Your conventions drift; your instructions should drift with them.
Rule 5: CLAUDE.md is not a hard enforcement layer
This is the rule everyone learns the hard way. Your `CLAUDE.md` says 'never edit production config files directly' and yet one day Claude does exactly that because a chain of reasoning made it seem warranted. This is not a bug. `CLAUDE.md` is guidance, not enforcement.
For rules that must be enforced, use the right tool: `permissions.deny` in managed settings blocks tools at the system level; hooks with `exit 2` block specific commands like `Bash(rm *)` deterministically; managed policy CLAUDE.md files cannot be excluded by individual users, so organization-wide requirements go there, not in project CLAUDE.md. Use `CLAUDE.md` for how things should be done. Use settings and hooks for what cannot happen.
The target structure of a good CLAUDE.md
A strong `CLAUDE.md` follows a predictable shape. Here is the skeleton we recommend starting from, then adapt to your project:
# [Project name]
> [One-sentence description of what this project is]
## Commands
```bash
npm run dev # Dev server
npm run build # Production build
npm run test # Full test suite
npm run lint # Lint + format check
```
## Tech Stack
- **Framework**: Next.js 15 (App Router)
- **Styling**: Tailwind 4
- **Database**: PostgreSQL via Prisma
- **Hosting**: Vercel
## Architecture
- Routes in `src/app/`
- API handlers in `src/app/api/`
- Shared components in `src/components/`
- Database client in `src/lib/db.ts` (singleton)
## Key Conventions
1. TypeScript strict. No `any` without a comment explaining why.
2. Server components by default; client components only when needed.
3. All API responses return `{ data, error }` — never throw to the client.
4. New migrations require running `npm run db:generate` and committing both files.
## Before starting work
1. Run `npm run dev` and verify the app loads.
2. Check the Linear ticket for acceptance criteria.
3. If touching auth or billing, ping the team first. That is 40 lines. If your first attempt blows through 200, you have scope creep. Push detailed procedures out into skills, path-specific conventions into `.claude/rules/`, and keep `CLAUDE.md` as the project's front-page.
Deconstructing a real CLAUDE.md
To make this concrete, here is the structure of the actual `CLAUDE.md` powering this site, GetuWork — publicly available in our repo. The full file is longer than the skeleton above because we have explicit SEO rules, a multilingual content structure, and specific editorial conventions. It still fits under 200 lines.
Sections in the GetuWork CLAUDE.md (roughly 180 lines)
- Project Vision — one paragraph on positioning and audience. This stays because every content decision should trace back to it.
- Tech Stack — versions and key choices (Astro 5, Tailwind 4 via Vite, custom i18n). No history, just current state.
- Commands — five lines listing dev/build/preview/deploy. Claude reaches here first.
- Architecture — route structure, i18n system, data layer. This is the map someone new would need to navigate the repo.
- Key Conventions — numbered list of rules (i18n first, Astro syntax rather than JSX, SEO rules). Numbers make it easy to reference later.
- Content Clusters — how we structure our content (pillar/child pages). This is specific to our editorial strategy and would be out of scope for most projects.
- Documentation Map — pointers into `docs/` for deeper references. Keeps `CLAUDE.md` short by outsourcing detail.
The critical choices: no history (we do not tell Claude what changed last month), no procedures longer than 5 steps (those live in skills), and heavy use of pointers into the `docs/` directory rather than inlining documentation. The file tells Claude enough to start. For anything deeper, it tells Claude where to look.
When to split into .claude/rules/
For larger projects, you can organize instructions into `.claude/rules/` — a directory of modular markdown files, each covering one topic. The structure looks like this:
your-project/
├── CLAUDE.md # Lean, project-wide essentials
└── .claude/
└── rules/
├── code-style.md # Loaded every session (no paths frontmatter)
├── testing.md # Loaded every session
├── api-conventions.md # Path-scoped to src/api/
├── frontend/
│ └── components.md # Path-scoped to src/components/
└── security.md # Loaded every session Rules without frontmatter are loaded unconditionally, same priority as your main `CLAUDE.md`. The interesting feature is path-scoped rules — rules that only load into context when Claude is actually working on matching files. You declare scoping with glob patterns in YAML frontmatter:
---
paths:
- "src/api/**/*.ts"
- "src/**/*.{ts,tsx}"
---
# API Development Rules
- All API endpoints must include input validation via Zod schemas
- Use the standard error response format: `{ error: { code, message } }`
- Include OpenAPI documentation comments using `@openapi` JSDoc syntax
- Never expose internal error messages to the client This rule file only loads when Claude reads a file matching `src/api/**/*.ts` or `src/**/*.{ts,tsx}`. When Claude is editing CSS or markdown, these rules do not consume context. Your project gets deep, domain-specific guidance where it matters, without paying token cost everywhere.
Glob patterns support brace expansion (`{ts,tsx}`), recursive matches (`**`), and multi-pattern declarations. You can symlink a rules directory from a central location to share a standard rulebook across multiple repos — circular symlinks are detected and handled gracefully.
The @ import feature nobody uses
`CLAUDE.md` files can import other files with `@path/to/file`. The imported file is expanded into context at launch alongside the importing file. Paths are relative to the importing file unless absolute. Imports can recurse up to five hops deep.
# My Project
See @README for project overview and @package.json for npm scripts.
# Git Workflow
- Trunk-based development; main is always deployable
- Follow @docs/commit-conventions.md for commit messages
# Personal Preferences
- @~/.claude/my-project-instructions.md The killer use case is the last line. A personal `CLAUDE.local.md` at the project root is gitignored, which means it only exists in the worktree where you created it. If you work across multiple git worktrees, you lose your personal notes every time. Importing from `@~/.claude/my-project-instructions.md` solves this — your personal preferences live in your home directory and every worktree imports them.
The AGENTS.md compatibility pattern
Claude Code reads `CLAUDE.md`, not `AGENTS.md`. If your repo already has an `AGENTS.md` from Cursor, Continue, or another agent, you do not have to duplicate the content. Create a `CLAUDE.md` that imports it, then add your Claude-specific instructions below:
@AGENTS.md
## Claude Code
Use plan mode for any change that touches billing, auth, or schema migrations.
Do not auto-commit — always leave me to review. Both tools read the same `AGENTS.md` content. Claude Code gets the additional Claude-specific behavior below the import. No drift between the two.
The monorepo pattern — claudeMdExcludes
If you work in a monorepo, ancestor `CLAUDE.md` files from other teams can pollute your context. The `claudeMdExcludes` setting lets you skip them by absolute path or glob pattern:
{
"claudeMdExcludes": [
"**/monorepo/CLAUDE.md",
"/home/user/monorepo/other-team/.claude/rules/**"
]
} Add this to `.claude/settings.local.json` to keep the exclusion personal to your machine. Note that managed policy `CLAUDE.md` files cannot be excluded — organization-wide instructions always apply. This is intentional: it gives IT a way to enforce requirements no individual user can bypass.
Debugging: Claude is ignoring my CLAUDE.md
When a rule is not being followed, the debugging checklist has four steps. Run through them in order.
Debugging checklist
- Is the file being loaded? Run `/memory` in Claude Code. It lists every `CLAUDE.md`, `CLAUDE.local.md`, and rules file currently loaded. If your file is missing, Claude cannot see it. Check the file path and the walk-up behavior — `CLAUDE.md` files in subdirectories load on demand when Claude reads files in those subdirectories, not at launch.
- Is there a conflicting rule? Look across your CLAUDE.md, local CLAUDE.md, user-level CLAUDE.md, and any `.claude/rules/` files for instructions that contradict each other. When two rules conflict, Claude picks one arbitrarily.
- Is the rule specific enough? 'Use modern JavaScript' means nothing concrete. 'Target ES2022, no `var`, prefer `for...of` over `forEach` when mutating' is actionable.
- Has it survived compaction? Project-root `CLAUDE.md` is re-injected after `/compact`, but nested `CLAUDE.md` files in subdirectories are not re-injected automatically — they reload the next time Claude reads a file in that subdirectory. Instructions you gave in conversation (not in a file) are lost on compaction. Add them to `CLAUDE.md` to persist.
For deep debugging, use the `InstructionsLoaded` hook to log exactly which instruction files loaded, when, and why. It gives you a paper trail for every session and is the fastest way to diagnose weird path-specific loading behavior.
A linter skill you can install today
To put this all into practice, here is a skill that audits your `CLAUDE.md` against the five rules and reports what needs fixing. Save as `~/.claude/skills/claude-md-audit/SKILL.md`:
---
name: claude-md-audit
description: Audit a CLAUDE.md file against the five rules of good CLAUDE.md design. Use when reviewing a CLAUDE.md, onboarding to a new project, or before asking a teammate to adopt your CLAUDE.md.
allowed-tools: Read Grep Glob
---
Audit the target CLAUDE.md file. If no path is provided, find the project-root CLAUDE.md.
Report on each of the five rules in order. For each rule, give the verdict (PASS / WARN / FAIL), the evidence, and the recommended fix if the rule is violated.
## Rule 1: Under 200 lines
Count the lines. Report the count. PASS if under 200, WARN if 200-300, FAIL if over 300. Recommend splits via @imports or .claude/rules/ on WARN or FAIL.
## Rule 2: Specific instead of general
Scan for vague instructions. Flag any instruction containing words like "properly", "nicely", "appropriate", "modern", "good" without concrete criteria. List each vague instruction with a suggested rewrite.
## Rule 3: Structure like a human reads
Check for: markdown headers present, paragraphs under 4 sentences, bullet lists for enumerations, any section over 15 lines without sub-headers. Flag long monolithic paragraphs.
## Rule 4: No contradictions
Scan for potentially contradicting instructions. Look for cases where two statements cover the same topic with different guidance (e.g., one says "single quotes", another says "double quotes"). Flag pairs for human review.
## Rule 5: CLAUDE.md is not enforcement
Scan for instructions that say "never", "must", "always" followed by an action that would benefit from hard enforcement. For each, recommend whether it would be better implemented as a hook (blocks a specific tool call) or as a managed permissions.deny rule.
## Overall score
After all five rules, produce a one-line overall verdict: SHIP IT if all PASS, FIX FIRST if any FAIL, REVIEW if mix of PASS/WARN. Invoke it with `/claude-md-audit` in any project with a `CLAUDE.md`. The skill reports on all five rules, surfaces contradictions, and points you at rules that would be better enforced as hooks. For teams onboarding a new project's `CLAUDE.md`, running this once saves a round of code review.
This skill uses the same `allowed-tools` pattern covered in our skills deep dive — Read, Grep, and Glob are pre-approved for this skill, so you are not prompted for permission on every file access during the audit.
FAQ
What should I put in user-level versus project-level CLAUDE.md? User-level (`~/.claude/CLAUDE.md`) is for personal preferences that apply to every project: code style you prefer, shortcut abbreviations, 'prefer pnpm over npm.' Project-level (`./CLAUDE.md`) is for things specific to this codebase: build commands, architecture, naming conventions, rules code review catches most often.
Should my CLAUDE.md be committed to git? Yes for the project-root `CLAUDE.md`. It represents shared team knowledge and the whole team benefits from it. No for `CLAUDE.local.md`, which is personal and should be added to `.gitignore`. Running `/init` with the personal option handles this automatically.
Do small projects need a CLAUDE.md? Even 10 lines beats none. Minimum viable content: build commands, test command, and one or two conventions Claude would otherwise get wrong. The minute you find yourself typing the same correction twice in chat, that correction belongs in `CLAUDE.md`.
How long should I spend writing it initially? About 30 minutes for a first draft. Then iterate — every time you find yourself correcting Claude on the same thing twice, add that instruction. Over a month, a `CLAUDE.md` matures from a rough start into a file that represents exactly how your codebase wants to be edited.
How do I know if my CLAUDE.md is actually working? Observe whether Claude repeats the same mistakes across sessions. If a rule is in `CLAUDE.md` and Claude still breaks it: the rule is either not being loaded (run `/memory` to verify), in conflict with another rule, or too vague. The audit skill above catches the last two.
Where do I go next? Pair this with our deep dive on Claude Code skills — skills are where the multi-step procedures you should keep out of `CLAUDE.md` go. For a complete orientation across Claude Code's feature surface, start with the Claude Code hub guide. And when you are ready to evaluate the tool against alternatives, our Claude Code review has the benchmarks.
¿Te ha gustado este artículo?
Recibe cada semana nuestras mejores guías y reviews en tu bandeja de entrada. Únete a 5,000+ desarrolladores que no se pierden nada de la IA.