---
title: The Complete Guide to Writing a Great CLAUDE.md
title_en: The Complete Guide to Writing a Great CLAUDE.md
description: A practical, research-backed reference for writing CLAUDE.md files Claude Code actually follows — file locations, load order, what to include, scaling with rules, and a minimal template.
sidebar_label: Writing a great CLAUDE.md
---

# The Complete Guide to Writing a Great CLAUDE.md

A practical, research-backed reference for writing `CLAUDE.md` files that Claude Code actually follows. Compiled from Anthropic's official docs and field-tested community practices.

---

## 1. What CLAUDE.md Is (and Isn't)

`CLAUDE.md` is a plain markdown file that gives Claude **persistent instructions** for a project, your personal workflow, or your whole organization. Claude reads it at the **start of every session** and injects it into the context window.

Key mental model:

- It is **context, not enforced configuration**. Claude reads it and *tries* to follow it — there is no guarantee of strict compliance, especially for vague or conflicting instructions.
- It is delivered as a user message **after** the system prompt, not as part of it.
- If you need something to run **always**, at a fixed point (e.g. before every commit), use a **hook**, not CLAUDE.md.
- If you need to **hard-block** a tool/command/path, use **managed settings** (`permissions.deny`), not CLAUDE.md.

> Rule of thumb: **CLAUDE.md shapes behavior. Hooks and settings enforce it.**

---

## 2. The Golden Rules

1. **Keep it under 200 lines** (~300 is the absolute ceiling). It loads every session and consumes context budget that could go to your actual code. Many strong examples are under 60 lines.
2. **Every line must earn its place** — it should prevent a mistake or save a repeated explanation.
3. **Be specific and verifiable.** "Use 2-space indentation" beats "format code properly."
4. **Write imperative commands, not observations.** "Never use inline mocks — use `src/test/factories/*`" beats "we generally try to avoid inline mocks."
5. **Negative rules matter as much as positive ones.** "Never commit `.env`", "No class components", "No SSR." Without them, Claude defaults to the most common pattern it knows — which may not be yours.
6. **Don't make a linter's job an LLM's job.** Use deterministic tools (linters, formatters) for style enforcement; they're faster, cheaper, and reliable.
7. **Use emphasis sparingly.** `IMPORTANT` and `YOU MUST` genuinely improve adherence — but only if rare. Mark everything important and nothing is.
8. **Resolve contradictions.** If two rules conflict, Claude picks one arbitrarily. Review periodically.

### Why the line limit matters

Frontier thinking models can reliably follow roughly **150–200 instructions** total. Claude Code's own system prompt already uses ~50 of those. Instruction-following degrades as the count grows — so every instruction you add competes with the rest for attention. Smaller/non-thinking models follow fewer still.

---

## 3. File Locations & Load Order

CLAUDE.md files can live in several places. They are **concatenated** (not overridden), loaded from broadest to most specific scope — so more specific instructions are read last and take priority.

| Scope | Location | Purpose | Shared with |
|---|---|---|---|
| **Managed policy** | macOS: `/Library/Application Support/ClaudeCode/CLAUDE.md` · Linux/WSL: `/etc/claude-code/CLAUDE.md` · Windows: `C:\Program Files\ClaudeCode\CLAUDE.md` | Org-wide standards, security/compliance | All users in org (cannot be excluded) |
| **User** | `~/.claude/CLAUDE.md` | Your personal prefs across all projects | Just you, all projects |
| **Project** | `./CLAUDE.md` or `./.claude/CLAUDE.md` | Team-shared project instructions | Team via version control |
| **Local** | `./CLAUDE.local.md` | Personal project-specific prefs (gitignore it) | Just you, current project |

**Directory walk:** Claude walks **up** the tree from your working directory, loading every `CLAUDE.md` / `CLAUDE.local.md` it finds. Content is ordered root → working dir, so instructions closest to where you launched are read last. Within a directory, `CLAUDE.local.md` is appended after `CLAUDE.md`.

**Subdirectories:** Nested `CLAUDE.md` files **below** your working dir are *not* loaded at launch — they load on demand when Claude reads files in those directories.

> Filename is case-sensitive: exactly `CLAUDE.md` (uppercase `CLAUDE`, lowercase `.md`).

---

## 4. What to Put In It

Cover these, roughly in order of impact:

### a. Build / Test / Lint commands
Claude does **not** know how to build, test, or lint your project. Tell it explicitly. Without this it'll try `npm test` when you use `pnpm vitest` and burn turns failing.

```markdown
## Commands
- Build:  `pnpm build`
- Test:   `pnpm vitest run`
- Lint:   `pnpm lint --fix`
- Typecheck: `pnpm tsc --noEmit`
```

### b. Coding rules (positive AND negative)
```markdown
## Code style
- TypeScript strict mode; never use `any`
- Named exports only, no default exports
- Use the project logger, never `console.log`
- Tailwind utility classes only — no inline styles
```

### c. Architecture / project layout
Give Claude a map, especially in monorepos.
```markdown
## Layout
- API handlers live in `src/api/handlers/`
- Shared types in `packages/types/`
- Never edit generated files in `src/gen/`
```

### d. Gotchas & non-obvious constraints
```markdown
## Gotchas
- API tests require a local Redis instance (`docker compose up redis`)
- The legacy `v1/` routes are frozen — do not refactor them
```

### The WHAT / WHY / HOW framework
A useful structure to sanity-check coverage:
- **WHAT** — tech stack (with version numbers!), project structure, codebase map
- **WHY** — project purpose and goals
- **HOW** — build commands, testing, verification

> Claude can't guess your framework version. State it. "React 19", "Node 22", "Python 3.12".

---

## 5. What to Leave Out

- ❌ Style rules a linter/formatter already enforces.
- ❌ Task-specific or one-off instructions that don't apply universally → use a **skill**.
- ❌ Multi-step procedures or rules that only matter for one part of the codebase → use a **path-scoped rule** or skill.
- ❌ Duplicated authoritative info (full README, schema dumps). Link to it instead.
- ❌ "Hotfix" entries added to patch one bad session. Treat root cause, not symptom.

---

## 6. Keeping It Lean: Imports & Progressive Disclosure

### `@` imports
Pull in other files with `@path/to/file`:
```markdown
See @README for the overview and @package.json for npm commands.

# Workflow
- Git conventions: @docs/git-instructions.md
```
- Relative paths resolve from the importing file. Recursive imports allowed, max depth 4.
- **Caveat:** imported files still load into context at launch — imports help *organization*, not *context size*.

### Progressive disclosure
Keep the main file lean; point Claude to detail docs it can read on demand:
```
agent_docs/
├── building_the_project.md
├── running_tests.md
├── code_conventions.md
└── service_architecture.md
```
Reference each with a one-line description and let Claude decide which to open.

### Prefer `file:line` references over code snippets
Pointing to `src/api/handlers/user.ts:42` won't go stale the way a pasted snippet will.

### Maintainer comments are free
Block-level HTML comments (`<!-- note to humans -->`) are **stripped before** entering Claude's context — use them for human-only notes without spending tokens. (Comments inside code blocks are preserved.)

---

## 7. Scaling Up: `.claude/rules/`

For larger projects, split instructions into topic files under `.claude/rules/`. One topic per file.

```
your-project/
├── .claude/
│   ├── CLAUDE.md
│   └── rules/
│       ├── code-style.md
│       ├── testing.md
│       └── security.md
```

- Rules **without** `paths` frontmatter load every session (same priority as `.claude/CLAUDE.md`).
- **Path-scoped rules** load only when Claude touches matching files — saving context:

```markdown
---
paths:
  - "src/api/**/*.{ts,tsx}"
  - "tests/**/*.test.ts"
---
# API rules
- All endpoints must validate input
- Use the standard error response format
```

| Pattern | Matches |
|---|---|
| `**/*.ts` | All TS files anywhere |
| `src/**/*` | Everything under `src/` |
| `*.md` | Markdown in project root |

- Rules can be **symlinked** to share across projects.
- User-level rules live in `~/.claude/rules/` (loaded before project rules, so project wins).

---

## 8. CLAUDE.md vs Auto Memory vs Skills vs Hooks

| Mechanism | Who writes it | When it loads | Use for |
|---|---|---|---|
| **CLAUDE.md** | You | Every session, in full | Standards, workflows, architecture |
| **Auto memory** (`MEMORY.md` + topic files) | Claude | Every session (first 200 lines / 25KB of `MEMORY.md`) | Learnings, debugging insights, discovered prefs |
| **Skills** | You | On demand when relevant/invoked | Repeatable multi-step procedures |
| **Rules** (`.claude/rules/`) | You | Every session, or when matching files open | Modular/path-scoped standards |
| **Hooks** | You | Fixed lifecycle events (shell commands) | Things that MUST run, regardless of Claude's choice |
| **Managed settings** | IT/admin | Always enforced by client | Hard blocks: deny tools/paths, sandbox, auth |

> When you tell Claude "always use pnpm, not npm," it saves that to **auto memory**. To put it in CLAUDE.md instead, say "add this to CLAUDE.md."

### AGENTS.md interop
Claude Code reads `CLAUDE.md`, **not** `AGENTS.md`. If your repo uses `AGENTS.md`, create a `CLAUDE.md` that imports it:
```markdown
@AGENTS.md

## Claude Code
Use plan mode for changes under `src/billing/`.
```

---

## 9. Bootstrapping & Maintenance

### Start with `/init`
Run `/init` in your project root. Claude analyzes the codebase and drafts a CLAUDE.md with discovered commands, tests, and conventions. **Always review it** — cut the obvious, add what Claude can't discover (your team's actual conventions, gotchas, the *why*). Starting from `/init` beats a blank file; shipping `/init` output unreviewed does not.

### Grow it organically
Add an entry when:
- Claude makes the same mistake a second time
- A code review catches something Claude should have known
- You type the same correction you typed last session
- A new teammate would need the same context

### Prune it regularly
Every few weeks, ask Claude to review and optimize the file: remove obsolete rules, consolidate redundancy, resolve conflicts. Instructions accumulate and decay.

---

## 10. Troubleshooting

**"Claude isn't following my CLAUDE.md"**
- Run `/memory` to confirm the file is actually loaded (if it's not listed, Claude can't see it).
- Make instructions more specific and verifiable.
- Hunt for contradictions across nested files and rules.
- If it must run at a fixed point → convert to a **hook**.
- For system-prompt-level instructions → `--append-system-prompt` (must pass every invocation; best for scripts).

**"My CLAUDE.md is too large"**
- Trim to what's needed every session.
- Move conditional content to **path-scoped rules**.
- Note: `@` imports help organization but *don't* reduce context.

**"Instructions seem lost after /compact"**
- Project-root CLAUDE.md is **re-injected** after compaction. Nested subdirectory files reload only when Claude next reads a file there.
- If something vanished, it was likely conversation-only — add it to CLAUDE.md to persist.

**Debug what's loaded:** use the `InstructionsLoaded` hook to log exactly which instruction files load, when, and why.

---

## 11. Quick Checklist

- [ ] Under 200 lines
- [ ] One-line project description + tech stack with versions
- [ ] Build / test / lint / typecheck commands
- [ ] Positive *and* negative coding rules
- [ ] Architecture / file-layout map
- [ ] Non-obvious gotchas
- [ ] Every instruction specific and verifiable
- [ ] `IMPORTANT`/`YOU MUST` used sparingly
- [ ] No linter-replaceable style rules
- [ ] No contradictions
- [ ] Detail offloaded to imports / rules / skills
- [ ] Reviewed (not raw `/init` output)

---

## 12. Minimal Template

```markdown
# <Project Name>

<One-line description.> Stack: <e.g. Next.js 15, React 19, TypeScript 5.6, Postgres>.

## Commands
- Dev:       `pnpm dev`
- Build:     `pnpm build`
- Test:      `pnpm vitest run`
- Lint:      `pnpm lint --fix`
- Typecheck: `pnpm tsc --noEmit`

## Code style
- TypeScript strict; never `any`
- Named exports only
- Use `logger`, never `console.log`

## Architecture
- API handlers: `src/api/handlers/`
- Shared types: `packages/types/`
- Never edit generated code in `src/gen/`

## Rules
- IMPORTANT: Never commit secrets or `.env*` files
- Run `pnpm test` before committing
- No new dependencies without justification

## Gotchas
- Integration tests need local Redis: `docker compose up -d redis`

See @README.md for full overview. Detailed conventions: @docs/conventions.md
```

---

## Sources

- [How Claude remembers your project — Claude Code Docs](https://code.claude.com/docs/en/memory)
- [Best practices for Claude Code — Claude Code Docs](https://code.claude.com/docs/en/best-practices)
- [Writing a good CLAUDE.md — HumanLayer](https://www.humanlayer.dev/blog/writing-a-good-claude-md)
- [How to Write a Good CLAUDE.md File — Builder.io](https://www.builder.io/blog/claude-md-guide)
- [Writing the Best CLAUDE.md: A Complete Guide — DataCamp](https://www.datacamp.com/tutorial/writing-the-best-claude-md)
- [How to Write a CLAUDE.md File That Actually Works — TurboDocx](https://www.turbodocx.com/blog/how-to-write-claude-md-best-practices)
- [The Complete Guide to CLAUDE.md — Bijit Ghosh (Medium)](https://medium.com/@bijit211987/the-complete-guide-to-claude-md-memory-rules-loading-and-cross-tool-compression-97cc12ed037b)
