Sub-Agent Context Hierarchy: Managing Context Isolation in Multi-Agent Systems

James Phoenix
James Phoenix

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:

  1. Root context: Shared patterns all agents must follow (20-50 lines)
  2. Agent context: Role-specific behavioral flows (100-200 lines)
  3. 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:

Leanpub Book

Read The Meta-Engineer

A practical book on building autonomous AI systems with Claude Code, context engineering, verification loops, and production harnesses.

Continuously updated
Claude Code + agentic systems
View Book
# 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

References

Topics
Agent ArchitectureAgent OrchestrationContext EngineeringContext ManagementMulti Agent SystemsProgressive Disclosure

Newsletter

Become a better AI engineer

Weekly deep dives on production AI systems, context engineering, and the patterns that compound. No fluff, no tutorials. Just what works.

Join 306K+ developers. No spam. Unsubscribe anytime.


More Insights

Cover Image for Verified Spec-Driven Development (VSDD)

Verified Spec-Driven Development (VSDD)

Three methodologies that usually get argued about as rivals turn out to compose. Spec-driven development defines what, test-driven development enforces how, and adversarial verification checks that nothing was missed. Run them as sequential gates instead of competing philosophies and you get a pipeline where every line of code can be traced back to the requirement that demanded it.

James Phoenix
James Phoenix
Cover Image for “We Can’t Run Locally” Is a Concurrency Problem Now

“We Can’t Run Locally” Is a Concurrency Problem Now

The excuse survived a decade because one engineer’s feedback loop fitted inside one shared environment. Point twenty agents at that same environment and it stops being a slow loop and starts being a broken one.

James Phoenix
James Phoenix