Studio Notebook

Claude Code Atlas

Agent Tool And Subagent Lifecycle

Learn how AgentTool launches specialized agents, backgrounds work, and builds subagent prompts.

Why this matters

AgentTool is where one tool call stops being “do one local action” and starts becoming “launch a second worker with its own lifecycle.”

Big picture first

Read AgentTool in three passes:

  1. the input/output schema in AgentTool.tsx
  2. the long instructional prompt in AgentTool/prompt.ts
  3. the actual execution path that eventually calls runAgent(...)

Agent prompt excerpt

tools/AgentTool/prompt.ts

## When to fork

Fork yourself (omit `subagent_type`) when the intermediate tool output isn't worth keeping in your context.

Start with the schema

const baseInputSchema = lazySchema(() => z.object({
  description: z.string().describe('A short (3-5 word) description of the task'),
  prompt: z.string().describe('The task for the agent to perform'),
  subagent_type: z.string().optional().describe('The type of specialized agent to use for this task'),
  model: z.enum(['sonnet', 'opus', 'haiku']).optional().describe("Optional model override for this agent."),
  run_in_background: z.boolean().optional().describe('Set to true to run this agent in the background. You will be notified when it completes.')
}));
const fullInputSchema = lazySchema(() => {
  const multiAgentInputSchema = z.object({
    name: z.string().optional().describe('Name for the spawned agent. Makes it addressable via SendMessage({to: name}) while running.'),
    team_name: z.string().optional().describe('Team name for spawning. Uses current team context if omitted.'),
    mode: permissionModeSchema().optional().describe('Permission mode for spawned teammate (e.g., "plan" to require plan approval).')
  });
  return baseInputSchema().merge(multiAgentInputSchema).extend({
    isolation: z.enum(['worktree']).optional().describe('Isolation mode. "worktree" creates a temporary git worktree so the agent works on an isolated copy of the repo.'),
    cwd: z.string().optional().describe('Absolute path to run the agent in. Overrides the working directory for all filesystem and shell operations within this agent. Mutually exclusive with isolation: "worktree".')
  });
});

This tells you the real surface area. AgentTool is not only “prompt plus subagent type.” It also covers names, teams, permission mode, backgrounding, and worktree isolation.

The prompt is part of the tool design

AgentTool/prompt.ts is long because the tool is teaching the model how to delegate well, not just how to fill out JSON. The most important idea for a first read is that the prompt distinguishes fresh specialized agents from forked self-agents and warns the model not to fabricate unfinished results.

Where execution actually starts

export const AgentTool = buildTool({
  async prompt({
    agents,
    tools,
    getToolPermissionContext,
    allowedAgentTypes
  }) {
    const toolPermissionContext = await getToolPermissionContext();
    return await getPrompt(filteredAgents, isCoordinator, allowedAgentTypes);
  },
  name: AGENT_TOOL_NAME,
  searchHint: 'delegate work to a subagent',
  async call({
    prompt,
    subagent_type,
    description,
    model: modelParam,
    run_in_background,
    name,
    team_name,
    mode: spawnMode,
    isolation,
    cwd
  }: AgentToolInput, toolUseContext, canUseTool, assistantMessage, onProgress?) {

The call(...) path is where delegation becomes real lifecycle management. AgentTool.tsx does not just emit a prompt. It decides how the agent runs, whether it should be backgrounded, and whether to use worktree isolation, then hands execution off to helpers like runAgent(...), async-task registration, and worktree management.

Takeaways

  • AgentTool is a delegation runtime, not just a wrapper around prompts.
  • Its prompt file teaches the model how to delegate safely and when to fork.
  • The schema already reveals key lifecycle ideas like backgrounding, isolation, and teammate routing.