CLAUDE.md best practices: 8 patterns that work
Meta description: 8 patterns for structuring CLAUDE.md files so Claude Code actually understands your codebase — from skills and hooks to progressive disclosure.
TL;DR
Your CLAUDE.md is not a README. It’s a short, high-signal repo memory that tells Claude Code how to work in your codebase — not everything about it. After applying these patterns across multiple production repositories, I’ve landed on 8 that reliably make a difference: concise root files, reusable skills, deterministic hooks, progressive disclosure via ADRs, local context in sensitive directories, lean project structure, minimal skill definitions, and documenting architectural why. Get these right, and Claude stops fighting your architecture and starts extending it.
The problem: knowledge dump vs. repo memory
Most teams treat CLAUDE.md like onboarding docs — they dump everything in. Architecture diagrams, coding standards, deployment procedures, team conventions. The result is a 2,000-line file where the stuff Claude actually needs gets buried.
The thing people miss: Claude Code doesn’t need to know everything. It needs the right things at the right time.
The 8 patterns
1. CLAUDE.md as short, high-signal repo memory
Your root CLAUDE.md should be a concise cheat sheet, not a knowledge base. Think sticky notes on a senior engineer’s monitor — build commands, critical invariants, the one thing that breaks if you forget it.
| Approach | Token cost | Signal quality | Result |
|---|---|---|---|
| Full knowledge dump (2,000+ lines) | High | Low — buried in noise | Claude ignores critical rules |
| Concise repo memory (50-150 lines) | Low | High — every line matters | Claude follows conventions reliably |
Keep it under 200 lines. If you need more, you need pattern #4.
2. Skills for repeated workflows
Skills encapsulate repeated workflows — code reviews, release prep, debugging runbooks. Instead of re-explaining your release process every session, define it once as a skill that Claude can invoke consistently.
# Example skill: /release
1. Run `./scripts/version-bump.sh`
2. Update CHANGELOG.md with conventional commits since last tag
3. Create PR targeting main with title "release: vX.Y.Z"
Short, declarative skills outperform verbose ones. A 10-line skill that says what to do beats a 50-line skill that explains how each step works internally. Say what you want done; trust Claude to figure out the mechanics.
3. Hooks over memory for deterministic actions
If an action must always happen — formatting on save, running tests before commit, blocking edits to sensitive folders — don’t put it in CLAUDE.md. Use hooks. Memory is probabilistic; hooks are deterministic.
Claude Code hooks live in .claude/settings.json under event matchers like PreToolUse and PostToolUse:
{
"hooks": {
"PreToolUse": [
{
"matcher": "Edit",
"command": "echo 'Editing file: $CLAUDE_FILE'"
}
],
"PostToolUse": [
{
"matcher": "Write",
"command": "npx prettier --write $CLAUDE_FILE"
}
]
}
}
Hook schemas evolve — check the official Claude Code docs for the current configuration format.
A line in CLAUDE.md saying “always run prettier” will be forgotten halfway through a long session. A hook won’t.
4. Progressive disclosure — point, don’t dump
Instead of inlining your entire authentication architecture into CLAUDE.md, point to it:
## Architecture decisions
- Auth flow: see docs/adr/003-auth-strategy.md
- Database sharding: see docs/adr/007-sharding.md
- API versioning: see docs/adr/012-api-versions.md
Claude reads these files when it needs them. Your root context stays lean while deep knowledge remains accessible on demand.
5. Local CLAUDE.md in sensitive directories
Place local CLAUDE.md files in directories that need special treatment — auth/, db/migrations/, infra/. These override or extend the root file with context that only matters in that scope.
# infra/CLAUDE.md
- NEVER modify terraform state files directly
- All changes require plan output review before apply
- Cost tags are mandatory on every resource
I’ve found this especially useful in codebases where different directories play by fundamentally different rules. The auth module almost always needs stricter guardrails than the rest of the app.
6. Keep context lean and navigable
Every token in your CLAUDE.md that doesn’t directly change Claude’s behavior is wasted context. The same idea behind .editorconfig, ESLint configs, and Git hooks applies here: surface the minimum viable signal at the exact point of action.
This extends to project structure too. Clear folder names, consistent naming, and explicit ownership boundaries help Claude navigate your repo the same way they help a new hire. If a human would be confused by your project layout, Claude will be too.
# Before: unclear structure
src/
mod1/
hlpr.ts
svc.ts
u.ts
mod2/
stuff.ts
# After: navigable structure
src/
payments/
payment-validator.ts
payment-service.ts
payment-utils.ts
notifications/
notification-sender.ts
When Claude sees payments/payment-service.ts, it already knows scope, responsibility, and where related code lives — before reading a single line.
7. Version your CLAUDE.md alongside code
Treat CLAUDE.md as a living artifact that evolves with your codebase. Check it into version control, review changes in PRs, and update it when architecture shifts. A stale CLAUDE.md is worse than none — it actively misleads.
| Practice | Outcome |
|---|---|
| CLAUDE.md updated in same PR as arch changes | Claude stays aligned with current architecture |
| CLAUDE.md reviewed separately, months later | Drift accumulates; Claude follows outdated rules |
| CLAUDE.md never updated after initial creation | Claude fights new patterns, enforces deprecated ones |
The teams I’ve seen get the best results add “update CLAUDE.md” to their PR checklist, right next to “update tests.” It sounds like a small thing, but the compound effect is real.
8. Document the WHY in ADRs
When Claude hits an architectural decision it doesn’t understand — say, why you chose gRPC over REST for internal services — it will try to “fix” it. ADRs (Architecture Decision Records) that explain the why prevent Claude from second-guessing your architecture.
# ADR-005: gRPC for internal services
## Status: Accepted
## Context: Inter-service latency exceeded 200ms p99 under load
## Decision: Migrate internal APIs from REST to gRPC
## Consequence: Significant throughput improvement measured in load tests, but added protobuf compilation step
Without this, Claude sees gRPC and may suggest REST “for simplicity.” With the ADR in place, it respects the decision and works within the constraint.
Pattern comparison
| Pattern | Type | When to use |
|---|---|---|
| Root CLAUDE.md | Static context | Always — every repo needs one |
| Skills | Reusable workflows | Repeated multi-step tasks |
| Hooks | Deterministic enforcement | Actions that must never be skipped |
| Progressive disclosure | On-demand context | Complex architectures with deep docs |
| Local CLAUDE.md | Scoped rules | Sensitive or special-case directories |
| Lean and navigable | Structural discipline | All repos — reduce noise everywhere |
| Versioned CLAUDE.md | Change management | Any repo under active development |
| ADRs | Architectural rationale | Any non-obvious design decision |
3 takeaways you can act on today
-
Audit your CLAUDE.md. If it’s over 200 lines, extract detail into ADRs and local context files. Keep the root file high-signal.
-
Convert your top 3 repeated workflows into skills. Release, review, and debug are good starting candidates. Keep each under 15 lines.
-
Replace every “always do X” instruction with a hook. If it must happen every time, it belongs in deterministic automation, not probabilistic memory.
TAGS: architecture, devops, cleanarchitecture, api, productengineering