Otto Docs
Features

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

  1. 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).

  2. Subtasks are created and queued. Each dispatch creates a new task record in the database with task_type: subtask linked to the parent task. The subtask is enqueued to a background worker queue.

  3. 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.

  4. 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.

  5. Results are collected. When all subagents reach a terminal state (completed or failed), their results are gathered into a combined response.

  6. 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:

  1. Check if all sibling subtasks for the parent are in a terminal state.
  2. Acquire a distributed lock (Redis SETNX, 60-second TTL) to prevent double-resume when two subagents finish at nearly the same time.
  3. Collect results from all subtasks -- completed tasks contribute their output, failed tasks contribute a failure notice.
  4. 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_human and dispatch_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, or dispatch_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, and send_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:

ColorStatus
BlueRunning
GreenCompleted
RedFailed
OrangeWaiting

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:

LimitValueBehavior
Soft limit12 iterationsWarning injected into prompt to begin wrapping up
Hard limit15 iterationsForced 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's AsyncRedisSaver, and a GraphInterrupt is raised to pause the graph.

Completion Hooks

After every subagent finishes (success or failure), the _check_and_resume_parent function runs:

  1. Look up the parent task from the subtask record.
  2. Query all sibling subtasks to check if every one is in a terminal state.
  3. If all are done, acquire a Redis distributed lock to prevent race conditions.
  4. 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.