Home » AI Coding Memory » Structure CLAUDE.md

How to Structure CLAUDE.md for Maximum Context

A well-structured CLAUDE.md file focuses exclusively on information that Claude Code cannot determine from the codebase itself: non-obvious constraints, conventions that deviate from defaults, architecture decisions with their reasoning, and codebase-specific anti-patterns. The most effective files are under 2,000 words, organized by category rather than chronologically, and edited ruthlessly to remove anything the assistant can figure out on its own.

The Principle: Only Document the Non-Obvious

The most common mistake in CLAUDE.md files is documenting things the assistant already knows. Writing "This is a Next.js project with TypeScript" wastes tokens because Claude Code can determine that from package.json and tsconfig.json in under a second. Writing "We use PostgreSQL" wastes tokens because Claude Code can read the database configuration.

The information that belongs in CLAUDE.md is the information that is invisible or misleading when looking at the code alone. A database column named "status" that accepts integers 1 through 5 does not reveal that status 3 means "pending review by compliance" and that records in this status must never be modified by the API. A function named "processPayment" does not reveal that it must be called through a queue because the external API has a 10-request-per-second limit that the function does not enforce internally. These are the things that trip up new developers and AI assistants alike, and they are exactly what CLAUDE.md should capture.

Step-by-Step Structure

Step 1: Start with non-obvious constraints.
Constraints are the highest-value content for a CLAUDE.md file because violating a constraint causes bugs, outages, or data corruption. List the constraints that are not enforced in code and that a developer unfamiliar with the project would not know about.
## Constraints - The Stripe webhook endpoint must respond within 5 seconds or Stripe retries, causing duplicate processing. Keep the handler thin and queue heavy work. - The users table uses soft deletes (deleted_at column). ALL queries must filter for deleted_at IS NULL unless explicitly querying deleted records. The ORM does not add this filter automatically. - Redis is shared between the app and the job queue. Using FLUSHDB in development also wipes pending jobs. - The S3 bucket has a lifecycle policy that deletes objects in the /tmp/ prefix after 24 hours. Never use /tmp/ for permanent storage.
Step 2: Document conventions that differ from defaults.
Only include conventions that deviate from what the language, framework, or community standard prescribes. If your team follows the standard React project structure, do not document the React project structure. If your team puts tests in a non-standard location, document that.
## Conventions - API responses always use camelCase JSON keys, even though the Python backend uses snake_case internally. The serialization layer handles conversion. - Test files live in __tests__/ directories at each package level, not next to the source files. - Database migrations are numbered sequentially (001_, 002_), not timestamped. Check the highest number before creating. - Error messages returned to the frontend must be user-readable English, not technical descriptions. The frontend displays them directly in toast notifications.
Step 3: Include architecture decisions with reasoning.
The reasoning behind architecture decisions is more valuable than the decisions themselves because it helps the assistant make consistent choices in edge cases. When the assistant knows why a decision was made, it can extend that reasoning to new situations rather than just following a rule mechanically.
## Architecture Decisions - The notification service is separate from the user service even though they share the user database. This is because notifications must continue sending during user service deploys. They share a read-only database replica. - We use event sourcing for the order system but standard CRUD for everything else. The order system needs a full audit trail for compliance. Other entities do not have this requirement. - Authentication uses JWTs with 15-minute expiry and refresh tokens. The short expiry is intentional: we cannot revoke JWTs, so we rely on short lifetimes plus a token blacklist for the refresh tokens.
Step 4: List anti-patterns specific to your codebase.
Anti-patterns are things that look like they should work but cause problems in your specific codebase. These are different from general coding anti-patterns (which the assistant already knows). Document the approaches that a reasonable developer would try and that would fail.
## Anti-patterns (Do Not Do These) - Do not use the ORM's eager loading for the orders table. The polymorphic line_items association causes N+1 queries. Use OrderRepository.findWithItems() which has an explicit optimized join. - Do not call UserService.delete() directly. It does not clean up related records in other services. Use the DeleteUserSaga which coordinates cleanup across services. - Do not add indexes to the events table without checking with the DBA. The table has 800M rows and adding an index locks it for hours in production.
Step 5: Keep it under 2,000 words.
Every word in CLAUDE.md consumes context window tokens. A 2,000-word file uses roughly 2,500 tokens, leaving plenty of room for code, conversation, and MCP tool results. A 10,000-word file uses over 12,000 tokens, significantly reducing the space available for the actual work of the session.

Ruthless editing is the key skill. For each line in the file, ask: "If I removed this, would the assistant make a mistake?" If the answer is no, the line does not belong. If the answer is "maybe in an unusual case," consider whether the unusual case justifies the permanent token cost. The file should contain only information that prevents mistakes that matter.

Step 6: Use the three-file hierarchy for layered context.
Claude Code reads CLAUDE.md from three levels: the project root, any parent directories, and the user's home directory (~/.claude/CLAUDE.md). Use this hierarchy to separate concerns and reduce duplication.

The home-level file contains your personal preferences: coding style, interaction style, explanation depth, and patterns you prefer across all projects. The parent-directory file (if you use a monorepo or multi-project workspace) contains shared conventions. The project-level file contains project-specific constraints, architecture, and anti-patterns.

This layering means the project file only needs to document what is specific to that project, not your general preferences. A well-organized hierarchy keeps each file focused and short, even if the total context across all levels is substantial.

Common Mistakes to Avoid

Documenting file structure. The assistant can run ls and find. Listing every directory and its purpose is a waste of tokens unless the structure is unusual or misleading.

Including long code examples. If the example exists in the codebase, reference the file path instead. "See src/handlers/orders.ts for the standard handler pattern" is more token-efficient than pasting 50 lines of code and keeps the reference up to date as the code changes.

Writing a changelog. CLAUDE.md is not a history of changes. It is a current-state document. Remove information that is no longer relevant rather than keeping it for historical context. Use git history for that.

Being too general. "Write clean code" and "follow best practices" are not actionable instructions. Be specific: "Functions in the service layer must not exceed 30 lines" or "All public API endpoints must have at least one integration test."

Complement your CLAUDE.md with dynamic memory that grows automatically. Adaptive Recall stores the long tail of project knowledge that does not fit in a static file.

Get Started Free