Claude Code supports spawning multiple sub-agents that work in parallel or sequentially on complex tasks. The agent system supports local execution, git worktree isolation, remote execution, fork-based context sharing, inter-agent messaging, and team-based coordination. The implementation lives primarily in src/tools/AgentTool/ with supporting infrastructure in src/tasks/, src/coordinator/, and src/utils/swarm/.
AgentTool (src/tools/AgentTool/AgentTool.tsx) is the primary mechanism for creating sub-agents. The tool accepts a prompt, optional agent type, and execution parameters to determine how the agent runs.
The AgentTool input schema includes:
| Parameter | Type | Description |
|---|---|---|
prompt |
string (required) | The task for the agent to perform |
description |
string (required) | Short 3-5 word task summary |
subagent_type |
string (optional) | Specialized agent type to use |
model |
enum (optional) | Model override: sonnet, opus, or haiku |
run_in_background |
boolean (optional) | Run asynchronously, return task ID |
name |
string (optional) | Addressable name for SendMessage routing |
team_name |
string (optional) | Team context for spawning |
mode |
string (optional) | Permission mode for the agent |
isolation |
enum (optional) | "worktree" for git isolation, "remote" for cloud |
cwd |
string (optional) | Working directory override |
The tool determines execution mode based on the combination of parameters:
AgentTool.call(input)
|
+-- subagent_type omitted + fork enabled --> Fork Agent
| (inherits parent context)
|
+-- isolation: "worktree" -----------------> Worktree Agent
| (isolated git copy)
|
+-- isolation: "remote" -------------------> Remote Agent (CCR)
| (cloud environment)
|
+-- run_in_background: true ---------------> Background Agent
| (async, returns task ID)
|
+-- Default -------------------------------> Foreground Agent
(blocks until complete)
When no special isolation or background mode is requested:
- Calls
runAgent()(src/tools/AgentTool/runAgent.ts) which invokes thequery()function with isolated state - Gets its own token budget and file state cache (cloned from parent via
cloneFileStateCache) - Inherits parent's tool permissions but with agent-specific tool restrictions applied via
resolveAgentTools() - Parent's messages are normalized for isolation
- Runs the full query loop within the same process, blocking the parent until completion
- Result is returned directly as the tool result
When the fork subagent feature is enabled (src/tools/AgentTool/forkSubagent.ts) and subagent_type is omitted:
- Creates a child that inherits the parent's full conversation context and system prompt
- Uses
buildForkedMessages()to construct the child's message history: all parent tool_use blocks get identical placeholder results for prompt cache sharing, with a per-child directive appended - Always runs in the background (async) for a unified
<task-notification>model - Fork children are explicitly instructed not to spawn sub-agents themselves (recursive forking is blocked by detecting the
fork_boilerplatetag in history) - The
FORK_AGENTdefinition usestools: ['*']withuseExactToolsto receive the parent's exact tool pool for cache-identical API prefixes permissionMode: 'bubble'surfaces permission prompts to the parent terminalmodel: 'inherit'preserves the parent's model for context length parity and cache sharing- Mutually exclusive with coordinator mode and non-interactive sessions
When isolation: "worktree" is specified:
createAgentWorktree()(src/utils/worktree.ts) creates a temporary git worktree with its own branch- Agent operates on a fully isolated copy of the repository
- On completion,
hasWorktreeChanges()checks if the agent made modifications - If no changes: worktree is auto-cleaned via
removeAgentWorktree() - If changes exist: worktree path and branch name are returned in the result, allowing the parent to merge
- Fork agents can also use worktrees; a notice is injected via
buildWorktreeNotice()telling the child to translate paths from the parent context
When run_in_background: true or the agent definition has background: true:
- Registered as an async task via
registerAsyncAgent()with a unique agent ID - Control returns to the parent immediately with the task ID and output file path
- The agent runs via
runAsyncAgentLifecycle()which manages progress tracking, summarization, and notification - On completion,
enqueueAgentNotification()delivers a<task-notification>to the parent's message queue - Parent can also check progress via TaskGetTool / TaskOutputTool
- Parent can send follow-up messages via SendMessageTool (which auto-resumes stopped agents)
When isolation: "remote" is specified (restricted to internal Anthropic users):
checkRemoteAgentEligibility()validates preconditions (MCP servers, resource limits)registerRemoteAgentTask()creates aRemoteAgentTaskStateentry- The agent is teleported to a separate cloud environment via
teleportToRemote() - Always runs as a background task; parent is notified when complete
- Remote session events are polled via
pollRemoteSessionEvents() - Used for heavy or long-running workloads in trusted sandbox environments
Built-in agents are defined in src/tools/AgentTool/built-in/ and assembled by getBuiltInAgents() in src/tools/AgentTool/builtInAgents.ts.
| Agent Type | Purpose | Model | Key Restrictions |
|---|---|---|---|
general-purpose |
Default agent for multi-step tasks, code search, research | Default subagent model | All tools (['*']) |
Explore |
Fast read-only codebase exploration (glob, grep, read) | haiku (external), inherit (internal) | No Agent, Edit, Write, NotebookEdit, ExitPlanMode |
Plan |
Architecture and implementation planning (read-only) | inherit | No Agent, Edit, Write, NotebookEdit, ExitPlanMode |
verification |
Adversarial testing of implementation work | inherit | No Agent, Edit, Write, NotebookEdit, ExitPlanMode; always background |
claude-code-guide |
Help users understand Claude Code, Agent SDK, Claude API | (default) | Non-SDK entrypoints only |
statusline-setup |
Create/update statusLine settings from shell PS1 config | (default) | Specialized for settings |
Each agent definition (AgentDefinition type in src/tools/AgentTool/loadAgentsDir.ts) includes:
type BaseAgentDefinition = {
agentType: string // Unique identifier
whenToUse: string // Description shown to the model
tools?: string[] // Allowlisted tools (undefined = all)
disallowedTools?: string[] // Denylisted tools
skills?: string[] // Skill names to preload
mcpServers?: AgentMcpServerSpec[] // Agent-specific MCP servers
hooks?: HooksSettings // Session-scoped hooks
color?: AgentColorName // Visual color in UI
model?: string // Model override or 'inherit'
effort?: EffortValue // Reasoning effort level
permissionMode?: PermissionMode
maxTurns?: number // Max agentic turns before stopping
background?: boolean // Always run as background task
initialPrompt?: string // Prepended to first user turn
memory?: AgentMemoryScope // Persistent memory: 'user' | 'project' | 'local'
isolation?: 'worktree' | 'remote'
omitClaudeMd?: boolean // Skip CLAUDE.md for read-only agents
}Agents can come from multiple sources, with later sources overriding earlier ones for the same agentType:
- Built-in (
source: 'built-in'): Hardcoded insrc/tools/AgentTool/built-in/ - Plugin (
source: 'plugin'): Loaded vialoadPluginAgents() - User settings (
source: 'userSettings'): From user's~/.claude/agents/directory - Project settings (
source: 'projectSettings'): From project's.claude/agents/directory - Flag settings (
source: 'flagSettings'): From GrowthBook feature flags (JSON format) - Policy/managed (
source: 'policySettings'): From enterprise/managed policy
Custom agents are defined as markdown files with YAML frontmatter containing the agent metadata, and the markdown body serving as the system prompt. They can also be defined in JSON format via parseAgentFromJson().
SendMessageTool (src/tools/SendMessageTool/SendMessageTool.ts) routes messages between agents using a mailbox-based system.
Message Types (discriminated union):
| Type | Description |
|---|---|
| Plain text string | Regular message content (requires summary) |
shutdown_request |
Ask a teammate to shut down (with optional reason) |
shutdown_response |
Approve or reject a shutdown request |
plan_approval_response |
Approve or reject a plan (team lead only) |
Routing targets:
- By name: Routes to a specific teammate by name or agent ID
- Broadcast (
to: "*"): Sends to all teammates in the current team (except sender) - UDS socket (
to: "uds:<path>"): Cross-session local peer messaging - Bridge (
to: "bridge:<session-id>"): Cross-machine Remote Control peer messaging
Agent resumption: When a message is sent to a stopped agent (via name or agent ID), SendMessageTool automatically resumes it via resumeAgentBackground(). The agent is reconstituted from its disk transcript with the new message appended, preserving full context. Running agents receive messages via queuePendingMessage() for delivery at their next tool round.
Mailbox system: Messages are written to per-agent mailbox files via writeToMailbox() (src/utils/teammateMailbox.ts). Each message includes sender name, text content, timestamp, summary, and optional color for UI display.
Teams are managed through two tools:
TeamCreateTool (src/tools/TeamCreateTool/TeamCreateTool.ts):
- Creates a named team with a team file on disk
- Registers the team lead with a unique agent ID
- Each team member gets an assigned color via
assignTeammateColor() - Team file tracks all members, their pane IDs, backend types, and colors
TeamDeleteTool (src/tools/TeamDeleteTool/TeamDeleteTool.ts):
- Cleans up a team and its resources
Teams support multiple backend types for spawning teammates:
- In-process: Runs within the same process (used for in-process teammates)
- Tmux: Spawns in a tmux pane
- iTerm: Spawns in an iTerm tab
Coordinator mode (src/coordinator/coordinatorMode.ts) is a distinct operating mode enabled via CLAUDE_CODE_COORDINATOR_MODE=1:
- The coordinator gets a special user context listing available worker tools via
getCoordinatorUserContext() - Worker tools are filtered to exclude internal team management tools (TeamCreate, TeamDelete, SendMessage, SyntheticOutput)
- The coordinator uses
getCoordinatorAgents()to get coordinator-specific agent definitions - Session mode is persisted; resuming a coordinator session re-enters coordinator mode via
matchSessionMode() - Mutually exclusive with fork subagent mode
Tasks are tracked in the application state with the following lifecycle:
registered --> running --> completed
| |
+--> failed +--> Results available via
| TaskOutputTool at output_file
+--> stopped
(by TaskStopTool or abort)
Task infrastructure (in src/tasks/):
- LocalAgentTask (
src/tasks/LocalAgentTask/LocalAgentTask.tsx): Tracks in-process agent execution with progress metrics (tool use count, token count, recent activities) - RemoteAgentTask (
src/tasks/RemoteAgentTask/RemoteAgentTask.tsx): Tracks remote cloud agent sessions with polling-based progress - LocalShellTask (
src/tasks/LocalShellTask/): Tracks shell command execution within agents
Progress tracking:
Each agent maintains a ProgressTracker with:
toolUseCount: Number of tool invocationslatestInputTokens: Latest cumulative input token countcumulativeOutputTokens: Sum of all output tokensrecentActivities: Last 5 tool activities with descriptions
Task management tools:
| Tool | Purpose |
|---|---|
TaskListTool |
List all registered tasks with status |
TaskGetTool |
Get detailed info for a specific task |
TaskOutputTool |
Read the output file of a completed task |
TaskStopTool |
Stop/abort a running task |
Output persistence: Agent output is written to disk via initTaskOutputAsSymlink() / appendTaskOutput(). The output file path follows the pattern tied to the agent ID, accessible via getTaskOutputPath().
Agents can have persistent memory scoped to different levels (src/tools/AgentTool/agentMemory.ts):
user: Per-user memory, synced via project snapshotsproject: Per-project memorylocal: Local-only memory
Memory is loaded via loadAgentMemoryPrompt() and appended to the agent's system prompt. When memory is enabled, file read/write/edit tools are automatically injected into the agent's tool set. Snapshot initialization (agentMemorySnapshot.ts) handles copying project snapshots to local storage on first use.
Agents can declare their own MCP servers (mcpServers in the agent definition) that are additive to the parent's MCP clients:
- Servers can be referenced by name (matching an existing configured server) or defined inline with full config
initializeAgentMcpServers()connects agent-specific servers when the agent starts- Cleanup function disconnects them when the agent finishes
- Agent availability can be gated on required MCP servers via
requiredMcpServers(pattern matching against available server names)
The agent system includes several optimizations for API prompt cache sharing:
- Agent list attachment: The dynamic agent list can be injected as an attachment message rather than embedded in the tool description, preventing cache busts when MCP servers or permissions change (
shouldInjectAgentListInMessages()) - Fork prefix sharing: All fork children produce byte-identical API request prefixes using placeholder tool results, with only the final directive text block differing per child
- Model inheritance: Fork agents use
model: 'inherit'to stay on the parent's model, enabling cache reuse - Exact tool pools: Fork agents receive the parent's exact tool definitions (
useExactTools: true) for cache-identical tool schemas
- Factory: AgentTool creates the appropriate task type (local, remote, worktree, fork) based on input parameters
- Observer/Event Queue: LocalAgentTask uses progress tracking with notification enqueueing for async completion
- Mediator: SendMessageTool routes messages between agents via mailbox files, handling running, stopped, cross-session, and cross-machine targets
- Worker Pool: Team agents execute in parallel via tmux/iTerm/in-process backends with shared coordination through team files
- Decorator: Agent MCP servers are additive wrappers around the parent's MCP client pool
- Resume from Transcript: Stopped agents can be reconstituted from their disk-persisted transcript, enabling long-lived agent identities across sessions