---
title: "Agent & Coordinator — Claude Code Internals — Vlad Arbatov"
description: "Subagents, coordinator mode, isolation, fork protocol, task management"
image: "https://arbatov.dev/share-claude.png"
---

# Agent & Coordinator System

## Overview

Claude Code implements a multi-agent orchestration system enabling:
- **Subagent spawning** via `AgentTool` — specialized workers for complex tasks
- **Coordinator mode** — orchestrates work across parallel agents with task-notification callbacks
- **Async/background execution** — agents run in background with user notifications
- **Agent isolation** — worktree (git) or remote CCR environments
- **Context inheritance** — forked agents inherit parent context with prompt cache sharing
- **Communication** — `SendMessage` tool to continue agents, `<task-notification>` XML for results

---

## AgentTool Architecture

### Input Schema (tools/AgentTool/AgentTool.tsx:82-100)

```typescript
const baseInputSchema = z.object({
  description: z.string(),              // 3-5 word summary
  prompt: z.string(),                   // Task instruction
  subagent_type?: z.string(),           // Agent type
  model?: z.enum(['sonnet','opus','haiku']),
  run_in_background?: z.boolean()
})

// Full schema adds:
isolation?: z.enum(['worktree','remote'])
cwd?: z.string()  // Mutually exclusive with isolation
```

### Execution Flow (tools/AgentTool/runAgent.ts, 973 lines)

1. **Validation** — Check permission, validate agent type, check MCP requirements
2. **Agent Selection** — Resolve `subagent_type` to AgentDefinition, load MCP servers
3. **Context Setup** — Create isolated context, build system prompt, assemble tool pool
4. **Async vs Sync Decision**:
   ```typescript
   const shouldRunAsync = (
     run_in_background === true ||
     selectedAgent.background === true ||
     isCoordinatorMode() ||
     isForkSubagentEnabled() ||
     proactiveModule?.isProactiveActive()
   ) && !isBackgroundTasksDisabled
   ```
5. **Isolation Setup** — Worktree, Remote, or CWD override
6. **Lifecycle Dispatch** — Foreground blocks parent; Async returns immediately

---

## Built-In Agent Types

### General-Purpose (tools/AgentTool/built-in/generalPurposeAgent.ts)
- **Tools**: All (`['*']`)
- **When**: General research, implementation, multi-step tasks

### Explore (tools/AgentTool/built-in/exploreAgent.ts)
- **Model**: `inherit` (ants) | `haiku` (external)
- **Tools**: Read-only — no Agent, Edit, Write, NotebookEdit
- **omitClaudeMd**: `true`
- **When**: Fast codebase exploration, file pattern matching, code search

### Plan (tools/AgentTool/built-in/planAgent.ts)
- **Model**: `inherit`
- **Tools**: Read-only (same as Explore)
- **omitClaudeMd**: `true`
- **When**: Design implementation strategies, architectural planning
- **Output**: Critical files list for implementation

### Fork Subagent (tools/AgentTool/forkSubagent.ts)
- **Activation**: Omit `subagent_type` when `isForkSubagentEnabled()` is true
- **Tools**: `['*']` with `useExactTools=true` (exact parent tool pool)
- **PermissionMode**: `bubble`
- **maxTurns**: 200
- **Key feature**: Maximizes prompt cache hits by using identical placeholder text in all fork children

**Fork Boilerplate**:
```
<fork-boilerplate>
You are a forked worker process. You are NOT the main agent.
RULES:
1. Do NOT spawn sub-agents; execute directly.
2. Use tools directly: Bash, Read, Write, etc.
3. If modifying files, commit. Include commit hash.
4. Keep report under 500 words.
5. Response MUST begin with "Scope:".
Output format:
  Scope: <assigned scope>
  Result: <findings>
  Key files: <paths>
  Files changed: <list with commit hash>
  Issues: <list>
</fork-boilerplate>
```

**Guard Against Recursive Forking**: Detects `<fork-boilerplate>` tag in message history.

---

## Coordinator Mode

### Activation (coordinator/coordinatorMode.ts:36-41)

Requires:
- `COORDINATOR_MODE` bundle feature gate
- `CLAUDE_CODE_COORDINATOR_MODE=1` environment variable

### Task Workflow

1. **Research phase**: Workers explore in parallel
2. **Synthesis phase**: Coordinator understands findings, crafts spec
3. **Implementation phase**: Workers make targeted changes
4. **Verification phase**: Workers test independently

### Worker Results Format

```xml
<task-notification>
<task-id>{agentId}</task-id>
<status>completed|failed|killed</status>
<summary>{outcome}</summary>
<result>{agent's response}</result>
<usage>
  <total_tokens>N</total_tokens>
  <tool_uses>N</tool_uses>
  <duration_ms>N</duration_ms>
</usage>
</task-notification>
```

---

## Agent Isolation

### Worktree Mode (utils/worktree.ts)

- **Activation**: `isolation: 'worktree'`
- **Path**: `.claude/worktrees/{slug}/`
- **Symlinks**: node_modules, build caches (prevents disk bloat)
- **Cleanup**: No changes → auto-remove; Changes exist → return path to parent

### Remote Isolation (CCR)

- **Activation**: `isolation: 'remote'` (ant-only)
- **Preconditions**: Claude.ai account, CCR configured
- Always async, polled for results

### CWD Override

- **Activation**: `cwd: string` (mutually exclusive with isolation)
- Direct working directory override without worktree

---

## Communication

### SendMessage Tool (tools/SendMessageTool/SendMessageTool.ts)

```typescript
const inputSchema = z.object({
  to: z.string(),  // agent name, "*" for broadcast, "uds:<socket>", "bridge:<session>"
  summary: z.string().optional(),
  message: z.union([z.string(), StructuredMessage()])
})
```

**Structured Messages**:
- `shutdown_request` / `shutdown_response`
- `plan_approval_response`

### Task Notifications

Delivered via `enqueueAgentNotification()` — injected into parent's conversation as XML.

---

## Task Management

### Task Types (tasks/types.ts)

1. **LocalAgentTask**: Local subagent (async or sync)
2. **RemoteAgentTask**: CCR environment (always async, polled)
3. **LocalShellTask**: Bash/PowerShell (inline)
4. **InProcessTeammateTask**: Teammate in current process

### Progress Tracking (tasks/LocalAgentTask/LocalAgentTask.tsx)

```typescript
type ProgressTracker = {
  toolUseCount: number
  latestInputTokens: number
  cumulativeOutputTokens: number
  recentActivities: ToolActivity[]  // Last 5
}
```

---

## Context Inheritance

### Subagent Context (utils/forkedAgent.ts:260-350)

**Cloned (isolated)**:
- `readFileState`: Fresh cache
- `abortController`: New linked controller
- `setAppState`: No-op (child can't mutate parent)
- `messages`: Fresh array

**Shared safely**:
- `options`: Parent's tools, model, hooks
- `getAppState`: Parent's read-only view

### Cache-Safe Fork Parameters

For prompt cache sharing:
1. System prompt must match parent
2. Tools schema must match
3. Model must match
4. Message prefix must match
5. Thinking config must match

**Rule**: Don't change model on forks — different model invalidates cache.

### CLAUDE.md Handling

- `omitClaudeMd: true` in Explore and Plan agents (saves tokens)
- Project guidance still accessible via direct Read

---

## Resource Limits

### Turn Limits

- Fork agent: 200 turns (fixed)
- Custom agents: Specified in frontmatter
- Built-in agents: Uncapped

### Background vs Foreground

| Aspect | Foreground | Background |
|--------|-----------|------------|
| Parent blocking | Yes | No |
| User input | Blocked | Available |
| Results | Direct in conversation | Task notification |
| Task panel | Not visible | Visible |
| Continuation | Automatic | Via SendMessage |
