How to write a CLAUDE.md that actually helps the agent
CLAUDE.md is the most-undervalued AI productivity tool. A good one saves hours per week; a generic one is dead weight. Here's what makes the difference.
CLAUDE.md is the most-undervalued AI productivity tool. A well-written one saves you hours per week of re-explaining context. A generic copy-pasted one is dead weight that the agent skims and ignores.
This post documents the patterns we use across mq-dir's CLAUDE.md files and the failure modes that make CLAUDE.md useless.
What CLAUDE.md actually does
When you start a Claude Code session, the agent reads CLAUDE.md from (in order):
~/.claude/CLAUDE.md— your global preferences.<project root>/CLAUDE.md— project-specific rules.<session root>/CLAUDE.md(or.claude/instructions.md) — current goal/scope.
These compose. Global says "I prefer succinct responses." Project says "always run swift test before commit." Session says "we're rewriting auth this run; don't touch user UI."
The agent treats this as standing context, like a system prompt. Every conversation in this codebase/session gets it.
Three patterns: global / project / session
Global ~/.claude/CLAUDE.md
Things true about you, regardless of project:
- Prefer concise responses unless I ask for depth.
- When suggesting commands, give one option, not three.
- Don't add error handling for cases that can't happen.
- Don't add comments explaining what code does (well-named identifiers do that).
- I'm comfortable with TypeScript strict, Rust, Swift. No JavaScript without a reason.
This is short. 30-50 lines. Easy to maintain.
Project CLAUDE.md
Things true about THIS codebase:
# mq-dir
## Build & test
- `xcodegen generate` regenerates .xcodeproj after editing project.yml
- `swift test` runs core tests fast
- Every commit must be DCO-signed (`git commit -s`)
## Architecture
- mqdirCore: pure-Foundation, @Sendable persisted types
- mq-dir: SwiftUI/AppKit app target
## Persistence rules
- Every Codable type hand-rolls init(from:) with decodeIfPresent
- Every schema bump needs a testMigration_vN_to_vN+1 test
## Concurrency
- SWIFT_STRICT_CONCURRENCY: complete is on
- View models are @MainActor
## Out of scope (don't suggest)
- Cloud sync, plugins, file editing, iPadOS port
- Privacy posture: zero telemetry. Changes need opt-in design.
This is project-public. Commit it. Everyone (including the agent) benefits from it being authoritative.
mq-dir's actual CLAUDE.md is ~120 lines. That's about right for a real project. Some are 200; few should be over 400.
Session CLAUDE.md
Things true about THIS particular run:
# Session: auth rewrite — 2026-04-22
## Goal
Replace legacy CookieAuth with JwtAuth using the new pattern in
docs/auth.md. Ship behind the `feature.jwt` flag.
## Out of scope
- User-management UI (separate session)
- Test fixtures migration (follow-up)
## Constraints
- All new files: TypeScript strict
- Run `npm test -- --bail` after every commit
- PR to feat/auth-jwt; don't push to main
This is short — 15-30 lines. It's the contract for the run.
The non-negotiables
Three things every CLAUDE.md should have:
1. Scope (what's in vs. what's out)
The most-skipped section and the most-valuable.
## Out of scope
- Don't touch the auth module — that's a separate session.
- Don't migrate test fixtures — follow-up.
- Don't add new dependencies without explicit approval.
When the agent goes off-rails, scope is what brings it back. Without scope, the agent might "helpfully" refactor things you didn't ask about.
2. Constraints (the rules you'd otherwise re-explain)
## Constraints
- Run `swift test` before claiming a commit is done.
- Don't add comments unless explaining a non-obvious why.
- Don't introduce error handling for cases that can't happen.
Each constraint here is something you'd otherwise type into chat 50 times.
3. Project shape (the geography)
## Architecture
- src/auth/ — auth module
- src/users/ — user management (don't touch this run)
- src/lib/ — shared utilities
- tests/ — Jest tests, mirrors src/
- docs/ — design notes
The agent doesn't need to discover the codebase shape on each prompt if you tell it once.
Failure modes
Too vague
## Be helpful
Help me with my code.
This adds nothing. Skip the file.
Too long
A 1500-line CLAUDE.md is worse than 100 lines. The agent skims and misses critical rules. Refactor: extract sections to project-specific files.
Inconsistent with the codebase
CLAUDE.md says "use SwiftPM"; codebase actually uses Xcode project. The agent gets confused. Audit periodically.
Generic copy-pasta
Templates are useful as starting points, not as final form. A copy-pasted CLAUDE.md from another project will mention things that don't apply (paths that don't exist, conventions you don't follow). The agent picks up on the dissonance.
Ambiguous "rules"
## Rules
- Be careful with the database.
What does "careful" mean? Specify:
## Database rules
- Migrations require approval. Don't write them; flag the need.
- Don't add NULL columns to tables with > 1M rows (use default + backfill).
- DROP statements: never. Use ALTER + soft-delete.
Missing the why
When the agent encounters an edge case, knowing the why helps it make the right call.
- Hand-roll init(from:) for every Codable type.
Why: lets old state.json files load after schema bumps.
Workflow: every schema change needs a testMigration_vN_to_vN+1 test.
The why is what makes the rule applicable to new situations.
What to put where
A common structuring question:
| Type of fact | Goes in |
|---|---|
| "I prefer concise responses" | Global ~/.claude/CLAUDE.md |
| "We use Swift 6 strict concurrency" | Project CLAUDE.md |
| "This run is auth rewrite, don't touch users module" | Session CLAUDE.md |
| "Run npm test before commit" | Project (always-true) |
| "Run npm test -- --bail" (this session only) | Session |
| "Code style: 4-space indent" | Project |
| "Don't write to main branch" | Project (always) or Session (this run) depending |
Examples to learn from
The mq-dir project's CLAUDE.md is ~120 lines covering:
- Build & test commands
- Two-module architecture
- State ownership hierarchy
- Persistence rules (with the Codable migration pattern)
- Concurrency model
- Hot files (most-edited, with line counts)
- Project conventions (style, branch naming)
- Out-of-scope list
- Internal-only paths
Each section is 5-15 lines. None are vague. The "out of scope" section is explicit and the "why" is given when non-obvious.
You can read it as part of the public mq-dir repository if you want a real example.
Maintenance
CLAUDE.md isn't write-once. Two practices:
When you re-explain something to the agent twice, add it to CLAUDE.md.
If you typed the same instruction in chat twice in one week, the third time should not be necessary. Add it as a rule in the appropriate CLAUDE.md.
When the agent makes the same mistake twice, add a counter-example.
## Pitfalls
- Don't extract auth helpers to lib/. Auth-specific code stays in auth/.
Counter-example: lib/auth-utils.ts — was wrong; moved back to auth/.
The counter-example anchors what "wrong" looks like. Better than a vague rule.
Templates
A starting template for a project CLAUDE.md:
# <Project Name>
## Build & test
- <main build command>
- <test command>
- <commit signing requirement, if any>
## Architecture
- <directory>: <one-line purpose>
- <directory>: <one-line purpose>
## Conventions
- Indent: <4 spaces / 2 spaces / tabs>
- Naming: <camelCase / snake_case>
- Branches: feat/, fix/, docs/
## Rules
- <Concrete rule 1>
- <Concrete rule 2>
## Out of scope
- <thing not to suggest>
- <thing in a different module>
## Hot files
- src/foo.ts — <purpose, ~LOC>
Customize. Cut what doesn't apply.
A starting template for session CLAUDE.md:
# Session: <verb-noun> — <date>
## Goal
<One paragraph: what we're doing this run>
## Out of scope
- <thing not in this run>
## Constraints
- <command to run before commits>
- <branch policy>
Five sections, ~15 lines.
What changes when you write good CLAUDE.md
Three things:
- Less re-explanation in chat. You stop typing "remember, we use Codable migration" because the agent reads it on session start.
- The agent stays on-rails. Scope and constraints are the boundary; the agent self-corrects when it would otherwise drift.
- Onboarding is faster. New contributors (human or AI) read CLAUDE.md and have the right context.
The compounding benefit is real. Spend an hour on a good project CLAUDE.md; save it indefinitely.
Verdict
CLAUDE.md is a small, durable productivity asset. The patterns:
- Global for personal preferences (~30 lines).
- Project for codebase rules (~100-300 lines).
- Session for current run scope (~15-30 lines).
Be specific. Include the why. Maintain it as you go. Skip the generic templates.
For a real-world example, mq-dir's CLAUDE.md is in the public repo. The shape works; the patterns transfer.
A native quad-pane macOS file manager — free, no telemetry.
v0.1.0-beta.12 · Universal Binary · 5.3 MB · macOS 14.0+
Download for MacFrequently asked questions
References
- [1]
Ready to try mq-dir?
A native quad-pane file manager built for AI multi-tasking on macOS. Free, MIT licensed, zero telemetry.
Related posts
Must-install Mac apps for productivity in 2026 (curated, not generic)
Generic 'best Mac apps' lists are everywhere. This one is curated for one criterion: each app saves 10+ minutes per day. No filler.
Setting up a new Mac for Claude Code work, end-to-end
From unboxed Mac to first Claude Code session in 90 minutes. Every step, every command, every config — the complete walkthrough.
Free Mac apps every developer should know about in 2026
Paid productivity apps get all the attention; some of the best Mac dev tools are free. Here are the ones I install before reaching for my credit card.