Subagents
When a task is too large or has independent parts that can be worked on simultaneously, Otto breaks it into subtasks and dispatches them to subagents. Each subagent runs in parallel on its own back...
When a task is too large or has independent parts that can be worked on simultaneously, Otto breaks it into subtasks and dispatches them to subagents. Each subagent runs in parallel on its own background worker with its own tools and iteration budget. The parent task waits for all subagents to finish, collects their results, and synthesizes a final answer.
When Otto Uses Subagents
Otto decides to use subagents when a task has components that benefit from parallel execution. Common scenarios include:
- Research tasks that require investigating multiple topics independently ("Compare pricing models for AWS, GCP, and Azure")
- Multi-part deliverables where each section can be produced separately ("Create a market analysis with competitive landscape, pricing analysis, and customer segmentation sections")
- Tool-heavy workflows where different tools are needed for different parts of the work
The decision to dispatch subagents is made by the parent agent during its normal reasoning process. It is not a manual configuration -- Otto evaluates the task and dispatches when parallelization will improve quality or speed.
How Dispatch Works
-
The parent agent calls
dispatch_subagent. For each subtask, the agent provides a task description, context from the parent task, an agent type, and optional configuration (iteration limit, token budget). -
Subtasks are created and queued. Each dispatch creates a new task record in the database with
task_type: subtasklinked to the parent task. The subtask is enqueued to a background worker queue. -
The parent is automatically parked. After dispatching, the parent task enters the "waiting_subagents" status. Its execution state is checkpointed to Redis so it can resume exactly where it left off. This happens automatically -- the parent does not need to explicitly pause.
-
Subagents execute in parallel. Each subagent gets its own LangGraph execution loop, its own MCP server connections, and its own iteration budget. Subagents run independently and do not communicate with each other.
-
Results are collected. When all subagents reach a terminal state (completed or failed), their results are gathered into a combined response.
-
The parent resumes. The parent agent's state is restored from the checkpoint and it receives all subagent results as tool responses. It then synthesizes the results into a final deliverable.
Fast path. If all dispatched subtasks complete before the parent's checkpoint is written (for example, very simple subtasks), the parent skips parking entirely and continues with the results inline.
How Results Are Collected
When the last subagent in a batch finishes, a completion hook runs:
- Check if all sibling subtasks for the parent are in a terminal state.
- Acquire a distributed lock (Redis SETNX, 60-second TTL) to prevent double-resume when two subagents finish at nearly the same time.
- Collect results from all subtasks -- completed tasks contribute their output, failed tasks contribute a failure notice.
- Resume the parent agent with the collected results.
The parent agent receives the combined results as if they were responses to its dispatch_subagent tool calls, and proceeds with its normal reasoning loop.
Subagent Types
When dispatching a subagent, Otto selects an agent type that determines the subagent's capabilities and system prompt.
General
The default subagent type. Has access to most tools and is suitable for a wide range of tasks.
- Available tools: All tools except
ask_humananddispatch_subagent - Use case: Writing, analysis, document creation, tool-heavy workflows
Research
Optimized for information gathering and synthesis. Cannot modify files or send emails, ensuring it stays focused on reading and researching.
- Available tools: Search tools, file reading, memory -- no
write_file,send_email,ask_human, ordispatch_subagent - Use case: Web research, document analysis, competitive intelligence, literature review
Tool-Specialist
Designed for chained tool operations where the focus is on executing a multi-step workflow efficiently.
- Available tools: All tools except
ask_human,dispatch_subagent, andsend_email - Use case: Data processing pipelines, file transformations, automated workflows
All subagent types share a common restriction: they cannot ask humans for input and they cannot dispatch their own subagents. This prevents recursive delegation and ensures subagents complete their work independently.
Monitoring Subagents in the UI
Task List View
Parent tasks that have dispatched subagents show subagent pills -- small badges next to the task card. Each pill represents one subtask and is color-coded by status:
| Color | Status |
|---|---|
| Blue | Running |
| Green | Completed |
| Red | Failed |
| Orange | Waiting |
Clicking a pill expands a peek panel inline, showing the subtask's title, status, duration, description, and a link to view full details.
Task Detail View
The Subagents tab on the parent task's detail page shows expandable cards for each subtask. Each card includes:
- Subtask title and description
- Agent type (general, research, tool-specialist)
- Status and duration
- Full rendered output (markdown with syntax highlighting)
Breadcrumb navigation lets you move between parent and subtask views. Subtask expansion states are persisted in URL parameters for deep linking.
Configuration
Iteration Limits
Subagents have their own iteration limits, separate from the parent agent:
| Limit | Value | Behavior |
|---|---|---|
| Soft limit | 12 iterations | Warning injected into prompt to begin wrapping up |
| Hard limit | 15 iterations | Forced completion with whatever results are available |
The dispatch call can specify a max_iterations value between 1 and 15 for each subtask. This is clamped to the hard limit.
Token Budget
Each subagent can be given an optional token budget. When specified:
- At 80% of the budget, a warning is injected into the subagent's prompt.
- At 100%, the subagent is forced to stop and deliver its current results.
- If no budget is set, the subagent runs without token limits (still subject to iteration limits).
Step Timeout
Each step in a subagent's execution has a 10-minute timeout (compared to 5 minutes for the parent agent). This accommodates research-heavy MCP tool calls that may take longer to return.
Technical Details
This section covers internals that are useful for operators and advanced users.
Auto-Park Mechanism
When dispatch_subagent is called, the tool registers the new subtask IDs in a module-level pending list. After all tools in the current turn execute, the graph checks this list:
- If subtasks are already complete (fast path): results are collected immediately and returned inline. The parent continues without interruption.
- If subtasks are still running (common case): the parent task's status is set to
waiting_subagents, the execution state is checkpointed to Redis via LangGraph'sAsyncRedisSaver, and aGraphInterruptis raised to pause the graph.
Completion Hooks
After every subagent finishes (success or failure), the _check_and_resume_parent function runs:
- Look up the parent task from the subtask record.
- Query all sibling subtasks to check if every one is in a terminal state.
- If all are done, acquire a Redis distributed lock to prevent race conditions.
- Collect all results and enqueue a resume job for the parent.
The Redis lock (SETNX with 60-second TTL) is critical for preventing double-resume when two subagents finish at nearly the same time.
Checkpoint Restoration
The parent agent resumes from its exact execution state. LangGraph loads the full AgentState from Redis using the task's checkpoint_thread_id, receives the collected subtask results as ToolMessage responses matched to the original dispatch_subagent tool call IDs, and continues its ReAct loop.
MCP Isolation
Each subagent creates its own MCPManager with fresh connections to MCP servers. Subagent MCP sessions are not shared with the parent or with other subagents, ensuring complete isolation.
Parallel Tool Call Limits
Like the parent agent, subagents are limited to 5 simultaneous tool calls per turn. Excess calls receive synthetic "skipped" responses, and the agent can retry them in the next iteration.