mantis
guides

Sub-agents

A sub-agent is an agent exposed to the parent as a regular tool. The parent calls it like any other tool; the sub-agent runs to completion (with its own model, system prompt, and tools) and returns its final answer as the tool result.

Use sub-agents when the work decomposes into specialised slices — "research", "draft", "review" — that benefit from their own context.

Defining a sub-agent

Two flavours.

SubAgentSpec — declarative

from mantis_agent import SubAgentSpec, as_subagent_tool
 
researcher = SubAgentSpec(
    name="researcher",
    description="Research a topic and produce a fact-checked summary.",
    model="qwen2.5:7b",
    system_prompt="You are a careful researcher. Cite sources.",
    tools=[web_search, web_fetch],
    max_turns=15,
)
 
researcher_tool = as_subagent_tool(researcher)

Existing Agent — imperative

If you already have an Agent instance you want to expose:

from mantis_agent import Agent, as_subagent_tool
 
researcher = Agent(
    model="qwen2.5:7b",
    system_prompt="...",
    tools=[...],
)
researcher_tool = as_subagent_tool(
    researcher,
    name="researcher",
    description="Research a topic and produce a fact-checked summary.",
)

Under the hood this wraps the agent in a WrappedAgentTool. Same JSON schema as SubAgentTool.

Calling from a parent

Add the wrapped sub-agent to the parent's tools list:

options = {
    "model": "qwen2.5:7b",
    "tools": [researcher_tool, drafter_tool, reviewer_tool],
}

The model invokes them like any other tool. The sub-agent runs in isolation and returns its final assistant text.

Isolation

Sub-agents have their own:

  • Transcript (separate JSONL file under ~/.mantis-agent/sessions/)
  • System prompt
  • Tool registry
  • Permission policy
  • Budget cap

Set isolation=IsolationMode.SHARED to share session and transcript with the parent (the sub-agent's turns interleave into the parent's transcript). Use this when the sub-agent should append to the parent's context, not branch off.

from mantis_agent import IsolationMode
 
researcher_tool = as_subagent_tool(
    researcher,
    isolation=IsolationMode.SHARED,
)

Multiple sub-agents in parallel

If the parent emits two sub-agent calls in the same turn, they run concurrently (assuming parallel_safe=True, the default). Each gets its own task group; results thread back in emission order.

options = {
    "tools": [
        as_subagent_tool(spec_a),
        as_subagent_tool(spec_b),
        as_subagent_tool(spec_c),
    ],
}

The parent model can fan out: "use researcher + drafter + reviewer in parallel". The runtime handles the rest.

Passing prompts and data

Sub-agents accept a single prompt argument by default — whatever the parent passes. To accept structured input, define a custom schema on the spec:

researcher = SubAgentSpec(
    name="researcher",
    description="...",
    input_schema={
        "type": "object",
        "properties": {
            "topic": {"type": "string"},
            "depth": {"type": "string", "enum": ["shallow", "deep"]},
        },
        "required": ["topic"],
    },
)

The wrapped tool exposes that schema to the parent; the sub-agent gets the parsed input as a dict.

Budgets and limits

Apply caps separately to each sub-agent:

researcher = SubAgentSpec(..., max_usd=0.10, max_turns=8)
drafter = SubAgentSpec(..., max_usd=0.05, max_turns=5)

The parent's max_usd rolls up everything (its own model calls plus all sub-agent spend).

Patterns

Three common shapes:

  1. Specialist pool. Parent decides which expert to consult based on the user's question. Each sub-agent has a narrow domain.
  2. Pipeline. Parent calls researcher → drafter → reviewer in order, threading outputs through.
  3. Fan-out. Parent emits N sub-agent calls in parallel to compare outputs, then picks the best.

See mantis_agent/examples/multi_agent_research.py for a worked example of all three.