tools/AgentTool/ — Sub-Agent Orchestration Tool
Spawns child agent tasks for parallel or delegated work
Creates sub-agents that can independently use tools, process queries, and return results. Core of the multi-agent architecture (swarms). Manages agent lifecycle, configuration loading, memory persistence, prompt caching, and result aggregation across built-in, custom, and plugin agent types.
📚 What is this & why does it exist?
AgentTool is how Claude Code delegates complex tasks to specialized sub-agents. Instead of one monolithic AI trying to do everything, AgentTool lets the parent agent spawn child workers — each with its own tool access, working directory, and system prompt. This is the foundation for features like parallel task execution, specialized exploration agents, and team-based multi-agent swarms.
💡 Real-world analogy
Think of AgentTool as a team lead who can hire temporary contractors. Each sub-agent gets its own workspace (potentially an isolated git worktree), tool access (a filtered set of available tools), and a clear assignment (the prompt). The team lead tracks progress, can run multiple contractors in parallel, and aggregates their reports into a final deliverable. Some contractors are built-in specialists (Explore, Plan), while others are custom-trained for specific project needs. The team lead manages their memory so past learnings carry forward across sessions.
Contents
Architecture
flowchart TD
A["Parent Agent"] -->|"tool_use: Agent"| B["AgentTool.call()"]
B --> C{"Fork enabled?"}
C -->|"yes + no subagent_type"| D["buildForkedMessages()"]
C -->|"no / explicit type"| E{"team_name set?"}
E -->|"yes"| F["spawnTeammate()"]
E -->|"no"| G["resolveAgentTools()"]
D --> H["runAgent() with fork context"]
F --> I["Multi-agent spawn"]
G --> J["filterToolsForAgent()"]
J --> K["loadAgentMemoryPrompt()"]
K --> L["runAgent() async generator"]
L --> M["Stream events + progress"]
M --> N{"Background?"}
N -->|"yes"| O["Register LocalAgentTask"]
N -->|"no"| P["finalizeAgentTool()"]
O --> P
Agent Type Hierarchy
flowchart LR AD["AgentDefinition"] --> BA["BuiltInAgentDefinition"] AD --> CA["CustomAgentDefinition"] AD --> PA["PluginAgentDefinition"] BA --> EX["Explore agent"] BA --> PL["Plan agent"] BA --> FK["Fork agent"] CA --> MD["Markdown config"] CA --> JS["JSON settings"] PA --> MCP["MCP plugin agents"] style BA fill:#1a3a2a,stroke:#3fb950 style CA fill:#2a2a1a,stroke:#d29922 style PA fill:#2a1a2a,stroke:#f85149
Key Classes & Functions
| Class / Function | File | Purpose |
|---|---|---|
AgentTool | AgentTool.tsx | Main tool definition via buildTool(); handles fork routing, team spawning, agent selection, worktree isolation |
runAgent() | runAgent.ts | Core async generator: MCP setup, tool assembly, system prompt construction, stream event generation (973 LOC) |
resumeAgentBackground() | resumeAgent.ts | Resumes interrupted background agents; restores state from persisted messages |
filterToolsForAgent() | agentToolUtils.ts | Filters parent tool set for agent context; blocks disallowed/async tools |
resolveAgentTools() | agentToolUtils.ts | Resolves agent tool spec ('*' wildcard, explicit list) to actual tool instances |
finalizeAgentTool() | agentToolUtils.ts | Generates final tool result with usage stats, model info, context metadata |
buildForkedMessages() | forkSubagent.ts | Builds byte-identical message prefixes for fork children (prompt cache sharing) |
isForkSubagentEnabled() | forkSubagent.ts | Feature gate check for implicit fork when subagent_type omitted |
getAgentDefinitionsWithOverrides() | loadAgentsDir.ts | Loads agents from all sources: built-in, user (~/.claude), project (.claude), plugin, CLI args |
getBuiltInAgents() | builtInAgents.ts | Returns built-in agent definitions (Explore, Plan) gated by feature flags |
loadAgentMemoryPrompt() | agentMemory.ts | Loads MEMORY.md contents with scope-specific guidelines; injects into system prompt |
checkAgentMemorySnapshot() | agentMemorySnapshot.ts | Detects newer project snapshots; returns initialize | prompt-update | none |
getAgentColor() | agentColorManager.ts | Assigns unique color to agent type for UI grouping (8 colors) |
resolveAgentOverrides() | agentDisplay.ts | Deduplicates agents by source priority; marks overridden agents for display |
getPrompt() | prompt.ts | Generates agent list injection for system prompt; formats available agents |
Data Structures
| Type | Name | Description |
|---|---|---|
| Input | prompt | Task description and instructions for the sub-agent |
| Input | subagent_type | Agent type selector: general-purpose, explore, plan, fork, or custom name |
| Input | description | 3–5 word human-readable summary for UI display |
| Input | model | Model override: sonnet | opus | haiku | inherit |
| Input | isolation | Execution isolation: worktree (git) or remote (CCR) |
| Input | name / team_name | Multi-agent addressing: agent name + team name for swarm spawning |
| Output | AgentToolResult | Status (success | failed | timeout | killed), usage stats, model, agent ID |
| Type | AgentMemoryScope | user | project | local — memory persistence scope |
| Type | AgentColorName | 8 colors for UI: red, blue, green, yellow, purple, orange, pink, cyan |
| Type | ResolvedAgentTools | Resolved tool spec with valid/invalid tools, wildcard flag, allowed types |
| Const | ONE_SHOT_BUILTIN_AGENT_TYPES | Built-in agents that skip agentId/SendMessage to save tokens |
| Const | FORK_SUBAGENT_TYPE | Type identifier for fork-based sub-agents: 'fork' |
Interactions
| Direction | Partner | Interface | Description |
|---|---|---|---|
| → | Model API | queryModelWithStreaming() | Sub-agent makes its own API calls with inherited or overridden model |
| → | MCP servers | initializeAgentMcpServers() | Initializes agent-specific MCP server connections; tracks new vs shared clients |
| → | Permission system | ToolPermissionContext | Supports plan | acceptEdits | bubble permission modes per agent |
| → | Git worktrees | createAgentWorktree() | Creates isolated git worktree for parallel file operations without conflicts |
| → | Task system | LocalAgentTask | Background agents registered as async tasks with streaming progress |
| → | Memory filesystem | ~/.claude/agent-memory/ | Persists and loads agent-specific MEMORY.md across sessions |
| ← | Parent AgentLoop | tool_use block | Receives spawn request from model’s tool call |
| → | Skills system | loadSkillsDir() | Plugin agents may activate additional skills on demand |
| → | Analytics | logEvent() | Records agent spawn, completion, token usage, and model selection |
| ↔ | SendMessageTool | spawnTeammate() | Multi-agent swarm: teammates communicate via SendMessage |
Agent Source Priority
When multiple sources define agents with the same type, higher-priority sources override lower ones. The resolution order (highest to lowest):
- CLI argument agents — Passed via command-line flags, highest priority
- User agents — Defined in
~/.claude/agents/(markdown or JSON) - Project agents — Defined in
.claude/agents/(shared via VCS) - Local agents — Machine-specific, not in version control
- Managed agents — Organization-provided agent definitions
- Plugin agents — Loaded from MCP plugin servers
- Built-in agents — Explore, Plan, Fork (lowest priority, always available)
Configuration
| Knob / Parameter | Default | Description |
|---|---|---|
maxTurns | 200 | Maximum conversation turns before agent auto-terminates |
model | inherit | Model selection: sonnet, opus, haiku, or inherit from parent |
permissionMode | bubble | Permission handling: plan | acceptEdits | bubble to parent |
memory | none | Memory scope: user | project | local for MEMORY.md persistence |
isolation | none | Execution isolation: worktree (git) or remote (CCR) |
tools | ['*'] | Tool allowlist; '*' expands to all minus restricted set |
disallowedTools | [] | Tool denylist; takes precedence over allowlist |
FORK_SUBAGENT gate | off | Feature flag enabling implicit fork when subagent_type omitted |
BUILTIN_EXPLORE_PLAN_AGENTS | on | Feature flag for Explore & Plan built-in agents |
tengu_auto_background_agents | off | Auto-background agents after 120s timeout |
CLAUDE_CODE_SIMPLE | false | Env var: skip custom agents, load only built-ins |
CLAUDE_CODE_REMOTE_MEMORY_DIR | unset | Mount point for persistent agent memory in remote environments |
Directory Map
Source tree for AgentTool
AgentTool/
├── AgentTool.tsx ← Main tool definition: call(), fork routing, team spawn, worktree
├── UI.tsx ← React rendering: agent progress, status badges, color display
├── agentColorManager.ts ← Color assignment for multi-agent UI grouping (8 colors)
├── agentDisplay.ts ← Agent deduplication, override resolution, source grouping
├── agentMemory.ts ← MEMORY.md loading with user/project/local scopes
├── agentMemorySnapshot.ts ← Project snapshot sync: initialize, replace, mark synced
├── agentToolUtils.ts ← Tool filtering, resolution, finalization, async lifecycle
├── built-in/ ← Built-in agent prompt templates and definitions
├── builtInAgents.ts ← Explore, Plan, Fork agent definitions with feature gates
├── constants.ts ← AGENT_TOOL_NAME, ONE_SHOT types, disallowed tool lists
├── forkSubagent.ts ← Fork experiment: message building, cache sharing, guards
├── loadAgentsDir.ts ← Multi-source agent loading: markdown, JSON, plugins, CLI
├── prompt.ts ← Agent list injection, formatting, system prompt generation
├── resumeAgent.ts ← Background agent resumption from persisted state
└── runAgent.ts ← Core execution engine: MCP, tools, streaming (973 LOC)
Deep-Dive Highlights
Core mechanisms from AgentTool have been extracted into dedicated focus pages for in-depth exploration. Each page covers one algorithm, protocol, or subsystem with diagrams, code walks, and configuration details.
Deep-Dive Pages
Fork Sub-Agent Experiment Focus
Byte-identical message prefixes for prompt cache sharing, recursive fork guards, per-child directives, and worktree context notices.
Agent Memory System Focus
Three-scope memory persistence (user, project, local), snapshot synchronization, remote mount support, and MEMORY.md lifecycle.
Agent Loading & Resolution Focus
Multi-source agent discovery from markdown, JSON, plugins, and CLI args. Override priority, deduplication, and MCP requirement filtering.
Execution Engine & Streaming Focus
The runAgent() async generator: MCP initialization, tool pool assembly, system prompt construction, stream event generation, and Perfetto tracing.
Code Examples
Example: Agent Tool Resolution with Wildcards
// agentToolUtils.ts — Resolve agent tool spec to actual tools
export function resolveAgentTools(
agentDef: AgentDefinition,
availableTools: Tools,
): ResolvedAgentTools {
const toolSpec = agentDef.tools ?? ['*'];
const hasWildcard = toolSpec.includes('*');
if (hasWildcard) {
// Expand '*' to all available tools minus restricted set
const restricted = new Set([
...ALL_AGENT_DISALLOWED_TOOLS,
...(agentDef.disallowedTools ?? []),
]);
return {
hasWildcard: true,
validTools: availableTools
.filter(t => !restricted.has(t.name))
.map(t => t.name),
invalidTools: [],
resolvedTools: availableTools.filter(t => !restricted.has(t.name)),
};
}
// Explicit tool list — validate each name exists
const validTools: string[] = [];
const invalidTools: string[] = [];
for (const name of toolSpec) {
if (name.startsWith('mcp__') || availableTools.find(t => t.name === name)) {
validTools.push(name);
} else {
invalidTools.push(name);
}
}
return { hasWildcard, validTools, invalidTools,
resolvedTools: availableTools.filter(t => validTools.includes(t.name)) };
}
Example: Fork Message Building for Cache Sharing
// forkSubagent.ts — Build byte-identical prefixes for fork children
export function buildForkedMessages(
directive: string,
assistantMessage: AssistantMessage,
): MessageType[] {
// All fork children share identical placeholder results for tool_use blocks
// Only the final directive text differs per child → maximizes cache hits
const placeholderResults = assistantMessage.content
.filter(block => block.type === 'tool_use')
.map(block => ({
type: 'tool_result' as const,
tool_use_id: block.id,
content: 'Fork started — processing in background',
}));
return [
...historyMessages,
{ role: 'assistant', content: assistantMessage.content },
{ role: 'user', content: [
...placeholderResults,
{ type: 'text', text: buildChildMessage(directive) },
]},
];
}