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:

Udemy Bestseller

Learn Prompt Engineering

My O'Reilly book adapted for hands-on learning. Build production-ready prompts with practical exercises.

4.5/5 rating
306,000+ learners
View Course
  • 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

References

Topics
Agent ArchitectureContext InheritanceContext IsolationContext ManagementHierarchical ContextMulti AgentOrchestrationSpecialized AgentsSub Agents

More Insights

Cover Image for Own Your Control Plane

Own Your Control Plane

If you use someone else’s task manager, you inherit all of their abstractions. In a world where LLMs make software a solved problem, the cost of ownership has flipped.

James Phoenix
James Phoenix
Cover Image for Indexed PRD and Design Doc Strategy

Indexed PRD and Design Doc Strategy

A documentation-driven development pattern where a single `index.md` links all PRDs and design documents, creating navigable context for both humans and AI agents.

James Phoenix
James Phoenix