Subagents

# Subagents Kit supports multi-agent orchestration through both subprocess spawning and in-process subagents. ## Subprocess pattern Spawn Kit as a subprocess for isolated agent execution: ```bash kit "Analyze codebase" \ --json \ --no-session \ --no-extensions \ --quiet \ --model anthropic/claude-haiku-latest ``` Key flags for subprocess usage: | Flag | Purpose | |------|---------| | `--quiet` | Stdout only, no TUI | | `--no-session` | Ephemeral, no persistence | | `--no-extensions` | Prevent recursive extension loading | | `--json` | Machine-readable output | | `--system-prompt` | Custom system prompt (string or file path) | Positional arguments are the prompt. `@file` arguments attach file content as context. ## Built-in subagent tool Kit includes a built-in `subagent` tool that the LLM can use to delegate tasks to independent child agents: ``` subagent( task: "Analyze the test files and summarize coverage", model: "anthropic/claude-haiku-latest", // optional system_prompt: "You are a test analysis expert.", // optional timeout_seconds: 300 // optional, max 1800 ) ``` Subagents run as separate in-process Kit instances with full tool access (except spawning further subagents, to prevent infinite recursion). They can run in parallel. ## Extension subagents Extensions can spawn subagents programmatically: ```go result := ctx.SpawnSubagent(ext.SubagentConfig{ Task: "Review this code for security issues", Model: "anthropic/claude-sonnet-latest", SystemPrompt: "You are a security auditor.", }) ``` ### Monitoring subagents from extensions When the LLM (not the extension itself) spawns a subagent using the `subagent` tool, extensions can monitor its activity in real-time using three lifecycle event handlers: ```go // Track active subagents and display their output var subagentWidgets map[string]*SubagentWidget func Init(api ext.API) { // Subagent started by the main agent api.OnSubagentStart(func(e ext.SubagentStartEvent, ctx ext.Context) { // e.ToolCallID — unique ID for this subagent invocation // e.Task — the task/prompt sent to the subagent widget := NewWidget(e.ToolCallID, e.Task) subagentWidgets[e.ToolCallID] = widget ctx.SetWidget(widget.Config()) }) // Real-time streaming from subagent api.OnSubagentChunk(func(e ext.SubagentChunkEvent, ctx ext.Context) { // e.ToolCallID — matches the start event // e.ChunkType — "text", "tool_call", "tool_execution_start", "tool_result" // e.Content — text content // e.ToolName — tool name (for tool chunks) // e.IsError — true if tool result failed widget := subagentWidgets[e.ToolCallID] if widget != nil { widget.AddOutput(e) ctx.SetWidget(widget.Config()) } }) // Subagent completed api.OnSubagentEnd(func(e ext.SubagentEndEvent, ctx ext.Context) { // e.Response — final response from subagent // e.ErrorMsg — error message if subagent failed widget := subagentWidgets[e.ToolCallID] if widget != nil { widget.MarkComplete(e.Response, e.ErrorMsg) ctx.SetWidget(widget.Config()) delete(subagentWidgets, e.ToolCallID) } }) } ``` **Event structs:** ```go type SubagentStartEvent struct { ToolCallID string // Unique ID for this subagent invocation Task string // The task/prompt sent to subagent } type SubagentChunkEvent struct { ToolCallID string // Matches SubagentStartEvent.ToolCallID Task string // Task description ChunkType string // "text", "tool_call", "tool_execution_start", "tool_result" Content string // For text chunks ToolName string // For tool-related chunks IsError bool // For tool_result chunks } type SubagentEndEvent struct { ToolCallID string // Matches start event Task string // Task description Response string // Final response from subagent ErrorMsg string // Error message if failed } ``` This enables building monitoring widgets that display real-time activity from all subagents spawned by the main agent. ## Go SDK subagents The SDK provides in-process subagent spawning: ```go result, err := host.Subagent(ctx, kit.SubagentConfig{ Task: "Summarize the changes in this PR", Model: "anthropic/claude-haiku-latest", SystemPrompt: "You are a code reviewer.", Timeout: 5 * time.Minute, }) ``` ### Real-time subagent events Use `SubscribeSubagent` to receive real-time events from LLM-initiated subagents (i.e., when the model uses the `subagent` tool). Register inside an `OnToolCall` handler using the tool call ID: ```go host.OnToolCall(func(e kit.ToolCallEvent) { if e.ToolName == "subagent" { host.SubscribeSubagent(e.ToolCallID, func(event kit.Event) { switch ev := event.(type) { case kit.MessageUpdateEvent: fmt.Print(ev.Chunk) // streaming text from child case kit.ToolCallEvent: fmt.Printf("Child calling: %s\n", ev.ToolName) case kit.ToolResultEvent: fmt.Printf("Child result: %s\n", ev.ToolName) } }) } }) ``` The listener receives the same event types as `Subscribe()` (`ToolCallEvent`, `MessageUpdateEvent`, `ReasoningDeltaEvent`, etc.) but scoped to the child agent's activity. Listeners are cleaned up automatically when the subagent completes. If no listeners are registered for a tool call, no event dispatching overhead is incurred.