Hierarchical Context with CLAUDE.md Files
Summary
Place CLAUDE.md files at every directory level to provide LLMs with hyper-localized, contextual knowledge. This hierarchical approach ensures AI agents load only relevant patterns and constraints for the code they’re working on, dramatically improving accuracy and reducing context overload.
The Problem
LLMs lack context about project-specific patterns, constraints, and architectural decisions. Without guidance, they generate code that compiles but violates project conventions, design patterns, and domain rules. Loading all documentation in a monolithic file wastes context and dilutes signal with irrelevant information.
The Solution
Distribute knowledge hierarchically across CLAUDE.md files at every directory level. Root CLAUDE.md contains global architecture and principles (lean, 20-50 lines). Domain/package CLAUDE.md files contain domain-specific patterns (50-200 lines). Subdirectory CLAUDE.md files contain implementation details. LLMs load only root + relevant domain context, achieving 70% context reduction with 80-95% relevance.
The Problem
When working with AI coding agents, they lack inherent knowledge about your codebase:
- What patterns you follow
- What frameworks you use
- What design decisions you’ve made
- What constraints apply to specific domains
- What anti-patterns to avoid
Without this context, LLMs generate code that:
- Compiles but violates project conventions
- Runs but doesn’t match architectural patterns
- Works but creates technical debt
- Passes tests but misses domain-specific rules
The Monolithic Documentation Problem
The naive solution is to create a single, comprehensive CLAUDE.md file at the root:
/CLAUDE.md (5,000-10,000 lines)
├── Global architecture
├── API patterns
├── Database patterns
├── Frontend patterns
├── Testing patterns
├── Deployment patterns
├── Security patterns
└── ... (50+ more sections)
Problems:
- Context Overload: LLM loads 10,000 lines when it only needs 200
- Low Signal-to-Noise: 90%+ of content is irrelevant to current task
- Maintenance Burden: Single file becomes unmaintainable
- Difficult Discovery: Developers can’t find relevant sections
- Stale Information: Sections drift from actual code
- Merge Conflicts: Everyone edits the same file
Real-World Example
You’re working on an API endpoint in packages/api/src/routes/campaigns.ts.
Monolithic CLAUDE.md loads:
✅ API patterns (relevant)
✅ Validation patterns (relevant)
✅ Error handling (relevant)
❌ Frontend React patterns (irrelevant)
❌ Database migration patterns (irrelevant)
❌ Temporal workflow patterns (irrelevant)
❌ Email service patterns (irrelevant)
❌ ... (40 more irrelevant sections)
Result: 5% signal, 95% noise
What you actually need:
✅ Global architecture (20 lines)
✅ API-specific patterns (150 lines)
✅ Campaign domain rules (100 lines)
Total: 270 lines, 100% relevant
The Solution: Hierarchical CLAUDE.md Files
Distribute documentation hierarchically to mirror your codebase structure:
/
├── CLAUDE.md (LEAN - 30 lines)
│ ├── Core philosophy
│ ├── Global architecture principles
│ └── Link to domain-specific docs
│
├── packages/
│ ├── api/
│ │ ├── CLAUDE.md (150 lines)
│ │ │ ├── FastAPI patterns
│ │ │ ├── Route handler conventions
│ │ │ ├── Validation approach
│ │ │ └── Error handling
│ │ │
│ │ └── src/
│ │ ├── routes/
│ │ │ ├── campaigns/
│ │ │ │ └── CLAUDE.md (80 lines)
│ │ │ │ ├── Campaign-specific rules
│ │ │ │ ├── Status workflow
│ │ │ │ └── Business constraints
│ │ │ │
│ │ │ └── users/
│ │ │ └── CLAUDE.md (60 lines)
│ │ │ ├── User management patterns
│ │ │ └── Auth integration
│ │ │
│ │ └── services/
│ │ └── CLAUDE.md (100 lines)
│ │ └── Service layer patterns
│ │
│ ├── database/
│ │ └── CLAUDE.md (120 lines)
│ │ ├── Schema patterns
│ │ ├── Migration approach
│ │ └── Query optimization
│ │
│ └── temporal/
│ └── CLAUDE.md (180 lines)
│ ├── Workflow patterns
│ ├── Activity patterns
│ └── Determinism requirements
Loading Strategy
When working on a file, LLMs load:
- Root CLAUDE.md (global context)
- Relevant domain CLAUDE.md (domain context)
- Subdirectory CLAUDE.md (if exists, implementation details)
Example: Working on packages/api/src/routes/campaigns/create.ts
Loaded context:
├── /CLAUDE.md (30 lines) - Global architecture
├── /packages/api/CLAUDE.md (150 lines) - API patterns
└── /packages/api/src/routes/campaigns/CLAUDE.md (80 lines) - Campaign rules
Total: 260 lines, 95%+ relevant
Implementation Guide
Step 1: Create Lean Root CLAUDE.md
Keep the root file minimal – only global architecture and philosophy:
# Project: Social Media Scheduler
## Architecture
**Pattern**: Factory functions, no classes
**Stack**: TypeScript, FastAPI (Python), Supabase, Temporal
**Structure**: Monorepo with packages (api, database, temporal, web)
## Core Principles
1. **Type Safety**: All functions have explicit types
2. **Error Handling**: Return Result types, never throw in business logic
3. **Testing**: Integration tests over unit tests
4. **Documentation**: Self-documenting code + CLAUDE.md per domain
## Finding Domain-Specific Patterns
Each package has its own CLAUDE.md:
- `packages/api/CLAUDE.md` - API patterns
- `packages/database/CLAUDE.md` - Database patterns
- `packages/temporal/CLAUDE.md` - Workflow patterns
- `packages/web/CLAUDE.md` - Frontend patterns
Read the CLAUDE.md in the directory you're working in.
Line count: ~30 lines
Purpose: Orients the LLM to project structure, points to domain docs
Step 2: Create Domain CLAUDE.md Files
Each major package/domain gets its own CLAUDE.md:
Example: packages/api/CLAUDE.md
# API Package
## Route Handler Pattern
All routes follow this structure:
```typescript
import { FastifyRequest, FastifyReply } from 'fastify';
import { z } from 'zod';
const RequestSchema = z.object({
// Define request schema
});
export async function handleCreateCampaign(
request: FastifyRequest,
reply: FastifyReply
): Promise<void> {
// 1. Validate input
const validation = RequestSchema.safeParse(request.body);
if (!validation.success) {
return reply.status(400).send({
error: 'Validation failed',
details: validation.error.issues,
});
}
// 2. Call use case
const result = await createCampaignUseCase(validation.data);
// 3. Return result
if (!result.success) {
return reply.status(400).send({ error: result.error });
}
return reply.status(201).send(result.data);
}
Validation Rules
- Always use Zod schemas
- Always call
.safeParse()(never.parse()– don’t throw) - Always return validation errors as 400 with details
- Never trust request input
Error Handling
- Use cases return
Result<T, E>types - Routes check
result.successand respond accordingly - Never throw exceptions in route handlers
- Always log errors before returning
Authentication
- Use
requireAuthmiddleware for protected routes - Access user via
request.user(typed) - Return 401 for missing auth
- Return 403 for insufficient permissions
Testing
- Integration tests in
__tests__/routes/ - Test happy path + error cases
- Mock external services (database, Temporal)
- Use test fixtures from
__tests__/fixtures/
**Line count**: ~150 lines
**Purpose**: Provides API-specific patterns applicable to all routes
### Step 3: Create Subdomain CLAUDE.md Files (Optional)
For complex domains, add CLAUDE.md files at subdirectory level:
**Example**: `packages/api/src/routes/campaigns/CLAUDE.md`
```markdown
# Campaign Routes
## Domain Rules
### Campaign Status Workflow
DRAFT → SCHEDULED → PUBLISHED → COMPLETED
↓ ↓ ↓
ARCHIVED ARCHIVED ARCHIVED
**Allowed transitions**:
- DRAFT → SCHEDULED (when schedule time set)
- DRAFT → ARCHIVED (cancel before scheduling)
- SCHEDULED → PUBLISHED (when schedule time reached)
- SCHEDULED → ARCHIVED (cancel before publish)
- PUBLISHED → COMPLETED (when all posts sent)
- PUBLISHED → ARCHIVED (cancel mid-flight)
**Forbidden transitions**:
- ❌ COMPLETED → any other status (final state)
- ❌ ARCHIVED → any other status (final state)
- ❌ PUBLISHED → DRAFT (can't un-publish)
### Business Constraints
- **Max posts per campaign**: 50
- **Min schedule delay**: 5 minutes from now
- **Max schedule delay**: 90 days from now
- **Supported platforms**: Instagram, Twitter, LinkedIn
- **Image requirements**: 1080x1080 (Instagram), 1200x675 (Twitter, LinkedIn)
### Validation
```typescript
import { CampaignStatus } from '@repo/types';
function validateStatusTransition(
from: CampaignStatus,
to: CampaignStatus
): Result<void, string> {
const allowed = {
DRAFT: ['SCHEDULED', 'ARCHIVED'],
SCHEDULED: ['PUBLISHED', 'ARCHIVED'],
PUBLISHED: ['COMPLETED', 'ARCHIVED'],
COMPLETED: [],
ARCHIVED: [],
};
if (!allowed[from].includes(to)) {
return {
success: false,
error: `Cannot transition from ${from} to ${to}`,
};
}
return { success: true };
}
Common Patterns
- Always validate status transitions
- Always check user owns campaign before modifying
- Always verify post count ≤ 50
- Always validate schedule time constraints
- Never allow direct status updates (use transition endpoints)
**Line count**: ~80 lines
**Purpose**: Campaign-specific business rules and constraints
### Step 4: Link Files Together
Each CLAUDE.md points to related files:
**Root CLAUDE.md**:
```markdown
## Finding Domain-Specific Patterns
Read the CLAUDE.md in the package you're working in:
- `packages/api/CLAUDE.md`
- `packages/database/CLAUDE.md`
Domain CLAUDE.md (packages/api/CLAUDE.md):
## Domain-Specific Rules
Some routes have additional domain rules in subdirectories:
- `src/routes/campaigns/CLAUDE.md` - Campaign workflow and constraints
- `src/routes/users/CLAUDE.md` - User management patterns
Benefits
1. Hyper-Localized Context
LLMs load only relevant documentation:
Monolithic approach:
- Load: 10,000 lines
- Relevant: 500 lines (5%)
- Noise: 9,500 lines (95%)
Hierarchical approach:
- Load: 260 lines (root + domain + subdomain)
- Relevant: 250 lines (96%)
- Noise: 10 lines (4%)
Context reduction: 97.4%
Relevance improvement: 19x better
2. Better AI Accuracy
Focused context = better code generation:
Monolithic CLAUDE.md:
- LLM must filter 10K lines to find API patterns
- Gets confused by irrelevant patterns (frontend, workflows)
- Misses domain-specific rules buried in noise
- Result: Code compiles but violates conventions
Hierarchical CLAUDE.md:
- LLM reads 260 lines of relevant patterns
- Sees exactly what applies to current task
- Catches domain rules (campaign status workflow)
- Result: Code follows all conventions
3. Maintainability
Smaller files are easier to maintain:
- Focused editing: Edit only relevant domain
- Fewer conflicts: Developers work in different domains
- Easier reviews: PRs touch small, focused files
- Faster updates: Find and update specific patterns quickly
- Clear ownership: Domain teams own their CLAUDE.md
4. Developer Discovery
Developers can find patterns easily:
# What patterns apply to campaigns?
cat packages/api/src/routes/campaigns/CLAUDE.md
# What are global architecture rules?
cat CLAUDE.md
# How do we handle auth?
grep -r "authentication" **/CLAUDE.md
5. Living Documentation
Colocated documentation stays up-to-date:
- Lives next to code (harder to drift)
- Updated in same PR as code changes
- Reviewed alongside code
- Specific to actual implementation
Best Practices
1. Keep Root CLAUDE.md Lean
Target: 20-50 lines maximum
Include:
- Project name and purpose
- High-level architecture (stack, patterns)
- Core principles (3-5 max)
- Links to domain CLAUDE.md files
Exclude:
- Implementation details
- Framework-specific patterns
- Domain-specific rules
- Code examples (unless illustrating core principle)
2. Domain Files: 50-200 Lines
Target: 50-200 lines
Include:
- Patterns specific to this domain
- Framework usage (how we use FastAPI, React, etc.)
- Common anti-patterns to avoid
- Links to subdomain CLAUDE.md files (if any)
- Code examples showing patterns
Exclude:
- Subdomain-specific business rules
- Extremely detailed implementation guides
- Copy-pasted framework documentation
3. Subdomain Files: 50-150 Lines
Target: 50-150 lines
Include:
- Business rules and constraints
- Domain-specific workflows
- Validation rules
- State transitions
- Common gotchas
Exclude:
- General patterns (those go in parent CLAUDE.md)
- Framework usage (those go in domain CLAUDE.md)
4. Use Clear Structure
Maintain consistent structure across all CLAUDE.md files:
# [Domain Name]
## Overview
[Brief description of this domain]
## Patterns
[Common patterns with code examples]
## Rules
[Must-follow rules and constraints]
## Anti-Patterns
[What NOT to do, with examples]
## Testing
[Testing approach for this domain]
## Related
[Links to related CLAUDE.md files]
5. Include Code Examples
Show, don’t just tell:
❌ Bad:
"Use factory functions instead of classes"
✅ Good:
"Use factory functions instead of classes:
```typescript
// ✅ Do this
export const createUserService = (deps: Dependencies) => {
return {
getUser: async (id: string) => { ... },
createUser: async (data: UserInsert) => { ... },
};
};
// ❌ Don't do this
export class UserService {
getUser(id: string) { ... }
createUser(data: UserInsert) { ... }
}
“
### 6. Update in Same PR as Code
When changing patterns:
1. Update code
2. Update CLAUDE.md in **same PR**
3. Reviewer checks both code and docs
This prevents documentation drift.
### 7. Use Grep-Friendly Names
Make patterns easy to find:
```markdown
## Route Handler Pattern
## Validation Pattern
## Error Handling Pattern
Developers and LLMs can grep for “Pattern” to find all patterns.
8. Link Related Concepts
Connect related CLAUDE.md files:
## Related
- See `packages/database/CLAUDE.md` for schema patterns
- See `packages/temporal/CLAUDE.md` for background job patterns
- See root `CLAUDE.md` for global architecture
Real-World Example
Before: Monolithic CLAUDE.md
File: /CLAUDE.md (8,500 lines)
Structure:
# Project Documentation
## Architecture (200 lines)
## API Patterns (800 lines)
## Database Patterns (600 lines)
## Frontend Patterns (1,200 lines)
## Temporal Workflows (900 lines)
## Testing Patterns (400 lines)
## Campaign Domain (300 lines)
## User Domain (250 lines)
## Analytics Domain (350 lines)
## Email Service (400 lines)
## ... (40 more sections)
When working on campaign endpoint:
- Load: 8,500 lines
- Relevant: ~300 lines (campaign domain) + 200 (API patterns) = 500 lines
- Noise: 8,000 lines (94% irrelevant)
Problems:
- LLM context wasted on frontend, workflows, analytics
- Hard to find campaign-specific rules in 8,500 lines
- Every PR touches same file (merge conflicts)
- Developers don’t read it (too large)
After: Hierarchical CLAUDE.md
Structure:
/CLAUDE.md (40 lines)
packages/api/CLAUDE.md (180 lines)
packages/api/src/routes/campaigns/CLAUDE.md (90 lines)
Root (/CLAUDE.md – 40 lines):
# Social Media Scheduler
## Architecture
Factory functions, TypeScript, FastAPI, Supabase, Temporal.
Monorepo structure: packages (api, database, temporal, web).
## Core Principles
1. Type safety: explicit types everywhere
2. Error handling: Result types, no throwing
3. Integration tests over unit tests
4. Colocated documentation: CLAUDE.md per package
## Domain Docs
- `packages/api/CLAUDE.md` - API patterns
- `packages/database/CLAUDE.md` - Database patterns
- `packages/temporal/CLAUDE.md` - Workflow patterns
- `packages/web/CLAUDE.md` - Frontend patterns
Domain (packages/api/CLAUDE.md – 180 lines):
# API Package
## Route Handler Pattern
[150 lines of FastAPI patterns, validation, error handling, auth]
## Domain-Specific Rules
- `src/routes/campaigns/CLAUDE.md` - Campaign workflow
- `src/routes/users/CLAUDE.md` - User management
Subdomain (packages/api/src/routes/campaigns/CLAUDE.md – 90 lines):
# Campaign Routes
## Status Workflow
DRAFT → SCHEDULED → PUBLISHED → COMPLETED
[90 lines of campaign-specific business rules, constraints, validation]
When working on campaign endpoint:
- Load: 40 (root) + 180 (API) + 90 (campaigns) = 310 lines
- Relevant: ~300 lines (97% relevant)
- Noise: ~10 lines (3% irrelevant)
Improvements:
- 96% less context loaded (8,500 → 310 lines)
- 24x better signal-to-noise ratio (5% → 97%)
- No merge conflicts (different teams edit different files)
- Easy discovery (cat the file you’re working in)
Common Pitfalls
❌ Pitfall 1: Duplicating Content
Problem: Copying patterns from root to domain files
Solution: Root has only global patterns, domains extend/specialize
❌ Bad:
/CLAUDE.md:
"Use factory functions, no classes"
packages/api/CLAUDE.md:
"Use factory functions, no classes" (duplicate!)
✅ Good:
/CLAUDE.md:
"Use factory functions, no classes"
packages/api/CLAUDE.md:
"Route handlers follow factory pattern (see root CLAUDE.md):
export const createRouteHandler = (deps: Dependencies) => {
return async (request, reply) => { ... };
};"
❌ Pitfall 2: Making Root CLAUDE.md Too Large
Problem: Root grows to 500+ lines
Solution: Move domain-specific content to domain files
Trigger: If root > 100 lines, audit and move content
❌ Pitfall 3: Orphaned CLAUDE.md Files
Problem: CLAUDE.md exists but code deleted
Solution: Delete CLAUDE.md when deleting directories
# In package.json scripts
"clean": "find . -type f -name 'CLAUDE.md' -exec check-orphaned {} \;"
❌ Pitfall 4: Inconsistent Structure
Problem: Every CLAUDE.md has different sections
Solution: Use template for new CLAUDE.md files
# [Domain Name]
## Overview
## Patterns
## Rules
## Anti-Patterns
## Testing
## Related
❌ Pitfall 5: Not Linking Files
Problem: LLMs don’t know related CLAUDE.md files exist
Solution: Always include “Related” section with links
Measuring Success
Metrics to Track
-
Context Loaded:
- Before: Total lines in monolithic CLAUDE.md
- After: Lines in root + domain + subdomain
- Target: 70-90% reduction
-
Relevance Ratio:
- Relevant lines / Total lines loaded
- Target: >80% relevance
-
File Sizes:
- Root: <50 lines
- Domain: 50-200 lines
- Subdomain: 50-150 lines
-
AI Accuracy:
- % of generated code following conventions
- Target: >90% compliance
-
Developer Usage:
- Survey: “Do you read CLAUDE.md files?”
- Target: >80% say yes
Success Criteria
Good hierarchical structure:
- ✅ Root CLAUDE.md <50 lines
- ✅ Context loaded per task <300 lines
- ✅ Relevance ratio >80%
- ✅ AI-generated code follows conventions 90%+ of time
- ✅ Developers actually read and update files
Needs improvement:
- ❌ Root CLAUDE.md >100 lines
- ❌ Context loaded per task >500 lines
- ❌ Relevance ratio <50%
- ❌ AI-generated code violates conventions frequently
- ❌ Developers ignore CLAUDE.md files
Integration with Other Patterns
Combine with Prompt Caching
Hierarchical CLAUDE.md files work perfectly with prompt caching:
// Cached context (stable)
const stableContext = `
${await readFile('CLAUDE.md')} // Root (rarely changes)
${await readFile('packages/api/CLAUDE.md')} // Domain (changes occasionally)
`;
// Dynamic request (not cached)
const dynamicRequest = `
${await readFile('packages/api/src/routes/campaigns/CLAUDE.md')} // Subdomain
Implement createCampaign endpoint
`;
Combine with Semantic Naming
Semantic file names make CLAUDE.md files discoverable:
packages/
├── api-fastify-routes/
│ └── CLAUDE.md (API route patterns)
├── database-supabase-client/
│ └── CLAUDE.md (Database patterns)
├── temporal-workflows/
│ └── CLAUDE.md (Workflow patterns)
See: Semantic Naming for Retrieval
Combine with Custom ESLint Rules
CLAUDE.md documents patterns, ESLint enforces them:
CLAUDE.md:
## Factory Pattern
ALWAYS use factory functions, NEVER classes.
ESLint (.eslintrc.js):
rules: {
'no-classes': 'error', // Enforces factory pattern
}
See: Custom ESLint Rules for Determinism
Combine with Test-Based Regression Patching
When bugs occur:
- Write test that catches bug
- Fix bug
- Update CLAUDE.md with pattern to prevent recurrence
Example:
Bug: Campaign status transition validation missing
Fix:
- Add test:
test_campaign_status_transition_validation() - Fix code: Add validation logic
- Update
packages/api/src/routes/campaigns/CLAUDE.md:
## Status Transitions
ALWAYS validate status transitions using validateStatusTransition().
NEVER allow direct status updates.
See: Test-Based Regression Patching
Conclusion
Hierarchical CLAUDE.md files solve the context overload problem by distributing knowledge across the codebase:
Key Benefits:
- 70-90% context reduction: Load only relevant documentation
- 80-95% relevance: LLMs see only applicable patterns
- Better AI accuracy: Focused context = better code generation
- Maintainability: Small, focused files are easier to maintain
- Developer discovery: Easy to find relevant patterns
- Living documentation: Colocated docs stay up-to-date
Structure:
- Root CLAUDE.md (20-50 lines): Global architecture, core principles
- Domain CLAUDE.md (50-200 lines): Framework patterns, domain conventions
- Subdomain CLAUDE.md (50-150 lines): Business rules, specific constraints
Loading strategy: Root + relevant domain + subdomain = 200-400 lines of highly relevant context
The result: LLMs generate code that follows all project conventions, architectural patterns, and domain rules – not by chance, but by design.
Related Concepts
- Context Debugging Framework – Systematic approach when context issues arise
- Context Rot Auto-Compacting – Prevent context degradation in long sessions
- Progressive Disclosure Context – Load context only when needed
- MCP Server for Project Context – Dynamic context beyond static CLAUDE.md files
- Clean Slate Trajectory Recovery – Reset when context becomes counterproductive
- Sliding Window History – Bounded state management for context retention
- Prompt Caching Strategy – Cache hierarchical CLAUDE.md files for cost savings
- Semantic Naming Patterns – Make CLAUDE.md files discoverable
- Custom ESLint Rules for Determinism – Enforce patterns documented in CLAUDE.md
- Test-Based Regression Patching – Update CLAUDE.md when fixing bugs
- Institutional Memory Learning Files – Capture why patterns exist
- Few-Shot Prompting with Project Examples – Store few-shot examples in domain-specific CLAUDE.md files
- Human-First DX Philosophy – Hierarchical context makes documentation discoverable for humans
References
- Claude Code Documentation – Official Claude Code documentation on CLAUDE.md files
- Anthropic Context Management Best Practices – Anthropic’s guide to effective context management with Claude
Hierarchical Context Files: CLAUDE.md at Every Directory Level
Summary
AI coding agents struggle with massive monolithic documentation that mixes irrelevant context with domain-specific patterns. Hierarchical context files solve this by placing CLAUDE.md files at every directory level, creating a tree of increasingly specific context. Root files define global architecture, domain directories specify patterns for APIs/databases/workflows, and subdirectories add implementation details. LLMs load context bottom-up, getting exactly what they need without noise.
The Problem
Monolithic root CLAUDE.md files become massive (5,000-10,000+ lines) as projects grow, mixing global architecture with domain-specific patterns for APIs, databases, UI components, and workflows. When LLMs load this entire file for every request, they get 90%+ irrelevant context, leading to hallucinated patterns, ignored constraints, and inconsistent implementations. Developers face the same problem: finding relevant documentation requires searching thousands of lines or asking teammates.
The Solution
Create a hierarchy of CLAUDE.md files mirroring your codebase structure. Root CLAUDE.md stays lean (30-50 lines) with global architecture. Each domain directory (api/, database/, workflows/) gets its own CLAUDE.md with domain-specific patterns. Subdirectories add implementation details. LLMs load context hierarchically (root → domain → subdomain), receiving 200-500 lines of highly relevant context instead of 10,000 lines of mixed content. This achieves 80-95% context relevance vs 5-10% with monolithic files.
The Problem: Context Dilution at Scale
When you ask Claude Code to “implement a new Temporal workflow,” it loads your root CLAUDE.md file to understand project patterns. But what happens when that file looks like this?
# Root CLAUDE.md (10,247 lines)
## Project Architecture
[500 lines about monorepo structure]
## API Patterns
[1,200 lines about tRPC endpoints, DTOs, validation]
## Database Patterns
[1,500 lines about Supabase migrations, RLS policies]
## UI Patterns
[2,000 lines about React components, state management]
## Workflow Patterns (buried at line 8,734)
[800 lines about Temporal workflows, activities]
## CLI Patterns
[600 lines about command-line tools]
## Shared Utilities
[400 lines about shared helper functions]
The Real Impact
LLM perspective:
- Loads 10,247 lines of context
- Only 800 lines (7.8%) are relevant to Temporal workflows
- 9,447 lines (92.2%) are noise about APIs, databases, UI
- LLM attention diluted across irrelevant patterns
- Frequently ignores or hallucinates Temporal patterns
Developer perspective:
- Opens CLAUDE.md to check Temporal patterns
- Scrolls through 8,734 lines to find relevant section
- Takes 5-10 minutes to locate information
- Often gives up and asks teammates instead
Code quality impact:
- LLM generates workflows using API patterns (wrong domain)
- Inconsistent implementations across team
- 30-40% first-try correctness
- 3-5 iterations to get correct code
Why This Happens
Projects evolve organically. What starts as a simple 100-line CLAUDE.md grows as you add:
- New domains: API, database, workflows, UI
- Domain patterns: tRPC conventions, migration rules, workflow patterns
- Examples: Working code showing correct implementations
- Anti-patterns: Common mistakes to avoid
- Rationale: Why certain decisions were made
Before long, you have a 10,000-line monolith mixing global architecture with highly specific domain patterns.
The Solution: Hierarchical Context Files
The Core Principle
“Context should be as close as possible to the code it describes, and as specific as necessary.”
Instead of one massive root CLAUDE.md, create a hierarchy of context files that mirror your codebase structure:
project/
├── CLAUDE.md # Global: 30-50 lines
├── packages/
│ ├── api/
│ │ ├── CLAUDE.md # API domain: 200-300 lines
│ │ └── src/
│ │ ├── routes/
│ │ │ ├── CLAUDE.md # Route patterns: 100-150 lines
│ │ │ ├── users/
│ │ │ │ └── CLAUDE.md # User routes: 50-100 lines
│ │ │ └── campaigns/
│ │ │ └── CLAUDE.md # Campaign routes: 50-100 lines
│ │ └── middleware/
│ │ └── CLAUDE.md # Middleware: 80-120 lines
│ ├── database/
│ │ ├── CLAUDE.md # Database domain: 250-350 lines
│ │ └── src/
│ │ ├── migrations/
│ │ │ └── CLAUDE.md # Migration rules: 150-200 lines
│ │ └── dtos/
│ │ └── CLAUDE.md # DTO patterns: 100-150 lines
│ ├── workflows/
│ │ ├── CLAUDE.md # Temporal domain: 300-400 lines
│ │ └── src/
│ │ ├── workflows/
│ │ │ └── CLAUDE.md # Workflow patterns: 150-200 lines
│ │ └── activities/
│ │ └── CLAUDE.md # Activity patterns: 100-150 lines
│ └── ui/
│ ├── CLAUDE.md # UI domain: 250-350 lines
│ └── src/
│ └── components/
│ └── CLAUDE.md # Component patterns: 150-200 lines
How Context Loading Works
When working on a file like packages/workflows/src/workflows/send-email.ts, the LLM loads context hierarchically from bottom-up:
-
Most specific:
packages/workflows/src/workflows/CLAUDE.md(150 lines)- Workflow-specific patterns
- Naming conventions
- Error handling for workflows
-
Domain level:
packages/workflows/CLAUDE.md(300 lines)- Temporal SDK patterns
- Activity usage
- Determinism requirements
-
Global level:
CLAUDE.md(40 lines)- Monorepo structure
- Tech stack
- SOLID principles
Total context: ~490 lines of highly relevant information
Relevance: 95%+ of loaded context applies to Temporal workflows
Compare to monolithic:
- Monolithic: 10,247 lines loaded, 800 relevant (7.8%)
- Hierarchical: 490 lines loaded, 465 relevant (95%)
Result: LLM generates correct workflow patterns on first try.
Implementation Guide
Step 1: Identify Your Domains
Audit your codebase to find logical domains with distinct patterns:
# Example project structure
packages/
├── api/ # Domain: HTTP endpoints, tRPC, validation
├── database/ # Domain: Migrations, RLS, queries
├── workflows/ # Domain: Temporal orchestration
├── ui/ # Domain: React components, state
├── cli/ # Domain: Command-line tools
└── shared/ # Domain: Shared utilities
Key question: “Does code in this directory need different patterns than other directories?”
- API routes: DTO validation, error codes, tRPC patterns → Yes, separate domain
- Database migrations: Schema changes, RLS policies, backwards compatibility → Yes, separate domain
- Temporal workflows: Determinism, activities, error handling → Yes, separate domain
- React components: Props, hooks, state management → Yes, separate domain
If yes → Create domain-specific CLAUDE.md
Step 2: Extract Domain Context from Root
Identify sections in your root CLAUDE.md that only apply to specific domains:
Before:
# Root CLAUDE.md (10,247 lines)
## API Patterns
- Validate all DTOs with Zod schemas
- Return only 200/400/401/403/404/500 status codes
- Use tRPC for type safety
[1,200 lines of API-specific patterns]
## Temporal Workflow Patterns
- All external calls must use activities
- Workflows must be deterministic
- Use proxyActivities pattern
[800 lines of Temporal-specific patterns]
## Database Migration Patterns
- Never delete columns, only deprecate
- Always include RLS policies
- Use snake_case for SQL
[1,500 lines of database-specific patterns]
After:
# Root CLAUDE.md (40 lines)
## Project Architecture
Monorepo using Turborepo with domain-driven structure:
- `packages/api`: tRPC API endpoints
- `packages/database`: Supabase database layer
- `packages/workflows`: Temporal orchestration
- `packages/ui`: Next.js frontend
**See each package's CLAUDE.md for domain-specific patterns.**
## Global Principles
- TypeScript strict mode enabled
- All code must have integration tests
- Follow SOLID principles
- Prefer functional patterns over classes
- 200 lines max per file (enforced by linter)
# packages/api/CLAUDE.md (280 lines)
## API Architecture
This package implements the tRPC API layer.
## DTO Validation Patterns
- Every endpoint MUST validate input with Zod schemas
- DTOs defined in `packages/database/src/dtos/`
- Return types must be explicit (never `any`)
## Error Handling
- Return only these status codes: 200/400/401/403/404/500
- Use TRPCError for all errors
- Include error codes for client handling
[270+ more lines of API-specific patterns]
# packages/workflows/CLAUDE.md (320 lines)
## Temporal Architecture
This package implements Temporal workflows and activities.
## Workflow Patterns
- **Determinism**: Workflows MUST be deterministic
- **External calls**: Use activities, never direct calls
- **Randomness**: Use `workflow.uuid()`, not `Math.random()`
## Activity Patterns
- All activities MUST have `startToCloseTimeout`
- Idempotent: Activities can be retried safely
- Error handling: Throw `ApplicationFailure` for business errors
[310+ more lines of Temporal-specific patterns]
# packages/database/CLAUDE.md (340 lines)
## Database Architecture
This package manages Supabase database schema and migrations.
## Migration Patterns
- **Never delete columns**: Mark as deprecated instead
- **Always add RLS policies**: No table without RLS
- **Use snake_case**: For SQL, camelCase for TypeScript
## RLS Policy Patterns
- User-scoped: `auth.uid() = user_id`
- Tenant-scoped: `auth.uid() IN (SELECT user_id FROM tenant_users WHERE tenant_id = tenants.id)`
- Public read: `SELECT true`
[330+ more lines of database-specific patterns]
Result:
- Root: 40 lines (was 10,247)
- Domains: 300-400 lines each (highly focused)
- Total: Same information, better organized
Step 3: Create Subdomain Context for Complex Domains
When domains have distinct subdomains, add another level:
packages/api/
├── CLAUDE.md # API-level: tRPC setup, global middleware (280 lines)
└── src/
├── routes/
│ ├── CLAUDE.md # Route-level: organization, naming (120 lines)
│ ├── users/
│ │ └── CLAUDE.md # User routes: auth, profiles (80 lines)
│ └── campaigns/
│ └── CLAUDE.md # Campaign routes: CRUD, permissions (90 lines)
└── middleware/
└── CLAUDE.md # Middleware: auth, logging, errors (100 lines)
When to add subdomain CLAUDE.md:
Only when patterns diverge significantly between subdirectories.
Example: User routes vs Campaign routes
# packages/api/src/routes/users/CLAUDE.md (80 lines)
## User Route Patterns
User routes handle authentication and profile management.
## Authentication
- POST /users/register: Email + password, returns user + session
- POST /users/login: Email + password, returns session
- POST /users/logout: Invalidates session
## Password Rules
- Minimum 12 characters
- Must include: uppercase, lowercase, number, symbol
- Use bcrypt with cost factor 12
- Check against leaked password database
[70+ more lines of user-specific patterns]
# packages/api/src/routes/campaigns/CLAUDE.md (90 lines)
## Campaign Route Patterns
Campaign routes handle marketing campaign CRUD operations.
## Authorization
- All campaign endpoints require authentication
- Check user has permission for tenant
- Campaign access: Owner or tenant member with `campaigns:read`
## Campaign State Machine
- DRAFT → SCHEDULED → RUNNING → COMPLETED
- DRAFT → ARCHIVED
- RUNNING → PAUSED → RUNNING
- Only DRAFT campaigns can be edited
[80+ more lines of campaign-specific patterns]
Why separate files?
- User patterns (auth, passwords) ≠ Campaign patterns (state machines, permissions)
- When working on user routes, campaign patterns are noise
- When working on campaign routes, auth patterns are noise
Step 4: Standardize Section Structure
Use consistent headers across all CLAUDE.md files for predictability:
# packages/[domain]/CLAUDE.md
## Architecture
[What this domain does, how it fits into project]
## Patterns
[Domain-specific implementation patterns]
## Conventions
[Naming, organization, file structure]
## Anti-Patterns
[Common mistakes, what NOT to do]
## Examples
[Working code showing correct patterns]
## Related Context
[Links to other relevant CLAUDE.md files]
Example:
# packages/workflows/CLAUDE.md
## Architecture
Temporal orchestrates long-running workflows. This package contains:
- `src/workflows/`: Workflow definitions (deterministic logic)
- `src/activities/`: Activities (side effects like API calls)
- `src/worker.ts`: Worker that executes workflows
## Patterns
### Workflow Determinism
Workflows MUST be deterministic (replaying history must produce same result).
**DO**:
- Use `workflow.uuid()` for randomness
- Use `workflow.now()` for current time
- Use `proxyActivities()` for external calls
**DON'T**:
- Use `Math.random()` (non-deterministic)
- Use `Date.now()` (non-deterministic)
- Make HTTP calls directly (non-deterministic)
### Activity Pattern
```typescript
// src/workflows/send-email-workflow.ts
import { proxyActivities } from '@temporalio/workflow';
import type * as activities from '../activities';
const { sendEmail } = proxyActivities<typeof activities>({
startToCloseTimeout: '1 minute',
});
export async function sendEmailWorkflow(email: string) {
await sendEmail({ to: email, template: 'welcome' });
}
Conventions
- Workflow files:
[name]-workflow.ts - Activity files:
[name]-activity.ts - Workflow IDs:
${workflowName}-${entityId}(e.g.,sendEmail-user123)
Anti-Patterns
❌ External Calls in Workflows
// WRONG: Direct HTTP call
export async function workflow() {
await fetch('https://api.example.com'); // Non-deterministic!
}
✅ External Calls in Activities
// CORRECT: HTTP call in activity
export async function fetchDataActivity() {
return await fetch('https://api.example.com');
}
export async function workflow() {
const data = await fetchData(); // Calls activity
}
Examples
See src/workflows/send-welcome-email-workflow.ts for complete example.
Related Context
- Root CLAUDE.md: Global architecture
- packages/workflows/src/workflows/CLAUDE.md: Workflow-specific patterns
- packages/workflows/src/activities/CLAUDE.md: Activity-specific patterns
### Step 5: Link Between Levels
Create explicit navigation between hierarchy levels:
```markdown
# Root CLAUDE.md
## Domain-Specific Patterns
See domain CLAUDE.md files:
- `packages/api/CLAUDE.md`: API patterns
- `packages/database/CLAUDE.md`: Database patterns
- `packages/workflows/CLAUDE.md`: Temporal patterns
- `packages/ui/CLAUDE.md`: React patterns
# packages/workflows/CLAUDE.md
## Related Context
**Parent**: See `CLAUDE.md` (root) for global architecture
**Children**:
- `src/workflows/CLAUDE.md`: Workflow-specific patterns
- `src/activities/CLAUDE.md`: Activity-specific patterns
**Siblings**:
- `packages/api/CLAUDE.md`: For HTTP endpoints that trigger workflows
- `packages/database/CLAUDE.md`: For DTOs used in workflows
Real-World Example
Scenario: Implementing a New Temporal Workflow
Task: “Create a workflow to send welcome emails when users sign up.”
Before: Monolithic CLAUDE.md
// Context loaded:
// - Root CLAUDE.md: 10,247 lines
// - Lines 1-500: Architecture
// - Lines 501-1,700: API patterns (irrelevant)
// - Lines 1,701-3,200: Database patterns (irrelevant)
// - Lines 3,201-5,200: UI patterns (irrelevant)
// - Lines 5,201-6,000: Temporal patterns (RELEVANT)
// - Lines 6,001-10,247: Other patterns (irrelevant)
//
// Relevance: 800 / 10,247 = 7.8%
// LLM generates (mixing API and workflow patterns):
export async function sendWelcomeEmail(userId: string) {
// ❌ Wrong: Using API error handling pattern
if (!userId) {
throw new TRPCError({ code: 'BAD_REQUEST' });
}
// ❌ Wrong: Direct external call (non-deterministic)
await sendgrid.send({
to: await getUser(userId).email,
template: 'welcome',
});
}
// Developer reviews: "This is wrong, it's using API patterns in a workflow"
// Ask LLM to fix...
// 3-4 iterations later, finally correct
After: Hierarchical CLAUDE.md
// Context loaded (hierarchically):
// 1. Root CLAUDE.md: 40 lines (global architecture)
// 2. packages/workflows/CLAUDE.md: 320 lines (Temporal patterns)
// 3. packages/workflows/src/workflows/CLAUDE.md: 150 lines (workflow specifics)
//
// Total: 510 lines
// Relevance: 485 / 510 = 95%
// LLM generates (using correct Temporal patterns):
import { proxyActivities } from '@temporalio/workflow';
import type * as activities from '../activities';
const { sendEmail, getUserEmail } = proxyActivities<typeof activities>({
startToCloseTimeout: '1 minute',
});
export async function sendWelcomeEmailWorkflow(
userId: string
): Promise<void> {
// ✅ Correct: Input validation (from workflow patterns)
if (!userId) {
throw new ApplicationFailure('userId required');
}
// ✅ Correct: External calls via activities (deterministic)
const email = await getUserEmail(userId);
await sendEmail({
to: email,
template: 'welcome',
data: { userId },
});
}
// Developer reviews: "Perfect, uses correct Temporal patterns"
// Ships on first try ✓
Impact:
- Iterations: 3-4 → 1
- Time: 30-45 min → 5-10 min
- Code quality: Mixed patterns → Consistent Temporal patterns
Integration with AI Tools
Claude Code
Claude Code automatically loads CLAUDE.md files hierarchically:
# When working on:
packages/workflows/src/workflows/send-email-workflow.ts
# Claude Code loads:
1. /CLAUDE.md
2. /packages/workflows/CLAUDE.md
3. /packages/workflows/src/workflows/CLAUDE.md
# No configuration needed - just create the files
Cursor
Cursor’s .cursorrules files work the same way:
project/
├── .cursorrules # Global
├── packages/
│ ├── api/
│ │ └── .cursorrules # API-specific
│ └── workflows/
│ └── .cursorrules # Temporal-specific
Aider
Aider loads context via explicit configuration:
# packages/workflows/.aider.conf.yml
read:
- ../../CLAUDE.md
- CLAUDE.md
- src/workflows/CLAUDE.md
Custom Tooling
Implement hierarchical loading in your own tools:
import fs from 'fs';
import path from 'path';
function loadHierarchicalContext(filePath: string): string[] {
const contexts: string[] = [];
let currentDir = path.dirname(filePath);
const root = process.cwd();
// Walk up from file to root
while (currentDir.startsWith(root)) {
const claudeFile = path.join(currentDir, 'CLAUDE.md');
if (fs.existsSync(claudeFile)) {
// Prepend (root context loaded first)
contexts.unshift(fs.readFileSync(claudeFile, 'utf-8'));
}
if (currentDir === root) break;
currentDir = path.dirname(currentDir);
}
return contexts;
}
// Usage:
const contextFiles = loadHierarchicalContext(
'packages/workflows/src/workflows/send-email.ts'
);
// Returns:
// [
// '/CLAUDE.md',
// '/packages/workflows/CLAUDE.md',
// '/packages/workflows/src/workflows/CLAUDE.md',
// ]
const fullContext = contextFiles.join('\n\n---\n\n');
Best Practices
1. Keep Root CLAUDE.md Lean (<50 lines)
Root file should be navigation, not implementation:
# Root CLAUDE.md
## Project Architecture
Monorepo structure:
- `packages/api`: tRPC endpoints (see packages/api/CLAUDE.md)
- `packages/database`: Supabase layer (see packages/database/CLAUDE.md)
- `packages/workflows`: Temporal (see packages/workflows/CLAUDE.md)
## Global Principles
- TypeScript strict mode
- Integration tests required
- SOLID principles
- 200 lines max per file
Don’t include domain-specific patterns in root.
2. Add Hierarchy Levels Only When Patterns Diverge
Don’t create deep hierarchies prematurely:
❌ Too deep (premature):
packages/api/src/routes/users/handlers/create/validation/CLAUDE.md
✅ Start simple:
packages/api/CLAUDE.md
✅ Add when patterns diverge:
packages/api/src/routes/users/CLAUDE.md (only when users/ has unique patterns)
Rule of thumb: Max 3-4 levels
3. Use Consistent Section Headers
Standardize headers for predictability:
## Architecture
## Patterns
## Conventions
## Anti-Patterns
## Examples
## Related Context
4. Include Concrete Examples
Abstract rules are hard to apply. Show code:
❌ Abstract:
- Workflows must be deterministic
✅ Concrete:
- Workflows must be deterministic
**DON'T**:
```typescript
export async function workflow() {
const id = Math.random(); // Non-deterministic!
}
DO:
export async function workflow() {
const id = workflow.uuid(); // Deterministic ✓
}
### 5. Link Between Hierarchy Levels
Make navigation explicit:
```markdown
# packages/workflows/CLAUDE.md
## Related Context
**Parent**: CLAUDE.md (root)
**Children**: src/workflows/CLAUDE.md, src/activities/CLAUDE.md
**Siblings**: packages/api/CLAUDE.md (for triggering workflows)
6. Update Context When Code Changes
Treat CLAUDE.md as first-class code:
# Git hook: pre-commit
#!/bin/bash
for file in $(git diff --cached --name-only); do
if <a href="/posts/file-ts/">$file == *.ts</a>; then
dir=$(dirname "$file")
if [ -f "$dir/CLAUDE.md" ]; then
echo "⚠️ Code changed in $dir - review $dir/CLAUDE.md"
fi
fi
done
Measuring Success
Key Metrics
1. Context Relevance
Metric: % of loaded context lines that apply to current task
interface ContextMetrics {
totalLinesLoaded: number;
relevantLines: number;
relevanceRate: number;
}
// Monolithic:
const monolithic: ContextMetrics = {
totalLinesLoaded: 10247,
relevantLines: 800,
relevanceRate: 0.078, // 7.8%
};
// Hierarchical:
const hierarchical: ContextMetrics = {
totalLinesLoaded: 510,
relevantLines: 485,
relevanceRate: 0.950, // 95%
};
Target: >80% relevance
2. First-Try Correctness
Metric: % of LLM-generated code that’s correct without iteration
Monolithic: 30-40% first-try correct
Hierarchical: 70-85% first-try correct
Target: >80%
3. Time to Find Context
Metric: How long to locate relevant documentation
Monolithic: 5-10 minutes (search 10K lines)
Hierarchical: <30 seconds (same directory as code)
Target: <1 minute
4. Iteration Count
Metric: Avg iterations needed for correct code
Monolithic: 3-5 iterations
Hierarchical: 1-2 iterations
Target: <2 iterations
Tracking Context Effectiveness
interface GenerationMetrics {
file: string;
contextLoaded: string[];
linesLoaded: number;
relevantLines: number;
firstTryCorrect: boolean;
iterations: number;
}
const metrics: GenerationMetrics = {
file: 'packages/workflows/src/workflows/send-email.ts',
contextLoaded: [
'CLAUDE.md',
'packages/workflows/CLAUDE.md',
'packages/workflows/src/workflows/CLAUDE.md',
],
linesLoaded: 510,
relevantLines: 485,
firstTryCorrect: true,
iterations: 1,
};
const relevanceRate = metrics.relevantLines / metrics.linesLoaded;
console.log(`Context relevance: ${(relevanceRate * 100).toFixed(1)}%`);
// Output: Context relevance: 95.1%
Common Pitfalls
❌ Pitfall 1: Too Many Hierarchy Levels
Problem: Over-engineering structure
❌ Too deep:
api/src/routes/users/handlers/create/validation/email/CLAUDE.md
Solution: Stop at 3-4 levels max
✅ Appropriate depth:
- CLAUDE.md (root)
- packages/api/CLAUDE.md (domain)
- packages/api/src/routes/CLAUDE.md (subdomain)
- packages/api/src/routes/users/CLAUDE.md (feature)
❌ Pitfall 2: Duplicating Content Across Levels
Problem: Same patterns in multiple files
# packages/api/CLAUDE.md
## DTO Validation
[200 lines]
# packages/database/CLAUDE.md
## DTO Validation
[Same 200 lines duplicated]
Solution: Extract to shared file
# packages/shared/CLAUDE.md
## DTO Validation (Shared)
[200 lines - single source of truth]
# packages/api/CLAUDE.md
See packages/shared/CLAUDE.md for DTO validation.
# packages/database/CLAUDE.md
See packages/shared/CLAUDE.md for DTO validation.
❌ Pitfall 3: No Examples
Problem: Abstract rules without concrete code
❌ Abstract only:
- Workflows must be deterministic
Solution: Always include code examples
✅ With examples:
- Workflows must be deterministic
```typescript
// ❌ Wrong:
const id = Math.random();
// ✅ Correct:
const id = workflow.uuid();
### ❌ Pitfall 4: Stale Context
**Problem**: Code changes but CLAUDE.md doesn't
**Solution**: Add git hooks to remind updates
```bash
#!/bin/bash
# .git/hooks/pre-commit
for file in $(git diff --cached --name-only | grep "\.ts$"); do
dir=$(dirname "$file")
[ -f "$dir/CLAUDE.md" ] && echo "⚠️ Review $dir/CLAUDE.md"
done
Advanced: Auto-Generated Summaries
Generate navigation summaries:
#!/bin/bash
# scripts/generate-context-map.sh
echo "# Context Map" > CONTEXT_MAP.md
echo "" >> CONTEXT_MAP.md
find . -name "CLAUDE.md" | sort | while read file; do
dir=$(dirname "$file")
echo "## $dir" >> CONTEXT_MAP.md
# Extract H2 headers
grep "^## " "$file" | sed 's/^## /- /' >> CONTEXT_MAP.md
echo "" >> CONTEXT_MAP.md
done
Output:
# Context Map
## .
- Project Architecture
- Global Principles
## ./packages/api
- API Architecture
- DTO Validation Patterns
- Error Handling
## ./packages/workflows
- Temporal Architecture
- Workflow Patterns
- Activity Patterns
Conclusion
Hierarchical context files solve the context dilution problem by organizing documentation to mirror code structure:
Before (Monolithic):
- 10,000+ line root CLAUDE.md
- 5-10% context relevance
- 30-40% first-try correctness
- 5-10 minutes to find patterns
- 3-5 iterations per task
After (Hierarchical):
- 30-50 line root + 200-400 line domain files
- 80-95% context relevance
- 70-85% first-try correctness
- <30 seconds to find patterns
- 1-2 iterations per task
Implementation Steps:
- Identify domains with distinct patterns (API, database, workflows, UI)
- Extract domain context from root CLAUDE.md to domain-specific files
- Create subdomain files when patterns diverge significantly
- Standardize structure (Architecture, Patterns, Conventions, Examples)
- Link between levels (parent, children, siblings)
- Keep root lean (<50 lines, mostly navigation)
Result: LLMs and developers get exactly the context they need, nothing more, nothing less.
Related Concepts
- Context Debugging Framework – Systematic approach when context issues arise
- Context Rot Auto-Compacting – Prevent context degradation in long sessions
- Progressive Disclosure Context – Load context only when needed
- MCP Server for Project Context – Dynamic context beyond static CLAUDE.md files
- Clean Slate Trajectory Recovery – Reset when context becomes counterproductive
- Sliding Window History – Bounded state management for context retention
- Prompt Caching Strategy – Cache hierarchical context for cost savings
- Semantic Naming Patterns – Name files for easy discovery
- Layered Prompts Architecture – Onion architecture for prompts
- Institutional Memory Learning Files – Capture why patterns exist
References
- Claude Code Documentation – Official Claude Code documentation on CLAUDE.md files
- Locality of Behavior Principle – The principle that behavior should be obvious from looking at code locally
- Colocation in React – Kent C. Dodds on the collocation principle: keeping related things together

