CLAUDE.md guide. How to write one that actually works.
I wrote this because I have read many articles about what CLAUDE.md is and how to write the best CLAUDE.md, but I don't think that's right. So I have researched and experimented myself on what the general rules are for how to write and maintain a CLAUDE.md effectively. Here are some guidelines. I write this just to share my workflow with you guys.
I wrote the whole guideline so that you can just copy this article and paste it directly into your Claude and tell it to rewrite your CLAUDE.md to follow this guideline, and it will do it. So yeah, it's that simple.
CLAUDE.md files are agent configuration: they are injected into the context window at the start of every AI agent session. Every line in a CLAUDE.md competes with the actual task for attention.
Principles
- Context window is finite, and budgeted. Frontier thinking models follow ~150-200 instructions reliably. Claude Code's system prompt already burns ~50. Every guardrail you add spends from the remaining budget, and compliance degrades uniformly. It is not just the bottom rules that get ignored, ALL rules get followed slightly less reliably. Target the minimum that prevents real damage.
- Relevance gating is real. Claude Code wraps CLAUDE.md with a system reminder that says the content "may or may not be relevant." If the agent decides a section is irrelevant to its current task, it skips it. A root file full of API-only rules during a frontend task trains the model to see the whole file as low-relevance, weakening even the rules that do apply. This is why app-specific rules belong in app-level files: they are only loaded when the agent is working in that app.
- Guardrails over guidance. CLAUDE.md tells agents what not to break and where to look. It does not teach patterns or explain architecture. That belongs in
docs/. - Automate before documenting. A linter rule or hook is strictly better than a prose guardrail. It is deterministic and costs zero instruction tokens. Only add a CLAUDE.md guardrail when automated enforcement is not possible. The enforcement hierarchy: (1) CI / linter / type checker, (2) Claude Code hook, (3) CLAUDE.md prose rule.
- Empirical, not speculative. A rule earns its place by preventing an observed failure. If an agent has never made the mistake, the rule is dead weight. If an agent makes the same mistake twice, add the rule. I also noticed that agents are in-context learners. They pick up patterns from the code they read during the session. A guardrail for a pattern the codebase already demonstrates consistently is spending an instruction token for marginal gain.
- Route, don't duplicate. CLAUDE.md points to docs. It does not copy from them. The moment content exists in both places, one of them will go stale.
File hierarchy
CLAUDE.md <- root: repo-wide rules, project topology, module index
apps/backend/CLAUDE.md <- app-level: backend-specific patterns, conventions, tooling
apps/frontend/CLAUDE.md <- app-level: frontend-specific patterns, conventions, tooling
packages/shared/CLAUDE.md <- package-level: shared library conventions (if needed)
In a monorepo, agents load the root CLAUDE.md first, then the app-level CLAUDE.md for the app they are working in. In a single-app repo, the root file is the only file. This means:
- The root file contains rules that apply everywhere. If a rule only matters inside one app or package, it belongs in that directory's CLAUDE.md.
- App-level files do not repeat root rules. They extend or specialize.
- If a rule in an app-level file conflicts with the root, the app-level file wins for work inside that app.
When to create an app-level file
Create one when a directory has patterns that agents consistently get wrong and those patterns are specific to that context. A frontend CLAUDE.md makes sense because the frontend has its own component anatomy, query patterns, and import conventions. A backend CLAUDE.md makes sense because the backend has its own handler structure, auth patterns, and test conventions.
Do not create an app-level CLAUDE.md speculatively. If the root file is sufficient, there is no app-level file.
Root CLAUDE.md structure
The root file has five sections, in this order. Order matters because agents attend most strongly to what comes first.
1. Guardrails
Rules that must never be violated, regardless of context. These are the highest-priority instructions in the file.
What belongs here:
- Import rules that agents violate and that cause real problems (wrong paths, wrong packages, bypassing shared instances)
- Security invariants (token storage, secret handling)
- Patterns that are explicitly prohibited because agents default to them (unnecessary memoization, barrel files, raw env access, useEffect for data fetching)
- Structural rules that prevent architectural damage (no type redefinition, no direct HTTP library usage)
What does NOT belong here:
- Rules enforceable by a linter, type checker, or hook. Automated enforcement is deterministic and costs zero instruction tokens. If
no-console: errorcatches it, delete the prose rule. - Style preferences (formatting, naming conventions). These go in linter config or conventions.md.
- Aspirational rules nobody has violated yet.
- Rules that only apply inside one app. Those go in that app's CLAUDE.md.
Write one rule per line. Imperative. Start with NEVER or ALWAYS. No prose explanation. If a rule needs explanation, put it in docs/conventions.md and keep the guardrail to a one-line summary.
## Guardrails
- NEVER import from `dayjs` directly. Use `@/lib/dayjs`.
- NEVER read `import.meta.env` directly. Use `@/config/env`.
- ALWAYS handle loading, error, and empty states in data-dependent components.
Aim for 10-25 lines. If you exceed 25, audit for rules that belong in app-level files or that have never actually been violated.
2. Project Structure
The monorepo layout. What lives where. Pure routing so the agent does not create files in wrong locations or misunderstand the workspace topology.
List each workspace or package with a one-line purpose, mention shared packages and where docs live. That's it. Internal folder structure within each app goes in that app's CLAUDE.md. Dependency lists and build details do not belong here. Keep it to 5-15 lines.
3. Key patterns
Patterns that span the monorepo or that define how apps interact. If an agent gets these wrong, the damage crosses app boundaries: cross-boundary type flow, auth architecture, and shared response formats.
Keep each pattern to 2-4 sentences and link to the relevant doc for depth. App-internal patterns (component anatomy, handler structure) go in app-level files, not here. I've found 15-30 lines is the right range; more than that and you're duplicating your guideline docs.
4. Module index
One entry per module. The agent uses this to decide whether it needs to load the full module doc into context before starting work.
Format per module:
**Payments** (`docs/payments.md`): Manages subscriptions, plans, and payment lifecycle.
Provider-agnostic schema; webhook-driven state machine for subscription status.
First sentence says what the module does. Second sentence covers the most important constraint or design choice. You can add a third for key integrations, but no more than that.
Leave out implementation details (the module doc covers those) and status updates or TODOs (those belong in specs or build plans). 3-5 lines per module. This section grows as you add modules, and that is fine because it sits lower in the file where dilution matters less.
5. Agent workflow
The "read before write" discipline. Tell the agent what to read before modifying a module, what to update after completing work, and where to find documentation standards. Do not paste the full documentation standards here. Link to them. Coding style rules go in guardrails or linter config, not in this section. 10-15 lines.
Total target
The root CLAUDE.md targets 80-120 lines. The hard ceiling is 200 lines. If you exceed 150, audit every section against the principles at the top of this guide.
App-level CLAUDE.md structure
App-level files are shorter and more focused. They contain only what is specific to that app and that agents get wrong.
Structure
- Guardrails: app-specific rules not covered by the root file
- Folder structure: internal directory layout for this app
- Patterns: app-specific conventions with links to the relevant guideline doc
Module index and project structure live at root, so do not repeat them here. Same for root guardrails.
Target
40-80 lines. If an app-level file exceeds 100 lines, content is probably duplicating the root file or a guideline doc.
Example: apps/frontend/CLAUDE.md
## Guardrails
- NEVER use useEffect to sync derived state. Derive it during render.
- NEVER create validation schemas that duplicate shared contracts. Import and extend.
- ALWAYS use the shared HTTP client from `@/lib/http`. No raw fetch or direct axios.
- ALWAYS handle loading, error, and empty states in data-dependent components.
## Folder Structure
Features live in `src/features/{name}/` with this layout:
- `api/`: HTTP calls, query hooks, key factory
- `components/`: feature-scoped UI
- `pages/`: route-level components (thin, validate params, compose features)
Shared code: `src/components/`, `src/hooks/`, `src/lib/`. Code moves here only
when a second feature genuinely needs it.
## Patterns
See `docs/frontend-guideline.md` for the full standard. Key points:
- Component anatomy: imports → types → constants → component (hooks, derived,
handlers, early returns, JSX).
- Query library (React Query, SWR, etc.) owns all server state.
- Forms use a form library with schema-based validation. Schema from shared
contracts, extended for UI-only fields.
Writing rules
- Imperative mood for guardrails. "NEVER do X" not "X should be avoided."
- No hedging. No "prefer" or "try to" or "when possible." Either it is a rule or it is not. If there are valid exceptions, state the exception explicitly: "NEVER use default exports, except for lazy-loaded page components."
- No explanation in guardrails. The guardrail is the rule. If the agent needs to understand why, link to a doc. The why slows down scanning.
- No code blocks longer than 5 lines. CLAUDE.md is configuration, not a tutorial. If a pattern needs a code example to be understood, that example belongs in a guideline doc, and the CLAUDE.md links to it.
- No TODOs, future plans, or aspirational content. CLAUDE.md describes what IS, not what will be.
Maintenance
When to add
Add a guardrail when you observe an agent making the same mistake on two separate occasions. One occurrence is noise. Two is a pattern. Write the rule that would have prevented it.
Before adding, check: is this already covered by a linter rule, a TypeScript config, or an existing guardrail? If yes, the agent is ignoring config, which is a different problem than missing documentation.
When to remove
Remove a guardrail when any of these are true:
- The rule is now enforced by a linter, type checker, or CI check. Automated enforcement is strictly better than a prose rule.
- The rule has not been relevant for 3+ months and the pattern it prevents is no longer a realistic agent behavior.
- The codebase has changed such that the rule no longer applies.
When to update or audit
Update the module index when you ship a new module or fundamentally change an existing one. Review the full file quarterly or whenever it crosses a length threshold.
Bloat checklist
Run this checklist every quarter or when the file feels too long:
- For each guardrail: has an agent violated this in the last 3 months? If no, consider removing.
- For each pattern: is this duplicated from a guideline doc? If yes, replace with a link.
- For each module summary: does this still accurately describe the module? If not, update from the module doc.
- Total line count: is it under the target for this file level? If over, what can be cut or moved?
Anti-patterns
The most common mistake is the kitchen sink: dumping every coding standard, style preference, and architectural decision into CLAUDE.md. I've seen 500-line files where the agent skims the whole thing and follows almost nothing. CLAUDE.md is a routing layer, not a knowledge base.
Then there's the tutorial approach, where you write explanations of why each rule exists, with code examples and edge cases. That belongs in guideline docs. CLAUDE.md states rules; docs explain them.
Watch out for wish lists too. Adding rules for problems that have not happened yet. "NEVER use microservices" is not useful if no agent has ever tried to introduce microservices into your codebase. I used to do this, preemptively adding guardrails "just in case." Every one of them was dead weight.
Copy-pasting from guidelines is another trap. Duplicating sections of your frontend or backend guideline into CLAUDE.md creates two sources of truth. When you update the guideline, the CLAUDE.md copy goes stale.
Do not write prose versions of linter rules. Guardrails for things a linter already catches (console.log is prohibited, use const not let) spend instruction tokens for zero marginal enforcement. If the linter is configured, the prose rule is dead weight. If the linter is not configured, configure it.
Avoid over-specifying the obvious. Rules like "write clean code" or "follow best practices" or "use meaningful variable names" are noise. Agents either do this by default or they do not, and a prose instruction will not change which.
Finally, do not use CLAUDE.md as a changelog. Recording what was added or removed over time, inside the file itself, is what git history is for. Every line of changelog is a line of diluted guardrails.
Precedence
When instructions conflict across files, the resolution order is:
- App-level CLAUDE.md (most specific to the current work context)
- Root CLAUDE.md (monorepo-wide rules)
- Guideline docs (
frontend-guideline.md,backend-guideline.md,conventions.md) - Module docs (
docs/{module}.md)
A guardrail in an app-level file overrides the root file for work inside that app. A guardrail in the root file overrides general guidance in a guideline doc. Guideline docs provide depth; CLAUDE.md provides the binding constraints.
Relationship to other docs
CLAUDE.md sits at the top of a documentation hierarchy. It routes agents to deeper docs and never copies from them.
The test for whether content belongs in CLAUDE.md vs. another doc: does the agent need this information before it starts reading code? If yes, CLAUDE.md. If the agent only needs it after it has started working on a specific module, it belongs in that module's doc or the relevant guideline.