Configuring AI coding agents to understand your codebase
01
Everything you need at a glance. Pin this page.
| File | Location | Purpose | Shared? |
|---|---|---|---|
CLAUDE.md |
./CLAUDE.md or ./.claude/CLAUDE.md |
Team project instructions for Claude Code | Via git |
.claude/rules/*.md |
./.claude/rules/ |
Modular topic-specific rules | Via git |
CLAUDE.local.md |
./CLAUDE.local.md |
Personal project preferences | Just you |
User CLAUDE.md |
~/.claude/CLAUDE.md |
Personal all-project preferences | Just you |
| User rules | ~/.claude/rules/*.md |
Personal modular rules | Just you |
| Auto memory | ~/.claude/projects/<proj>/memory/ |
Claude's own notes about your project | Just you |
AGENTS.md |
./AGENTS.md |
OpenAI Codex CLI instructions | Via git |
GEMINI.md |
./GEMINI.md |
Google Gemini CLI instructions | Via git |
.cursorrules |
./.cursor/rules/*.mdc |
Cursor IDE rules | Via git |
copilot-instructions.md |
./.github/copilot-instructions.md |
GitHub Copilot workspace instructions | Via git |
.claude/rules/ topic files.claude /init
mkdir -p .claude/rules
cat > .claude/rules/testing.md <<'EOF'
---
paths: ["tests/**", "src/**/*.test.*"]
---
# Testing Rules
- Use pytest for all tests
- Fixtures go in conftest.py
EOF
# In Claude Code, ask:
"Show me your system prompt"
"What instructions do you have?"
wc -l CLAUDE.md .claude/rules/*.md
# Target: <200 root, <100 per rule
02
Context is a finite resource. Spend it wisely or drown in noise.
Every line of your CLAUDE.md is reprocessed with every single message in a conversation. A 500-line config file consumed at the start of each turn is not free -- it costs real tokens and real attention.
Current context window sizes shape what is possible:
| Model | Context Window | Practical Budget for Config |
|---|---|---|
| Claude Opus / Sonnet | 200K tokens | ~2-5K tokens (1-3%) |
| GPT-4o | 128K tokens | ~2-4K tokens (2-3%) |
| Gemini 2.5 Pro | 1M tokens | ~2-5K tokens (still small!) |
Even with a 1M-token window, the practical budget for instructions is the same. Larger windows do not mean you should write longer config files. The model's attention degrades with length regardless of capacity.
Large language models do not read config files the way humans read manuals. There is no "careful sequential reading." Instead, instructions compete for attention weight. When your CLAUDE.md is 500 lines, important rules get lost in the noise -- the model gives each line roughly equal weight, and critical instructions become needles in a haystack.
For every line in your config, ask: "Would removing this cause the agent to make mistakes?"
If the answer is no, delete it. The agent already knows it, or it does not matter enough to spend context on.
A lean 50-line CLAUDE.md consistently outperforms a 500-line one. The shorter file has higher signal density -- every line matters, so the model pays attention to every line.
Think of your context configuration like a resume, not an autobiography. The best resumes are one page. The best CLAUDE.md files are under 200 lines. They include only what the agent cannot infer from the code itself.
pnpm test before committing" (agent cannot guess your package manager)Everything competes for the same context window. Here is a rough breakdown of what fills it during a typical Claude Code session:
The "Conversation + tool use" segment grows with every message. The more tokens you consume with static config, the fewer you have for actual work. Bloated config means shorter effective conversations before the context window fills up.
Bloated context is not just an attention problem -- it is a cost problem. If your CLAUDE.md adds 3,000 extra tokens and you send 100 messages per session, that is 300,000 wasted input tokens per session. At scale, this adds up fast.
03
CLAUDE.md and its ecosystem: how files are discovered, loaded, and prioritized.
Claude Code reads CLAUDE.md files recursively up the directory tree from your current working directory to the filesystem root. This means a monorepo can have layered config:
/
CLAUDE.md ← loaded (ancestor)
mycompany/
CLAUDE.md ← loaded (ancestor)
myproject/
CLAUDE.md ← loaded (project root = cwd)
.claude/
CLAUDE.md ← loaded (alternate location)
rules/
testing.md ← loaded (project rule)
deployment.md ← loaded (project rule)
frontend/
CLAUDE.md ← loaded on demand (child)
backend/
CLAUDE.md ← loaded on demand (child)
Ancestor directory files (above cwd) are loaded in full at launch. Child directory files (below cwd) are loaded on demand when Claude reads files in those subtrees. This means your frontend/CLAUDE.md only takes effect when Claude is actually working in that directory.
When instructions conflict, higher specificity wins. The full priority chain from lowest to highest:
| Priority | Source | Scope |
|---|---|---|
| 1 (lowest) | Managed policy (enterprise settings) | Organization |
| 2 | ~/.claude/CLAUDE.md (user global) |
All projects |
| 3 | ~/.claude/rules/*.md (user rules) |
All projects |
| 4 | ./CLAUDE.md (project root) |
This repo |
| 5 | ./.claude/rules/*.md (project rules) |
This repo |
| 6 | ./CLAUDE.local.md |
This repo, just you |
| 7 (highest) | Auto memory (~/.claude/projects/) |
This repo, just you |
In practice, this means your CLAUDE.local.md can override team conventions for your personal workflow, and Claude's own learned memory takes highest priority since it reflects the most recent corrections.
There is no hard character limit on CLAUDE.md, but 200 lines is the practical ceiling for your root config. Beyond that, signal degrades. Here is what belongs in root and what does not:
pnpm test, cargo build)CLAUDE.md supports an @import syntax to pull in content from other files using relative paths. This keeps your root file lean while referencing detailed docs:
# CLAUDE.md
## Build
Run `pnpm build` to compile. Run `pnpm test` to test.
## Architecture
@docs/architecture.md
## API Conventions
@docs/api-conventions.md
## Style
- Use kebab-case for files
- Components in PascalCase
- See .claude/rules/ for language-specific rules
Imports resolve relative paths from the file containing the @ directive. There is a maximum depth of 5 hops to prevent circular references. Each imported file counts against your context budget, so keep them focused.
Files in .claude/rules/ can include YAML frontmatter with a paths field. This scopes the rule so it only activates when Claude is working with matching files:
# .claude/rules/frontend-testing.md
---
paths: ["src/components/**", "src/hooks/**", "**/*.test.tsx"]
---
# Frontend Testing Rules
- Use React Testing Library, never Enzyme
- Test user behavior, not implementation details
- Mock API calls with msw
- Every component needs at least one render test
# .claude/rules/database.md
---
paths: ["src/db/**", "migrations/**", "*.sql"]
---
# Database Rules
- All migrations must be reversible
- Use parameterized queries, never string interpolation
- Index any column used in WHERE clauses
Path-scoped rules load only when relevant files are being worked on, which keeps the effective context lean even if you have dozens of rule files.
The /init command in Claude Code analyzes your repository and generates a starter CLAUDE.md. It inspects your package manager, test runner, directory structure, and existing configuration to produce a focused initial config.
# In Claude Code, run:
/init
# Claude will:
# 1. Scan your repo structure
# 2. Detect build tools, test frameworks, linters
# 3. Generate a ~30-50 line CLAUDE.md
# 4. Ask you to review and customize
Run /init even on existing projects. Compare its output to your current CLAUDE.md. If /init produces something shorter that works just as well, your original was probably too verbose.
Here is what a clean, effective root config looks like for a real project:
# CLAUDE.md
## Build & Test
- `pnpm install` -- install deps
- `pnpm dev` -- start dev server (port 3000)
- `pnpm test` -- run vitest (no watch mode in CI)
- `pnpm lint` -- eslint + prettier check
## Stack
Next.js 14 (App Router), TypeScript strict, Tailwind, Prisma + Postgres
## Structure
src/app/ -- routes (App Router)
src/components/ -- shared React components
src/lib/ -- utilities and helpers
src/db/ -- Prisma schema and queries
tests/ -- integration tests (Playwright)
## Conventions
- File names: kebab-case
- Components: PascalCase, one per file
- Server actions in `actions.ts` files adjacent to routes
- Prefer server components; add "use client" only when needed
## Gotchas
- Auth middleware in `src/middleware.ts` -- do not rename
- `NEXT_PUBLIC_` prefix required for client env vars
- Prisma generates types on `pnpm install` -- re-run after schema changes
That is roughly 25 lines. Everything Claude needs, nothing Claude can figure out on its own. No tutorials, no generic advice, no explaining what Next.js is.
04
Structure your project knowledge like your code: layered, scoped, and discoverable.
Claude Code reads CLAUDE.md files recursively up the directory tree from your current working directory all the way to /. Files closer to where you are working take precedence over files higher up. Child-directory CLAUDE.md files are loaded lazily -- only when Claude reads files inside those subtrees.
Here is the loading model in practice. Suppose you launch Claude Code inside myproject/src/api/:
# Loaded at launch (ancestors of cwd):
/myproject/CLAUDE.md # project-wide rules
/myproject/src/CLAUDE.md # source-level conventions
/myproject/src/api/CLAUDE.md # API-specific patterns (cwd)
# Loaded on demand (when Claude explores these directories):
/myproject/tests/CLAUDE.md # only if Claude reads test files
/myproject/frontend/CLAUDE.md # only if Claude reads frontend files
This means you get zero-cost specificity. You can scatter dozens of CLAUDE.md files throughout your repo and they will not bloat context until Claude actually needs them. The lazy loading is what makes this system scalable.
Child CLAUDE.md files are FREE until accessed. Use them liberally to provide module-level context. A 50-directory monorepo with 20 CLAUDE.md files costs the same as one with 1, until Claude enters those directories.
Here is what a well-structured monorepo looks like with full context layering. Every CLAUDE.md file has a specific scope and purpose:
myproject/
├── CLAUDE.md # Project-wide: git workflow, CI, naming
├── .claude/
│ ├── CLAUDE.md # Alternative location (same as root)
│ └── rules/
│ ├── code-style.md # Unconditional: applies everywhere
│ ├── security.md # Unconditional: auth patterns
│ └── api-endpoints.md # Path-scoped (see frontmatter below)
│ # ---
│ # paths:
│ # - "src/api/**/*.ts"
│ # ---
├── CLAUDE.local.md # Personal: my sandbox URLs, test data
│
├── frontend/
│ ├── CLAUDE.md # React patterns, component conventions
│ ├── src/
│ │ └── components/
│ │ └── CLAUDE.md # Component naming, prop patterns
│ └── tests/
│ └── CLAUDE.md # Frontend test conventions (vitest)
│
├── backend/
│ ├── CLAUDE.md # Express patterns, middleware conventions
│ ├── src/
│ │ ├── routes/
│ │ │ └── CLAUDE.md # Route naming, validation patterns
│ │ └── models/
│ │ └── CLAUDE.md # Schema conventions, migration rules
│ └── tests/
│ └── CLAUDE.md # Backend test conventions (jest)
│
└── shared/
└── CLAUDE.md # Shared types, utility conventions
Notice the pattern: the root file is project-wide, each top-level directory owns its domain, and deeply nested files handle specialized concerns. Claude only ever loads what it needs.
The root file should be short, focused, and universally applicable. If an instruction does not apply to every file in the repo, it does not belong here.
# MyProject
## Build & Test
- `pnpm install` -- install all workspaces
- `pnpm build` -- build all packages
- `pnpm test` -- run all tests
- `pnpm lint` -- eslint + prettier check
## Git Workflow
- Branch from main, PR required for merge
- Commit messages: conventional commits (feat:, fix:, chore:)
- All PRs need passing CI before merge
## Architecture
- Monorepo: frontend/ (React), backend/ (Express), shared/ (types)
- Frontend and backend import from shared/ -- never cross-import
- See subdirectory CLAUDE.md files for module-specific conventions
That is it. Twenty lines. Build commands, git workflow, and the one architectural constraint that matters everywhere (no cross-imports). Everything else lives in subdirectory files or .claude/rules/.
If it does not apply to EVERY file in the repo, move it down. API validation rules do not belong in root -- they belong in backend/src/routes/CLAUDE.md or a path-scoped rule.
Subdirectory files are scoped to their module. They can assume the parent context is already loaded and focus on what is different or specific to their directory.
# Backend (Express + TypeScript)
## Patterns
- All routes in src/routes/, one file per resource
- Middleware chain: auth -> validate -> handler -> error
- Database queries in src/models/, never in route handlers
## Testing
- Jest with supertest for API endpoints
- Test files mirror src/ structure in tests/
- Mock external services, never hit real APIs in tests
# React Components
## Naming
- PascalCase for component files and exports
- Props interface: ComponentNameProps
- One component per file, co-locate styles
## Patterns
- Prefer server components; add "use client" only when needed
- Custom hooks in adjacent hooks/ directory
- Barrel exports via index.ts per feature folder
Each file is lean -- 10-15 lines of highly specific instructions. Claude only loads these when it enters the relevant directory, so they are essentially free context until needed.
For cross-cutting concerns that do not map cleanly to a single directory, use .claude/rules/. Each file in this directory is a modular rule that can be either unconditional (applies always) or path-scoped (applies only to matching files).
Unconditional rules have no paths: frontmatter and apply everywhere:
# Code Style
- Use 2-space indentation for TypeScript, 4-space for Python
- Prefer const over let; never use var
- No default exports except for pages and layouts
- Import order: stdlib -> external -> internal -> relative
Path-scoped rules include YAML frontmatter with paths: globs. They only activate when Claude works with files matching those patterns:
---
paths:
- "src/api/**/*.ts"
- "src/routes/**/*.ts"
---
# API Development Rules
- All endpoints must validate input with zod schemas
- Return standard error format: { error: string, code: number }
- Include OpenAPI JSDoc comments on all public endpoints
- Rate limiting middleware required on all public routes
- Use async/await, never raw Promise chains
Path scoping supports glob patterns, brace expansion (*.{ts,tsx}), and recursive matching (**). You can organize rules into subdirectories within .claude/rules/ -- they are discovered recursively.
| Pattern | What It Matches |
|---|---|
"src/**/*.ts" |
All TypeScript files under src/ |
"*.{ts,tsx}" |
All TS/TSX files at any level |
"tests/**" |
Everything in tests/ directory |
"src/api/**/*.ts" |
TypeScript files specifically in src/api/ |
"**/*.test.*" |
All test files regardless of location |
If you maintain multiple projects with shared conventions, you can use symlinks in .claude/rules/ to point to a central rule library:
# Central rule library (e.g., in a shared-configs repo)
~/shared-rules/
├── typescript-style.md
├── security-patterns.md
└── testing-conventions.md
# Symlink into each project
cd myproject/.claude/rules/
ln -s ~/shared-rules/typescript-style.md .
ln -s ~/shared-rules/security-patterns.md .
# Or symlink the whole directory
ln -s ~/shared-rules/ .claude/rules/shared/
This keeps your team's conventions in one canonical location while each project inherits them through symlinks. Changes to the source propagate instantly.
Instead of copying content into CLAUDE.md, use @import to reference existing documentation. This is ideal when you already have well-maintained docs that Claude should follow:
# CLAUDE.md
## Build
Run `pnpm build` to compile all packages.
## Architecture
@docs/architecture.md
## API Reference
@docs/api-conventions.md
## Database
@docs/database-schema.md
Key rules for imports:
@ directiveIf a doc changes frequently and is maintained by another team, @import it. If it is stable and you own it, consider inlining the key points. Imports always pull the latest version, which is both a strength and a risk.
05
Every AI coding agent has its own config system. Here is how they all compare.
The AI coding agent space has fragmented into multiple config file formats. This table compares every major tool as of early 2026:
| Tool | Config File | Location | Format | Hierarchy | Size Limit | Import | Glob Scope |
|---|---|---|---|---|---|---|---|
| Claude Code | CLAUDE.md |
Any directory | Markdown | 5+ levels | None (soft ~200 lines) | @import |
paths: YAML |
| Codex CLI | AGENTS.md |
Any directory | Markdown | Recursive up | 32KB | None | None |
| Gemini CLI | GEMINI.md |
Any directory | Markdown | Recursive up | None specified | context.fileName |
None |
| Cursor | .cursor/rules/*.mdc |
.cursor/ |
MDC (YAML+MD) | Flat | None specified | @file |
globs: YAML |
| Windsurf | .windsurf/rules/*.md |
.windsurf/ |
Markdown | Flat | 12K chars total | None | trigger: YAML |
| Aider | .aider.conf.yml |
Root + home | YAML | 2 levels | None specified | read: key |
None |
| GitHub Copilot | copilot-instructions.md |
.github/ |
Markdown | Flat | ~2 pages | None | applyTo: YAML |
paths: frontmatter for file-type scoping~/.claude/projects/lint-cmd and test-cmd keys run checks automatically after editsMost teams use multiple AI tools. Here is which tools can read which other tools' config files natively:
| Reader | Can Natively Read | How |
|---|---|---|
| Gemini CLI | CLAUDE.md, AGENTS.md, .cursorrules, any file | context.fileName config |
| Aider | Any file (CLAUDE.md, AGENTS.md, etc.) | read: key in .aider.conf.yml |
| Claude Code | Only CLAUDE.md + .claude/rules/ | Native discovery |
| Codex CLI | Only AGENTS.md | Native discovery |
| Cursor | Only .cursor/rules/*.mdc | Native discovery |
If your team uses multiple AI coding agents, you need a strategy for sharing context without maintaining duplicate files. Here are the proven approaches:
# Maintain one source of truth
ln -s CLAUDE.md AGENTS.md
ln -s CLAUDE.md GEMINI.md
# All three tools read the same file
# CLAUDE.md
@docs/shared-context.md
# Claude-specific rules below...
# .aider.conf.yml
read: [docs/shared-context.md]
# .gemini/settings.json
{
"context": {
"fileName": ["CLAUDE.md"]
}
}
# Gemini inherits Claude's config
# AGENTS.md is the open standard
# Many tools are adding support
# Use it as the shared base,
# add tool-specific files as needed
Start with CLAUDE.md as your primary (it has the richest feature set), then symlink to AGENTS.md and GEMINI.md. Tool-specific rules go in their native format. This gives you one source of truth with per-tool extensions.
06
Getting the right information at the right time. Not everything needs to load at startup.
Loading every instruction at startup is wasteful. A frontend developer editing React components does not need backend database migration rules in context. A developer writing tests does not need deployment conventions cluttering the prompt.
The solution is progressive disclosure: context that arrives precisely when needed, not before. Claude Code offers a full stack of mechanisms for this, from static file-based rules to dynamic runtime hooks.
Context injection mechanisms, ordered from static (always available, file-based) to dynamic (runtime, computed):
The simplest form of progressive disclosure. Rules in .claude/rules/ with paths: frontmatter only activate when Claude works with matching files. Zero overhead when irrelevant.
# .claude/rules/react-components.md
---
paths:
- "src/components/**/*.tsx"
- "src/hooks/**/*.ts"
---
# React Component Rules
- Server components by default; "use client" only when needed
- Props interface named ComponentNameProps
- Co-locate styles, tests, and stories with components
These rules are invisible to Claude until it opens a file matching the glob pattern. You can have 50 path-scoped rules with zero startup cost.
Lazy-loaded when Claude explores that area of the codebase. Perfect for module-level documentation that is too detailed for root config but too important to omit entirely.
# backend/src/models/CLAUDE.md
# Only loaded when Claude reads files in backend/src/models/
# Database Models
- Prisma schema in prisma/schema.prisma
- Every model needs createdAt and updatedAt timestamps
- Soft deletes: use deletedAt field, never hard delete
- Migration naming: YYYYMMDD_description.sql
Referenced documentation pulled in on demand. Use this when you already maintain comprehensive docs and want Claude to follow them without duplicating content.
# CLAUDE.md
## API Design
@docs/api-style-guide.md
## Database Conventions
@docs/database-patterns.md
The imported files are resolved and injected when CLAUDE.md is loaded. Keep imported files focused -- a 500-line API doc pulls its entire weight into context.
Reusable prompt templates that inject task-specific context on demand. Skills are Markdown files in .claude/skills/ that can preprocess shell commands using ! backtick syntax to pull in live data:
# .claude/skills/pr-summary.md
---
name: pr-summary
context: fork
agent: Explore
---
## PR Context
- Diff: !`gh pr diff`
- Comments: !`gh pr view --comments`
## Task
Summarize this PR: what changed, why, and any risks.
Skills are invoked explicitly (via slash commands or the skills menu), so they carry no cost until triggered. The ! backtick syntax runs shell commands at invocation time and injects the output, giving Claude live context about the current state of things.
Deterministic lifecycle automation that runs at specific points during a Claude Code session. Unlike instructions (which are suggestions), hooks are enforced -- they run every time, regardless of what the model decides.
// .claude/settings.json
{
"hooks": {
"PostToolUse": [{
"matcher": "Edit|Write",
"hooks": [{
"type": "command",
"command": "npx eslint --fix $CLAUDE_FILE_PATH"
}]
}]
}
}
Available hook points in the lifecycle:
| Hook | When It Fires | Use Case |
|---|---|---|
SessionStart |
When a Claude Code session begins | Inject environment context, check prerequisites |
PreToolUse |
Before Claude runs any tool | Block dangerous operations, validate inputs |
PostToolUse |
After Claude runs a tool | Run linters after edits, auto-format files |
UserPromptSubmit |
When the user sends a message | Augment prompts with project context, inject timestamps |
The matcher field uses regex to filter which tools trigger the hook. "Edit|Write" fires on file edits. "Bash" fires on shell commands. Omitting the matcher fires on every tool use.
Isolated context windows for delegated tasks. Subagents run in a forked context with a restricted tool set, which means they do not pollute the main conversation's context window.
# .claude/skills/security-reviewer.md
---
name: security-reviewer
tools: Read, Grep, Glob
model: haiku
---
Review the specified files for OWASP Top 10 vulnerabilities.
Focus on: injection, broken auth, sensitive data exposure,
XXE, broken access control, security misconfiguration.
Report findings as a numbered list with severity (High/Medium/Low)
and the specific file + line number.
Subagents are ideal for specialized tasks that need deep focus: security review, documentation generation, test writing. They can use a smaller model (like Haiku) for cost efficiency, and their results are summarized back to the main conversation.
.claude/rules/!backtick preprocessingThe general rule: start static, go dynamic only when you need to. Most projects only need CLAUDE.md + a few path-scoped rules. Add skills and hooks when your workflow demands them. Subagents are for advanced use cases with clear delegation boundaries.
If it is always relevant -- CLAUDE.md. If it is file-type relevant -- path-scoped rule. If it is task-relevant -- skill. If it must be enforced -- hook.
07
Auto-memory system and session persistence. How Claude remembers across conversations.
~/.claude/projects/<project>/memory/
├── MEMORY.md # Index -- first 200 lines loaded every session
├── debugging.md # Detailed notes (loaded on demand)
├── api-conventions.md # API decisions (loaded on demand)
└── patterns.md # Code patterns discovered
<project> path derived from git repo root — all subdirs share one memory dirBuild commands, test conventions, code style preferences, package manager choices
Solutions to tricky problems, root causes of recurring errors, workarounds discovered
Key files, module relationships, abstraction layers, data flow patterns
Communication style, workflow habits, tool choices, naming conventions
/memory
"remember that we use pnpm, not npm"
CLAUDE_CODE_DISABLE_AUTO_MEMORY=0
CLAUDE_CODE_DISABLE_AUTO_MEMORY=1
| Phase | What Happens |
|---|---|
| Session start | Loads all ancestor CLAUDE.md files + .claude/rules/ + first 200 lines of MEMORY.md + skill descriptions |
| During session | Lazy-loads child CLAUDE.md files when entering subdirs. Reads topic memory files on demand. |
| Compaction | When context gets large, earlier messages are compressed to make room. Critical instructions survive because they are in config, not conversation. |
| Session end | Memory files may be updated with new discoveries. No conversation history persists across sessions. |
When compaction kicks in, your conversation history gets summarized — but your CLAUDE.md and rules are re-injected fresh. This is why persistent instructions belong in config files, not in "remember this" messages.
08
Writing instructions for machines vs humans. They are not the same audience.
CLAUDE.md is for the LLM agent. README.md is for human developers. They have different audiences, different formats, different goals.
pnpm test -- --watch"## Authentication
Our authentication system uses JWT tokens with refresh
token rotation. We chose this approach in Q3 2024 after
evaluating OAuth2, SAML, and session-based auth. The
decision was driven by our microservices architecture...
## Auth
- JWT + refresh token rotation
- Auth middleware: src/middleware/auth.ts
- Token refresh endpoint: POST /api/auth/refresh
- Never store tokens in localStorage -- use httpOnly cookies
| Strategy | When to Use | Example |
|---|---|---|
| Inline | Commands, conventions, patterns Claude needs every session | Always use pnpm, never npm |
| @import / link | API docs, architecture docs, schema descriptions | See @docs/api.md for endpoints |
| Do not include | Changelogs, migration history, design rationale | Keep in README.md or wiki only |
Use "IMPORTANT:" or "YOU MUST" for critical rules. Claude weighs these tokens more heavily during instruction following. Reserve them for rules that truly matter — overuse dilutes their power.
# Normal instruction
- Use 2-space indentation in TypeScript files
# High-priority instruction
IMPORTANT: Never commit .env files or expose API keys in code.
YOU MUST run `pnpm lint` before committing any changes.
09
The danger zone. These mistakes will rot your context quality over time.
One massive file that covers testing, deployment, API conventions, code style, architecture, and your team's lunch preferences. Claude has to parse all of it every turn, even when editing a CSS file.
Fix: Split by concern into .claude/rules/ and subdirectory CLAUDE.md files. The root file should be an index, not an encyclopedia.
"Use webpack.config.js for bundling" — but you switched to Vite six months ago. Claude follows stale instructions with confidence, producing code that does not work.
Fix: Treat CLAUDE.md as living code — update it on the same PR as the change it references.
"Always use semicolons" in CLAUDE.md, plus an ESLint rule that enforces it. Now you have two sources of truth. When the linter rule changes, the CLAUDE.md instruction becomes a lie.
Fix: Trust your linters. Only document what tools cannot enforce. Use hooks for the rest.
You pasted your entire OpenAPI spec into CLAUDE.md because "Claude needs to know the API." Now every message costs 10x more tokens and Claude's attention is diluted across 2000 lines of endpoint definitions.
Fix: Use @imports or reference links. "See @docs/api.md for endpoint details" — Claude will read it when it needs it.
Every sprint adds new rules. Nobody removes old ones. After a year, your CLAUDE.md is a geological record of every decision ever made, including ones that were reversed two quarters ago.
Fix: Review quarterly. For each line ask: "Would removing this cause mistakes?" If no, delete it.
Documenting every function signature, type definition, and module export in CLAUDE.md. Claude can read your code. It does not need you to transcribe it into config.
Fix: Document intent, conventions, and non-obvious relationships. Let the code speak for itself on structure.
Generic personality prompts that waste tokens without changing behavior. Claude already reasons carefully, already writes production-quality code, already thinks before acting.
Fix: Replace vague personality instructions with concrete rules. "Use dependency injection" beats "think like a senior architect."
"We are currently migrating from REST to GraphQL, so all new endpoints should be..." This belongs in the conversation or a temporary ticket, not in a config file that persists after the migration is complete.
Fix: Task context belongs in the conversation, not config files. When the migration is done, the instruction becomes The Museum.
10
When context goes wrong. Symptoms, causes, and fixes.
| Symptom | Likely Cause | Fix |
|---|---|---|
| Claude ignores specific rules | Rule buried in long config | Move to top of file or use IMPORTANT: prefix |
| Claude follows rule early but not late in session | Session context rot / compaction | Start fresh session, keep config lean |
| Same question, different answers each time | Contradicting instructions across files | Audit for conflicts across all CLAUDE.md files |
| Claude makes obvious style mistakes | Missing or stale style rules | Add specific rules or trust linter hooks |
| High token usage, slow responses | Bloated config + memory files | Audit and trim all context files |
| Claude does not know project patterns | Missing or too-general CLAUDE.md | Add specific build/test/deploy commands |
/memory
/context
wc -l CLAUDE.md
# Target: under 200 lines
find . -name "CLAUDE.md" | head -20
find .claude/rules -name "*.md" 2>/dev/null
When context is thoroughly confused and Claude keeps making the same mistakes despite correct config:
/clear or open a new terminal windowContext engineering is not a one-time setup. It is an ongoing practice — like maintaining a garden. Prune what is dead, water what is growing, and never let the weeds take over.
The best CLAUDE.md files are short, specific, and always current. They earn every line by preventing real mistakes. Everything else is noise.