← Tech Guides
* * ~> *

Context Management

Configuring AI coding agents to understand your codebase

Quick Reference

Everything you need at a glance. Pin this page.

Key Files

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

Golden Rules

The Five Commandments of Context
  • Keep root CLAUDE.md under 200 lines. If it scrolls, it is too long. Move details into .claude/rules/ topic files.
  • Put specifics in modular rule files. One file per concern: testing, deployment, code style, API conventions.
  • Delete any instruction the agent already follows. If Claude already writes TypeScript with strict mode, do not tell it to. Redundant instructions waste tokens and add noise.
  • Old or wrong context is worse than no context. Stale build commands, renamed directories, deprecated APIs -- these actively cause mistakes. Audit quarterly.
  • Use hooks for enforcement, not instructions for requests. If a rule must always be followed (linting, formatting), make it a pre-commit hook, not a polite suggestion in CLAUDE.md.

Quick Commands

Bootstrap a new project
claude /init
Add a modular rule
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
Check what Claude sees
# In Claude Code, ask:
"Show me your system prompt"
"What instructions do you have?"
Audit context size
wc -l CLAUDE.md .claude/rules/*.md
# Target: <200 root, <100 per rule

Why Context Matters

Context is a finite resource. Spend it wisely or drown in noise.

Token Economics

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.

The Attention Problem

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.

The Litmus Test

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.

Quality vs. Quantity

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.

  • Good: "Run pnpm test before committing" (agent cannot guess your package manager)
  • Good: "Use snake_case for Python variables" (only if your codebase mixes styles)
  • Bad: "Write clean, maintainable code" (the agent already does this)
  • Bad: "Use descriptive variable names" (standard practice, no need to state)
  • Bad: "Follow PEP 8" (Claude already knows PEP 8)

Context Budget

Everything competes for the same context window. Here is a rough breakdown of what fills it during a typical Claude Code session:

System prompt
CLAUDE.md + rules
Memory
Skills
Conversation + tool use
File contents

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.

Cost Implications

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.

Config Files

CLAUDE.md and its ecosystem: how files are discovered, loaded, and prioritized.

How Discovery Works

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.

Priority Order

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.

The 200-Line Limit

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:

Include in CLAUDE.md
  • Build and test commands (pnpm test, cargo build)
  • Repo-specific style rules that deviate from language defaults
  • Architecture decisions the agent needs to know
  • Known gotchas and workarounds
  • File naming conventions
  • Deployment patterns
Do NOT include in CLAUDE.md
  • Things Claude infers from reading the code
  • Standard language conventions (PEP 8, Go formatting)
  • Tutorials or explanations of concepts
  • Changelogs or version history
  • Generic advice ("write clean code")
  • Copy-pasted documentation from external tools

@imports

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.

Modular Rules with YAML Frontmatter

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.

Bootstrapping with /init

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
Pro Tip

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.

Example: Well-Structured CLAUDE.md

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.

Modular Context Architecture

Structure your project knowledge like your code: layered, scoped, and discoverable.

The Recursive Reading Model

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.

Key Principle

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.

Full-Stack Monorepo Example

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.

Example Root CLAUDE.md

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/CLAUDE.md (~20 lines)
# 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/.

Root CLAUDE.md Litmus Test

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.

Example Subdirectory CLAUDE.md

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/CLAUDE.md (~15 lines)
# 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
frontend/src/components/CLAUDE.md (~12 lines)
# 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.

The .claude/rules/ System

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:

.claude/rules/code-style.md (unconditional)
# 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:

.claude/rules/api-endpoints.md (path-scoped)
---
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

Symlinks and Sharing

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.

The @import System

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:

  • Paths are resolved relative to the file containing the @ directive
  • Maximum depth of 5 hops to prevent circular references (imports can import, up to 5 levels deep)
  • Imported content counts against your context budget, so keep referenced files focused
  • Use imports to avoid duplicating docs you already maintain -- do not create files just for importing
Import vs. Copy

If 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.

Multi-Tool Landscape

Every AI coding agent has its own config system. Here is how they all compare.

Comparison Matrix

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

Claude Code

The deepest hierarchy, the richest feature set
  • 5+ hierarchy levels: user global, user rules, project root, project rules, subdirectories, local overrides, auto memory
  • @imports: pull in existing documentation without copying (max depth 5)
  • .claude/rules/ with paths: frontmatter for file-type scoping
  • Auto memory: Claude stores project-specific learnings in ~/.claude/projects/
  • Skills & hooks: reusable prompt templates and lifecycle automation
  • Subagents: isolated context windows for delegated tasks

Codex CLI (OpenAI)

The vendor-neutral open standard
  • AGENTS.md: open standard under the Linux Foundation, intentionally vendor-neutral
  • Recursive discovery: reads AGENTS.md files up the directory tree, similar to CLAUDE.md
  • Override files: local override mechanism for personal preferences
  • 32KB hard limit: per-file size cap enforced by the tool
  • No import system: each file must be self-contained
  • Simplest format: plain Markdown, no frontmatter, no special syntax

Gemini CLI (Google)

The most flexible cross-tool reader
  • GEMINI.md: native config format, recursive up the directory tree
  • context.fileName: can be configured to read other tools' files (CLAUDE.md, AGENTS.md, .cursorrules)
  • /memory show: built-in debugging command to inspect loaded context
  • Cross-tool aware: designed from the start to coexist with other agents
  • No glob scoping: all rules apply unconditionally (as of early 2026)

Cursor

Four activation modes for fine-grained control
  • .cursor/rules/*.mdc: MDC format (YAML frontmatter + Markdown body)
  • 4 activation modes: Always (always loaded), Auto-Attach (by glob), Agent (model decides), Manual (user invokes)
  • globs: frontmatter: file pattern matching, similar to Claude's paths: but with different activation semantics
  • @file references: inline file content into rules
  • Flat hierarchy: no recursive directory scanning, all rules in one location

Windsurf

Cascade Memories and strict limits
  • .windsurf/rules/*.md: Markdown files with YAML frontmatter
  • Cascade Memories: auto-generated context from past interactions (similar to Claude's auto memory)
  • 12K character total limit: all rules combined cannot exceed this -- the strictest budget of any tool
  • trigger: frontmatter: activation conditions including glob patterns and manual triggers
  • Flat hierarchy: no recursive scanning, all rules in the .windsurf/ directory

Aider

YAML config with multi-model support
  • .aider.conf.yml: YAML format, not Markdown -- the only major tool using structured config
  • read: key: can reference any file to include as context, making it highly flexible for imports
  • Multi-model tiers: configure different models for different tasks (architect, editor, weak-model)
  • Built-in lint/test: lint-cmd and test-cmd keys run checks automatically after edits
  • 2-level hierarchy: home directory config + project-level config, merged at runtime

GitHub Copilot

Integrated into the GitHub ecosystem
  • .github/copilot-instructions.md: single file in the .github/ directory
  • applyTo: frontmatter: file pattern matching for scoped instructions
  • excludeAgent: opt specific agents out of certain rules
  • ~2 page soft limit: beyond this, instructions are truncated or ignored
  • Flat hierarchy: no recursive scanning, just the one file (plus VS Code settings)

Cross-Tool Compatibility

Most 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

Multi-Tool Strategies

If your team uses multiple AI coding agents, you need a strategy for sharing context without maintaining duplicate files. Here are the proven approaches:

Symlink Approach
# Maintain one source of truth
ln -s CLAUDE.md AGENTS.md
ln -s CLAUDE.md GEMINI.md

# All three tools read the same file
Shared Base + Imports
# CLAUDE.md
@docs/shared-context.md
# Claude-specific rules below...

# .aider.conf.yml
read: [docs/shared-context.md]
Gemini Reads All
# .gemini/settings.json
{
  "context": {
    "fileName": ["CLAUDE.md"]
  }
}
# Gemini inherits Claude's config
AGENTS.md as Common Denominator
# AGENTS.md is the open standard
# Many tools are adding support
# Use it as the shared base,
# add tool-specific files as needed
Practical Advice

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.

Progressive Disclosure

Getting the right information at the right time. Not everything needs to load at startup.

The Problem

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.

The Solution Stack

Context injection mechanisms, ordered from static (always available, file-based) to dynamic (runtime, computed):

1. Path-Scoped Rules

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.

2. Subdirectory CLAUDE.md

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

3. @imports

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.

4. Skills

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.

5. Hooks

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.

6. Subagents

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.

Decision Guide

When to Use What
  • Always relevant to all files? Put it in root CLAUDE.md
  • Relevant to a specific file type? Path-scoped rule in .claude/rules/
  • Relevant to a specific module? Subdirectory CLAUDE.md
  • Relevant to a specific task? Skill with !backtick preprocessing
  • Must be enforced every time? Hook (not an instruction)
  • Needs deep focus in isolation? Subagent with restricted tools

The 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.

The Progressive Disclosure Mantra

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.

Memory & Sessions

Auto-memory system and session persistence. How Claude remembers across conversations.

Auto Memory Location

~/.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 dir
  • First 200 lines of MEMORY.md injected into system prompt at session start
  • Topic files are NOT loaded at startup — Claude reads them on demand
  • Claude reads AND writes memory files during sessions (live updates)
  • Git worktrees get separate memory directories

What Claude Saves Automatically

Project Patterns

Build commands, test conventions, code style preferences, package manager choices

Debugging Insights

Solutions to tricky problems, root causes of recurring errors, workarounds discovered

Architecture Notes

Key files, module relationships, abstraction layers, data flow patterns

User Preferences

Communication style, workflow habits, tool choices, naming conventions

Managing Memory

Open memory in editor
/memory
Tell Claude directly
"remember that we use pnpm, not npm"
Force auto-memory on
CLAUDE_CODE_DISABLE_AUTO_MEMORY=0
Force auto-memory off
CLAUDE_CODE_DISABLE_AUTO_MEMORY=1

MEMORY.md Best Practices

The 200-Line Index
  • Keep it under 200 lines — that is the hard cutoff for auto-loading
  • Use it as an INDEX — link to topic files for details
  • Organize semantically by topic, not chronologically
  • Topic files can be any length — they are loaded on demand
  • Do not duplicate CLAUDE.md — memory is for discovered patterns, not prescribed rules

Session Lifecycle

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.
Why Compaction Matters for Config

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.

LLM Docs vs Human Docs

Writing instructions for machines vs humans. They are not the same audience.

The Core Principle

CLAUDE.md is for the LLM agent. README.md is for human developers. They have different audiences, different formats, different goals.

LLM Instructions (CLAUDE.md)
  • Imperative: "Use 2-space indentation"
  • Specific: "Run pnpm test -- --watch"
  • Structured: Headers, bullets, code blocks
  • Concise: Every line pays rent
  • Actionable: "If X, do Y" patterns
Human Docs (README.md)
  • Descriptive: Explain why, not just what
  • Narrative: Onboarding flow, guides
  • Visual: Screenshots, diagrams
  • Comprehensive: Edge cases, rationale
  • Historical: Cover decisions, context

Side-by-Side Comparison

BAD — Human-style in CLAUDE.md
## 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...
GOOD — LLM-style in CLAUDE.md
## 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

When to Link vs Inline

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

The EMPHASIS Trick

Weight Your Words

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.

Anti-Patterns

The danger zone. These mistakes will rot your context quality over time.

1. The Monolith

1000+ line root CLAUDE.md with everything

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.

2. The Museum

Config referencing old APIs, deprecated tools, removed files

"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.

3. The Duplicator

Same rules in CLAUDE.md AND in linter config

"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.

4. The Encyclopedia

Full API docs, architecture docs, schemas inlined in CLAUDE.md

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.

5. The Accumulator

Config that only grows, never shrinks

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.

6. The Mirror

Duplicating info obvious from the code

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.

7. The Personality

"Act as a senior engineer. Be thorough. Think step by step."

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."

8. The Task Leak

Sprint-specific instructions in persistent files

"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.

Context Rot Audit

Monthly Audit Checklist
  • Root CLAUDE.md under 200 lines? If not, split into rule files.
  • All build commands current? Try running them.
  • All file paths still exist? Grep for referenced paths.
  • No references to deprecated APIs? Search for old package names.
  • No duplicate rules? Check if linters already enforce them.
  • Config reviewed this quarter? Put it on the team calendar.

Troubleshooting

When context goes wrong. Symptoms, causes, and fixes.

Common Symptoms & 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

Debugging Commands

See loaded memory files
/memory
Check context usage
/context
Check root config length
wc -l CLAUDE.md
# Target: under 200 lines
Find all context files
find . -name "CLAUDE.md" | head -20
find .claude/rules -name "*.md" 2>/dev/null

The Nuclear Option

When context is thoroughly confused and Claude keeps making the same mistakes despite correct config:

Full Context Reset
  • Start a fresh session/clear or open a new terminal window
  • Review and clean all CLAUDE.md files — remove stale rules, fix wrong paths
  • Clear auto-memory if corrupted — delete topic files with wrong patterns
  • Rebuild context incrementally — add rules back one at a time, testing each

The Context Engineering Mindset

A Garden, Not a Monument

Context 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.