Summary
Sub-agent context hierarchy is a pattern for managing what context each specialized agent receives in a multi-agent system. By organizing context into three layers (Root, Agent, Package), you can give each sub-agent exactly the information it needs while preventing context pollution from unrelated domains. The orchestrator agent sees everything; specialized agents see only their domain plus shared patterns.
The Problem
When multiple specialized agents work together on a task, context management becomes complex:
- Context pollution: A backend agent doesn’t need frontend patterns cluttering its context
- Conflicting instructions: Generic patterns may conflict with domain-specific overrides
- Wasted tokens: Loading full project context for every sub-agent exhausts token budgets
- Confused responsibilities: Without clear boundaries, agents may attempt work outside their expertise
- Inconsistent behavior: Same information interpreted differently by different agents
A single monolithic context shared across all agents leads to diluted attention and mixed patterns.
The Solution
Implement a three-layer context hierarchy where each sub-agent receives:
- Root context: Shared patterns all agents must follow (20-50 lines)
- Agent context: Role-specific behavioral flows (100-200 lines)
- Package context: Domain-specific patterns for the code they touch (50-150 lines)
┌─────────────────────────────────────────────────────────────────┐
│ ORCHESTRATOR AGENT │
│ Context: Root + All Agent Definitions + Task Context │
└──────────────────────────┬──────────────────────────────────────┘
│
┌─────────────────┼─────────────────┐
│ │ │
▼ ▼ ▼
┌─────────────────┐ ┌──────────────┐ ┌───────────────┐
│ BACKEND AGENT │ │FRONTEND AGENT│ │ QA AGENT │
│ │ │ │ │ │
│ Root Context │ │ Root Context │ │ Root Context │
│ + backend.md │ │ + frontend.md│ │ + qa.md │
│ + api/CLAUDE.md │ │ + ui/CLAUDE.md│ │ + tests/ │
└─────────────────┘ └──────────────┘ └───────────────┘
Each agent sees only what it needs, nothing more.
The Three Layers
Layer 1: Root Context (Shared)
The root CLAUDE.md contains patterns all agents must follow:
# Root CLAUDE.md (30-50 lines)
## Architecture
- Monorepo with packages (api, ui, database, workflows)
- TypeScript strict mode everywhere
- Factory functions, no classes
## Error Handling
- Return Result types: { success: boolean, data?: T, error?: string }
- Never throw exceptions in business logic
- Always log errors before returning
## Naming Conventions
- Files: kebab-case (user-service.ts)
- Functions: camelCase (createUser)
- Types: PascalCase (UserService)
- Constants: UPPER_SNAKE_CASE (MAX_RETRIES)
## Quality Standards
- All code must have integration tests
- No TypeScript `any` types
- Maximum 200 lines per file
Key principle: Root context is lean and universal. Every sub-agent inherits these patterns.
Layer 2: Agent Context (Role-Specific)
Each agent type gets a behavioral flow defining its responsibilities:
# .claude/agents/backend-engineer.md (100-200 lines)
You are a Backend Engineer specializing in Node.js/TypeScript APIs.
## Your Responsibilities
- Implement API endpoints following tRPC patterns
- Design database schemas and migrations
- Write business logic in service layers
- Create Zod validation schemas
## Your Workflow
1. Read the domain CLAUDE.md for business rules
2. Check existing API patterns in /packages/api
3. Follow layered architecture (routes -> handlers -> services)
4. Always write Zod validation schemas
5. Use Result pattern for error handling
6. Hand off to QA Engineer when implementation is complete
## What You DON'T Do
- Write frontend code (delegate to Frontend Engineer)
- Write tests (delegate to QA Engineer)
- Review your own code (Code Reviewer's job)
- Make UI decisions
## Tools You Use
- Read: Study existing code
- Write: Create new files
- Edit: Modify existing code
- Bash: Run migrations, check schemas
Key principle: Agent context defines scope and handoff points. The agent knows what it does and doesn’t do.
Layer 3: Package Context (Domain-Specific)
Agents working in a specific domain load that domain’s CLAUDE.md:
# packages/api/CLAUDE.md (150-250 lines)
## Route Handler Pattern
All routes follow this structure:
```typescript
import { Router } from 'express';
import { validateSchema } from '../middleware/validation';
import { authenticate } from '../middleware/auth';
const router = Router();
router.post('/resource',
authenticate,
validateSchema(createResourceSchema),
createResourceHandler
);
Service Layer Pattern
Services use dependency injection and return Results:
interface UserServiceDeps {
db: Database;
mailer: Mailer;
}
export function createUserService(deps: UserServiceDeps) {
return {
createUser: async (data: CreateUserDTO): Promise<Result<User>> => {
// Business logic here
}
};
}
This Package Owns
- HTTP endpoint definitions
- Request validation
- Response formatting
- Authentication middleware
This Package Does NOT Own
- Database schema (see packages/database)
- Business rules (see packages/domain)
- Background jobs (see packages/workflows)
**Key principle**: Package context provides domain-specific patterns without cross-domain pollution.
## Context Loading Strategy
### Orchestrator Agent
The orchestrator sees everything to make delegation decisions:
```typescript
const orchestratorContext = {
root: readFile('CLAUDE.md'),
agentDefinitions: [
readFile('.claude/agents/backend-engineer.md'),
readFile('.claude/agents/frontend-engineer.md'),
readFile('.claude/agents/qa-engineer.md'),
readFile('.claude/agents/code-reviewer.md'),
],
taskContext: currentTask,
};
// Total: ~600-800 tokens
// Knows what each agent can do, delegates appropriately
Specialized Agents
Each agent loads only relevant context:
function loadAgentContext(agentType: string, targetFile: string): string {
const root = readFile('CLAUDE.md');
const agent = readFile(`.claude/agents/${agentType}.md`);
const package_ = findNearestClaude(targetFile);
return [root, agent, package_].join('\n\n---\n\n');
}
// Backend agent working on /packages/api/src/routes/users.ts:
const backendContext = loadAgentContext(
'backend-engineer',
'packages/api/src/routes/users.ts'
);
// Loads:
// 1. Root CLAUDE.md (40 lines)
// 2. backend-engineer.md (150 lines)
// 3. packages/api/CLAUDE.md (200 lines)
// Total: ~390 lines, all relevant
Context Isolation in Practice
// What each agent sees for a payment feature:
const backendAgent = {
context: [
'CLAUDE.md', // Shared patterns
'.claude/agents/backend.md', // Backend workflow
'packages/api/CLAUDE.md', // API patterns
'packages/domain/CLAUDE.md', // Business rules
],
canAccess: ['packages/api/**', 'packages/domain/**'],
};
const frontendAgent = {
context: [
'CLAUDE.md', // Shared patterns (same)
'.claude/agents/frontend.md', // Frontend workflow (different)
'packages/ui/CLAUDE.md', // UI patterns (different)
],
canAccess: ['packages/ui/**', 'apps/web/**'],
};
// Backend never sees UI patterns
// Frontend never sees API patterns
// Both follow shared naming and error handling
Implementation Patterns
Pattern 1: Explicit Context Injection
Pass context explicitly when spawning sub-agents:
async function spawnBackendAgent(task: string): Promise<Result<string>> {
const context = buildContext({
layers: ['root', 'backend-agent', 'api-package'],
task,
});
return await claude.complete({
system: context,
prompt: task,
allowedTools: ['Read', 'Write', 'Edit', 'Bash'],
allowedPaths: ['packages/api/**', 'packages/domain/**'],
});
}
Pattern 2: Directory-Based Auto-Loading
Load context based on file location:
function buildContextForFile(filePath: string): string {
const layers: string[] = [];
// Always load root
layers.push(readFile('CLAUDE.md'));
// Walk up from file to find CLAUDE.md files
let dir = path.dirname(filePath);
while (dir !== process.cwd()) {
const claudeFile = path.join(dir, 'CLAUDE.md');
if (existsSync(claudeFile)) {
layers.push(readFile(claudeFile));
}
dir = path.dirname(dir);
}
return layers.reverse().join('\n\n');
}
Pattern 3: Role-Based Context Registry
Register context requirements per agent role:
const contextRegistry = {
'backend-engineer': {
agentConfig: '.claude/agents/backend-engineer.md',
packageContexts: [
'packages/api/CLAUDE.md',
'packages/domain/CLAUDE.md',
],
toolAccess: ['Read', 'Write', 'Edit', 'Bash'],
pathRestrictions: ['packages/api/**', 'packages/domain/**'],
},
'frontend-engineer': {
agentConfig: '.claude/agents/frontend-engineer.md',
packageContexts: [
'packages/ui/CLAUDE.md',
],
toolAccess: ['Read', 'Write', 'Edit'],
pathRestrictions: ['packages/ui/**', 'apps/web/**'],
},
'code-reviewer': {
agentConfig: '.claude/agents/code-reviewer.md',
packageContexts: ['**/*'], // Can read everything
toolAccess: ['Read', 'Grep', 'Glob'], // Read-only
pathRestrictions: ['**/*'],
},
};
Context Boundaries
What to Share (Root Level)
Include in root context:
- Code style: Naming, formatting, file structure
- Error handling: Result patterns, logging conventions
- Type conventions: When to use interfaces vs types
- Quality standards: Testing requirements, lint rules
- Architecture overview: Package structure, dependency rules
What to Isolate (Agent/Package Level)
Keep domain-specific:
- Framework patterns: How to use tRPC, React, Temporal
- Business rules: Campaign workflows, payment processing
- API contracts: Endpoint structure, validation schemas
- UI patterns: Component structure, state management
- Database patterns: Schema conventions, migration rules
Boundary Violations to Avoid
// DON'T: Cross-domain patterns in root
const badRootContext = `
## Root CLAUDE.md
- Use tRPC for APIs (backend-specific)
- Use React Query for data fetching (frontend-specific)
- Workflows must be deterministic (Temporal-specific)
`;
// DO: Keep root generic, domains specific
const goodRootContext = `
## Root CLAUDE.md
- All functions have explicit return types
- Use Result pattern for operations that can fail
- Follow SOLID principles
`;
Benefits
1. Focused Attention
Each agent processes only relevant patterns:
Without isolation:
Backend agent loads: 2000 lines (API + UI + DB + Workflows)
Relevant content: 500 lines (25%)
With isolation:
Backend agent loads: 390 lines (Root + Agent + API)
Relevant content: 370 lines (95%)
2. Reduced Token Costs
Pay only for relevant context:
10 sub-agent calls without isolation:
10 × 2000 tokens = 20,000 tokens input
10 sub-agent calls with isolation:
10 × 400 tokens = 4,000 tokens input
Savings: 80%
3. Clear Responsibilities
Agents don’t attempt work outside their scope:
# Backend agent sees:
"You DON'T write frontend code (delegate to Frontend Engineer)"
# Frontend agent sees:
"You DON'T write API endpoints (delegate to Backend Engineer)"
# Result: Clear handoffs, no stepping on toes
4. Maintainability
Update domain patterns without affecting others:
# Update API patterns
echo "New validation rules" >> packages/api/CLAUDE.md
# Only backend agents see the change
# Update UI patterns
echo "New component patterns" >> packages/ui/CLAUDE.md
# Only frontend agents see the change
# Update shared patterns
echo "New error handling" >> CLAUDE.md
# All agents see the change
Common Pitfalls
Pitfall 1: Leaking Domain Context to Root
# BAD: Root CLAUDE.md
## API Patterns
- Use tRPC for type-safe APIs
- Always validate with Zod
# GOOD: Root CLAUDE.md
## Validation
- Always validate external input at boundaries
(Details in domain-specific CLAUDE.md files)
Pitfall 2: Duplicating Context Across Agents
# BAD: Same pattern in multiple agent files
# backend-engineer.md: "Use Result pattern..."
# frontend-engineer.md: "Use Result pattern..."
# GOOD: Pattern in root, referenced by agents
# Root CLAUDE.md: "Use Result pattern..."
# Agent files: "Follow error handling from root CLAUDE.md"
Pitfall 3: Missing Cross-Domain References
# BAD: Agent doesn't know where to look for related context
# backend-engineer.md: "Implement the payment endpoint"
# GOOD: Explicit cross-references
# backend-engineer.md:
"For payment business rules, see packages/domain/payments/CLAUDE.md"
"For API patterns, see packages/api/CLAUDE.md"
Pitfall 4: Over-Isolating Shared Concerns
# BAD: Every agent has its own error handling
# backend-engineer.md: "Return { success, data, error }"
# frontend-engineer.md: "Return { ok, result, message }"
# GOOD: Shared error handling in root
# Root CLAUDE.md: "All Result types: { success: boolean, data?: T, error?: string }"
Measuring Success
Context Relevance
Track how much loaded context applies to the task:
interface ContextMetrics {
totalLines: number;
relevantLines: number;
relevanceRatio: number;
}
// Target: >90% relevance for specialized agents
Token Efficiency
Monitor token usage per agent type:
interface TokenMetrics {
agentType: string;
avgContextTokens: number;
avgOutputTokens: number;
costPerTask: number;
}
// Target: <500 tokens context for specialized agents
Handoff Clarity
Track how often agents attempt out-of-scope work:
interface HandoffMetrics {
totalTasks: number;
correctDelegations: number;
boundaryViolations: number;
delegationAccuracy: number;
}
// Target: >95% correct delegations
Related
- Sub-Agent Architecture – Team structure and orchestration patterns
- Hierarchical Context Patterns – CLAUDE.md files at every level
- Progressive Disclosure Context – Load context only when needed
- Tool Access Control – Restricting agent capabilities
- Actor-Critic Adversarial Coding – Read-only reviewer pattern
- DDD Bounded Contexts for LLMs – Domain boundaries map to agent responsibilities
- Context Debugging Framework – Diagnosing context issues
- Clean Slate Trajectory Recovery – Reset when context is polluted
- Layered Prompts Architecture – Onion architecture for prompts
References
- Anthropic: Multi-Agent Systems – Official documentation on agent coordination
- Sub-Agent Architecture – Foundational patterns for specialized agents

