In the previous Model Context Protocol (MCP) chapter, we learned how to extend claudeCode by connecting it to external tools and data sources. We gave the AI more "hands."
But sometimes, having more hands isn't enough. Sometimes, the task is so big (like "Refactor this entire legacy module") that a single AI agent gets overwhelmed, distracted, or runs out of context memory.
We don't just need more hands. We need more Brains.
Enter the AgentTool. This allows the main AI to spawn "Sub-Agents"βtemporary worker AIsβto handle complex sub-tasks and report back only when finished.
Think of the main claudeCode session as a Project Manager.
If you ask the manager to "Research a topic and write a report," they could do it themselves. But it is more efficient to hire a Contractor (Sub-Agent).
The AgentTool is the mechanism that allows this delegation. It encapsulates an entire AI conversation loop inside a single tool call.
Imagine you ask: "Check all 20 documentation files and tell me if we mention 'deprecated_api'."
We learned about the "Conversation Loop" in Query Engine. The AgentTool simply starts another Query Engine loop inside the current one.
The Sub-Agent starts with a fresh "mind." It doesn't necessarily carry all the baggage of the main conversation. This is crucial for performance and accuracy. It focuses only on the specific task assigned.
Does the Sub-Agent get to use the terminal? Yes. The AgentTool constructs a "Context" for the child that allows it to access the same capabilities (like BashTool or FileEditTool) that the parent has, but tracked separately.
This tool is used automatically by the system when it detects a complex task, or specifically by "Teammates" (which we will cover in the next chapter).
The Main AI calls the tool with a prompt and a definition of the worker.
{
"agent_name": "ResearchBot",
"task": "Read src/utils.ts and explain what it does.",
"tools": ["FileEditTool", "BashTool"]
}
The tool returns the final text response from the Sub-Agent.
"I have read src/utils.ts. It contains helper functions for date formatting."
The implementation of AgentTool is essentially a recursive function call. It pauses the current agent, creates a new ToolUseContext, runs a new query() loop, and waits for it to finish.
Here is the flow:
The core logic resides in tools/AgentTool/runAgent.ts. This file coordinates the creation and execution of the worker.
First, we create a specialized environment for the sub-agent. We determine what tools it is allowed to use.
// tools/AgentTool/runAgent.ts
// We figure out which tools the sub-agent gets
const resolvedTools = useExactTools
? availableTools
: resolveAgentTools(agentDefinition, availableTools).resolvedTools;
// We create a new "Context" object (memory, permissions, etc.)
const agentToolUseContext = createSubagentContext(toolUseContext, {
agentType: agentDefinition.agentType,
messages: initialMessages,
// Sync agents share the parent's terminal (AbortController)
abortController: isAsync ? new AbortController() : parentController,
});
Explanation: createSubagentContext is like setting up a new desk for a new employee. We give them their own tools and their own message history (initialMessages).
If the sub-agent needs special tools (like a specific database connection via Model Context Protocol (MCP)), we initialize them here.
// Connect to agent-specific MCP servers
const {
clients: mergedMcpClients,
cleanup: mcpCleanup
} = await initializeAgentMcpServers(
agentDefinition,
parentContext.mcpClients
);
Explanation: The sub-agent inherits the parent's tools, plus it can load its own specific "Skills" (defined as MCP servers).
This is the heart of the feature. We import the query function (the same engine that drives the main app) and run it for the sub-agent.
import { query } from '../../query.js';
// Start the loop!
for await (const message of query({
messages: initialMessages,
systemPrompt: agentSystemPrompt,
toolUseContext: agentToolUseContext, // The new isolated context
maxTurns: 20, // Prevent infinite loops
})) {
// If the sub-agent speaks, we might log it or just wait
if (isRecordableMessage(message)) {
recordSidechainTranscript(message);
}
}
Explanation: We run query() exactly like the main application does. However, we trap the messages inside recordSidechainTranscript instead of printing them directly to the main user output. This keeps the main chat clean.
When the sub-agent finishes (or crashes), we must clean up resources.
try {
// ... Run the loop ...
} finally {
// 1. Disconnect MCP servers specific to this agent
await mcpCleanup();
// 2. Kill any background processes (like a server the agent started)
killShellTasksForAgent(agentId);
// 3. Free up memory
agentToolUseContext.readFileState.clear();
}
Explanation: Since the sub-agent might have opened database connections or started background scripts, the finally block ensures we don't leave "zombie" processes running.
The AgentTool is the foundation for advanced AI collaboration:
AgentTool to create persistent personas (like "Architect" or "QA Tester") that you can summon by name.
You have learned that the AgentTool allows claudeCode to scale its intelligence. By spawning isolated Sub-Agents, the main AI can delegate complex tasks like research or large-scale refactoring without clogging up its own memory or context window. It uses recursion to run a fresh instance of the Query Engine, complete with its own tools and permissions.
Now that we have the ability to spawn generic sub-agents, let's give them names and personalities.
Generated by Code IQ