Playbook
The gap between a CLAUDE.md that works and one that gets ignored comes down to one question: does every line contain information Claude cannot infer from reading the code? If Claude can figure it out from the codebase, it does not belong in your instruction file.
What Gets Followed vs Ignored
Followed reliably:
# Build & Test
- Run `npm test -- --run` for unit tests (not the full suite)
- TypeCheck with `npx tsc --noEmit` after code changes
- This project uses pnpm, not npmFrequently ignored:
# Guidelines
- Write clean, maintainable code
- Follow best practices
- Be careful with edge casesThe first set contains concrete, verifiable instructions Claude cannot infer. The second is vague advice Claude already "knows." Delete every line that restates Claude's defaults.
The Test for Every Line
Before committing a CLAUDE.md change, apply this filter to each instruction:
"Would removing this line cause Claude to make a mistake it wouldn't otherwise make?"
If the answer is no, the line is wasting attention budget. Remove it.
Layering Strategy
Each scope has a purpose. Putting instructions in the wrong layer causes conflicts and wastes tokens.
User Level (~/.claude/CLAUDE.md)
Personal preferences that apply everywhere. This file should be short — under 20 lines.
# Personal Preferences
- I prefer concise explanations over verbose ones
- When committing, use conventional commit format
- I use vim keybindings -- reference vim commands when suggesting editor actions
- Default to TypeScript strict modeProject Level (./CLAUDE.md)
Team-shared, committed to version control. The highest-impact file you control.
# Project: MyApp API
## Build & Test
- `pnpm install` to set up dependencies
- `pnpm test` runs vitest (prefer single test files for speed)
- `pnpm typecheck` runs tsc --noEmit
## Architecture
- Express API in src/api/, React frontend in src/web/
- Database: PostgreSQL with Drizzle ORM
- All API routes require auth middleware (see src/middleware/auth.ts)
## Conventions
- Use barrel exports (index.ts) for each module directory
- Error responses follow RFC 7807 Problem Details format
- Date fields use ISO 8601 strings, never timestampsLocal Level (./CLAUDE.local.md)
Personal project-specific notes, gitignored. Your sandbox for experiments and local environment details.
# My Local Setup
- My dev database is at localhost:5433 (non-standard port)
- Use SANDBOX_API_KEY=sk-test-xxx for local testing
- I'm currently working on the billing module refactorSubdirectory Level (./packages/api/CLAUDE.md)
Package-specific overrides in monorepos. Loaded lazily — zero cost until Claude enters that directory.
# API Package
- This package uses Express 5 (not Express 4 like the legacy service)
- All handlers must return typed Response<T> objects
- Integration tests require REDIS_URL environment variableProduction Architectures
Monorepo
The most common architecture for teams using Claude Code at scale.
monorepo/
├── CLAUDE.md # Global: workspace structure, shared conventions
├── CLAUDE.local.md # Personal: your active focus area
├── .claude/
│ ├── settings.json # Hooks, permissions
│ └── rules/
│ ├── code-style.md # Unconditional: loaded every session
│ ├── testing.md # Unconditional: testing conventions
│ └── api-design.md # Path-scoped: only for src/api/**
├── packages/
│ ├── frontend/
│ │ └── CLAUDE.md # Frontend-specific (lazy loaded)
│ ├── api/
│ │ └── CLAUDE.md # API-specific (lazy loaded)
│ └── shared/
│ └── CLAUDE.md # Shared library rules (lazy loaded)The root CLAUDE.md should document workspace structure, list packages with their purposes, define shared conventions, and explain inter-package relationships. Keep it concise — push details into the package-level files.
Use claudeMdExcludes in .claude/settings.local.json to skip irrelevant team CLAUDE.md files:
{
"claudeMdExcludes": [
"**/packages/ios-app/CLAUDE.md",
"**/packages/legacy-service/.claude/rules/**"
]
}Full-Stack App
Path-scoped rules via .claude/rules/ are often better than subdirectory CLAUDE.md files for full-stack apps. They use glob patterns rather than requiring exact directory placement.
app/
├── CLAUDE.md # Shared: build commands, deploy process, env vars
├── .claude/
│ └── rules/
│ ├── frontend.md # paths: ["src/components/**", "src/pages/**"]
│ ├── backend.md # paths: ["src/api/**", "src/services/**"]
│ └── database.md # paths: ["src/db/**", "migrations/**"]The paths frontmatter in each rules file controls when it loads. When Claude reads a file matching src/components/Button.tsx, it triggers frontend.md — and only frontend.md. No token cost for backend or database rules during a frontend-only task.
A path-scoped rules file looks like this:
---
paths:
- "src/components/**"
- "src/pages/**"
- "src/hooks/**"
---
# Frontend Rules
- Use React Server Components by default; add 'use client' only when needed
- All components export via named exports (no default exports)
- CSS modules for component-scoped styles, Tailwind for layout utilities
- Test components with @testing-library/react, not enzymeAnd a database-scoped rule:
---
paths:
- "src/db/**"
- "migrations/**"
- "prisma/**"
---
# Database Rules
- All migrations must be reversible (include both up and down)
- Use parameterized queries exclusively — no string interpolation in SQL
- Foreign keys require explicit ON DELETE behaviorLibrary / Open Source Package
Libraries need API stability enforcement above all else.
my-library/
├── CLAUDE.md # API design principles, semver policy, test requirements
├── .claude/
│ └── rules/
│ └── public-api.md # paths: ["src/index.ts", "src/public/**"]The project CLAUDE.md should emphasize backward compatibility rules, documentation requirements for public APIs, and the semver policy. The path-scoped public-api.md adds stricter constraints that only activate when touching exported surfaces.
# my-library
## Build & Test
- `pnpm build` compiles to ESM + CJS via tsup
- `pnpm test` runs vitest (run single files for speed)
- `pnpm typecheck` runs tsc --noEmit
## Semver Policy
- Breaking changes require a major version bump and CHANGELOG entry
- All public API changes must update JSDoc annotations
IMPORTANT: Exported types in src/public/ are part of the public API.
Changing function signatures, removing exports, or renaming types is a breaking change.The @import System
CLAUDE.md files support @path/to/file imports that expand at load time:
See @README.md for project overview and @package.json for available scripts.
# Additional Instructions
- Git workflow: @docs/git-instructions.md
- Personal overrides: @~/.claude/my-project-instructions.mdKey behaviors:
- Relative paths resolve relative to the file containing the import, not the working directory
- Absolute paths and
~home directory paths work - Recursive imports supported up to 5 levels deep
- First encounter of external imports triggers an approval dialog (auto-approve with
allowedImportPathsin settings) - Imported files consume tokens at session start
{
"allowedImportPaths": [
"docs/git-instructions.md",
"~/.claude/shared-instructions.md"
]
}The critical constraint: every imported file embeds fully into context. A 500-line architecture doc costs ~5,000 tokens on every session. Only import files that are short and universally needed. For reference documentation, tell Claude to read on demand instead:
# Architecture docs are in docs/architecture.md -- read when working on structural changes.AGENTS.md Compatibility
If your repo already uses AGENTS.md for other coding agents, import it and add Claude-specific overrides:
# CLAUDE.md
@AGENTS.md
## Claude Code Specific
Use plan mode for changes under `src/billing/`.This shares a single source of truth for common instructions while adding Claude-specific behavior on top.
Rules Files vs CLAUDE.md
The .claude/rules/ directory provides an alternative to subdirectory CLAUDE.md files with one advantage: path-scoped loading via glob patterns.
| Feature | Subdirectory CLAUDE.md | .claude/rules/*.md |
|---|---|---|
| Load trigger | Claude reads files in that directory | Glob pattern match on file path |
| Scope precision | Exact directory match | Glob patterns (e.g., src/**/*.test.ts) |
| Team visibility | Visible in directory structure | Centralized in .claude/ |
| Excludable | Via claudeMdExcludes | Via claudeMdExcludes |
| Unconditional loading | Always (ancestor) or lazy (descendant) | Only when no paths: frontmatter |
Use rules files when you need cross-cutting concerns (all test files, all API routes) or when scattering CLAUDE.md files across directories would be confusing. Use subdirectory CLAUDE.md when the instructions map cleanly to a directory boundary.
An unconditional rules file (no paths: frontmatter) loads every session, identical to content in the root CLAUDE.md:
# .claude/rules/code-style.md (no paths: frontmatter = unconditional)
- Use named exports for all modules
- Prefer `interface` over `type` for object shapes
- Error messages must include the operation that failed and the reasonA cross-cutting rules file targeting all test files regardless of directory:
---
paths:
- "**/*.test.ts"
- "**/*.test.tsx"
- "**/*.spec.ts"
---
# Testing Conventions
- Use `describe` blocks grouped by method/feature
- Prefer `it.each` for parameterized tests
- Mock external services at the module boundary, not inside tests
- Test file must be co-located with the module it testsTemplate: Starting From Scratch
Run /init with CLAUDE_CODE_NEW_INIT=1 for the enhanced interactive flow that analyzes your codebase and suggests a CLAUDE.md structure. Then trim ruthlessly. A starting template:
# Project Name
## Build & Test
- `<install command>` for dependencies
- `<test command>` for unit tests (prefer single file runs)
- `<typecheck command>` for type checking
## Architecture
- [2-3 lines: where code lives, what framework, key patterns]
## Conventions
- [3-5 lines: things Claude would get wrong without being told]
IMPORTANT: [The one rule that causes the most damage when violated]Target: under 30 lines for a simple project, under 100 for a monorepo root, under 200 absolute maximum. Every line above 200 degrades performance measurably.