> ## Documentation Index
> Fetch the complete documentation index at: https://docs.qoder.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Subagents

Subagents are specialized roles that the main session can delegate to temporarily. The Qoder Agent SDK Python edition supports two kinds of subagents:

* **Built-in subagents**: Provided by qodercli, such as general-purpose search, code exploration, and planning.
* **Custom subagents**: Defined by SDK users through `QoderAgentOptions.agents`, suitable for business review, test execution, security analysis, and other specialized roles.

This guide focuses on using built-in subagents from the Python SDK and defining custom subagents on demand. For complete type definitions, see [Agents Reference](/en/cli/sdk/python/references#agents-reference).

Unless otherwise noted, "Agent" in this guide means a subagent that the main session can delegate to. `QoderAgentOptions.agent` is a special usage that runs an Agent definition as the main session role.

<div id="built-in-subagents" />

<div id="builtinsubagents" />

## Built-in Subagents

When using a built-in subagent, you do not need to write the subagent definition yourself. You only need to know its name and reference it from the SDK.

Common built-in subagents currently provided by qodercli:

| Name              | Purpose                                                                                                                                |
| ----------------- | -------------------------------------------------------------------------------------------------------------------------------------- |
| `general-purpose` | General-purpose subagent, suitable for searching code, researching complex problems, and executing multi-step tasks                    |
| `Explore`         | Read-only code exploration subagent, suitable for quickly finding files, searching keywords, and understanding code structure          |
| `Plan`            | Read-only planning subagent, suitable for designing implementation plans, identifying key files, and analyzing architectural tradeoffs |

The built-in subagent list can change with the qodercli version and current configuration. In the interactive CLI, enter `/agents` to view the currently discovered subagents. From the command line, you can also run:

```bash theme={null}
qodercli agents list
```

After an SDK session is initialized, use `QoderSDKClient.supported_agents()` to read the subagents actually available to the current session:

```python theme={null}
from qoder_agent_sdk import QoderSDKClient, QoderAgentOptions


client = QoderSDKClient(options=QoderAgentOptions())
await client.connect("List available agents.")
agents = client.supported_agents()
await client.disconnect()
```

`supported_agents()` returns the subagents registered through `agents` plus the built-in, user, project, and plugin subagents discovered by the current CLI. See [AgentInfo](/en/cli/sdk/python/references#agentinfo) for the return structure.

<div id="using-built-in-subagents" />

<div id="usingbuiltinsubagents" />

## Using Built-in Subagents

<div id="run-as-the-main-session-role" />

<div id="runasthemainsessionrole" />

### Run as the Main Session Role

If you want the entire session to run under a built-in subagent role, pass the built-in subagent name directly to `QoderAgentOptions.agent`. You do not need to redefine it in `agents`.

```python theme={null}
from qoder_agent_sdk import QoderAgentOptions, query


options = QoderAgentOptions(agent="general-purpose")

async for message in query(
    prompt="Summarize this project architecture and identify the most important modules.",
    options=options,
):
    print(message)
```

`agent` can reference a subagent registered by the SDK, or a built-in / user / project / plugin subagent discovered by the current CLI.

<div id="delegate-as-a-subagent" />

<div id="delegateasasubagent" />

### Delegate as a Subagent

Subagent delegation happens through the built-in `Agent` tool. The main session's available tool set must include `Agent`; otherwise the model has no entry point for delegation. In SDK usage, a common pattern is to pre-authorize that tool call path and name the desired subagent in the prompt.

```python theme={null}
options = QoderAgentOptions(
    allowed_tools=["Agent"],
)

async for message in query(
    prompt="Use the Explore agent to find where authentication is implemented.",
    options=options,
):
    print(message)
```

`allowed_tools=["Agent"]` allows or pre-authorizes this class of tool calls. If you also use `tools` to restrict the main session tool allowlist, include `Agent` in `tools` as well. Do not put `Agent` in `disallowed_tools`.

The subagent name must match the discovered result exactly, including case. For example, current built-in names include `Explore`, `Plan`, and `general-purpose`. If unsure, call `client.supported_agents()` first.

<div id="custom-subagents" />

<div id="customsubagents" />

## Custom Subagents

When built-in subagents do not fit your business or project constraints, define custom subagents through `QoderAgentOptions.agents`. For example:

* Read-only code review subagent: can only read files and search; cannot modify code.
* Test execution subagent: can run test commands and analyze failure reasons.
* Security review subagent: focuses only on authentication, authorization, injection, sensitive information leakage, and related risks.
* Business support subagent: can only call specific MCP tools, such as order lookup, ticket search, or internal knowledge base search.

Custom subagents usually involve three steps:

1. Define the subagent name, usage description, and system prompt in `agents`.
2. Narrow the tools it can use with `tools` or `disallowedTools`.
3. Let the main session delegate to it through the `Agent` tool, or use `agent` to let it drive the main session directly.

> **The `Agent` tool is required**: Custom subagents need the main session to delegate through the built-in `Agent` tool, so `allowed_tools` must include the `Agent` tool.

<div id="defining-custom-subagents-with-agents" />

<div id="definingcustomsubagentswithagents" />

## Defining Custom Subagents with agents

Minimal example: register a read-only code review subagent.

```python theme={null}
import asyncio

from qoder_agent_sdk import AgentDefinition, QoderAgentOptions, query


async def main():
    options = QoderAgentOptions(
        allowed_tools=["Agent"],
        agents={
            "code-reviewer": AgentDefinition(
                description=(
                    "Reviews code for correctness, security issues, and "
                    "maintainability problems."
                ),
                prompt="""You are a code review specialist.
Review the requested code and report concrete findings.
Sort findings by severity and include file paths when possible.""",
                tools=["Read", "Grep", "Glob"],
            ),
        },
    )

    async for message in query(
        prompt="Use the code-reviewer agent to review the authentication module.",
        options=options,
    ):
        print(message)


asyncio.run(main())
```

There are three key points in this example:

* `QoderAgentOptions.agents` registers the custom subagents available to this session.
* Subagent delegation happens through the `Agent` tool; you must use `allowed_tools=["Agent"]` here to pre-authorize that call path.
* The subagent's own `tools` only allow reading and searching, so it cannot edit files or execute commands.

<div id="agents-input" />

<div id="agentsinput" />

### `agents` Input

`agents` maps subagent names to `AgentDefinition` objects. See [AgentDefinition](/en/cli/sdk/python/references#agentdefinition) for the complete type.

| Field             | Type                                   | Required | How to set it                                            | Description                                                                        |
| ----------------- | -------------------------------------- | -------- | -------------------------------------------------------- | ---------------------------------------------------------------------------------- |
| `description`     | `str`                                  | Yes      | One sentence describing when to use this subagent        | Routing description for the model; affects whether it is invoked                   |
| `prompt`          | `str`                                  | Yes      | The subagent's role, boundaries, and output requirements | System prompt for this subagent                                                    |
| `tools`           | `list[str]`                            | No       | For example `["Read", "Grep", "Glob"]`                   | Tool allowlist; when set, only listed tools can be used                            |
| `disallowedTools` | `list[str]`                            | No       | For example `["Bash", "Write"]`                          | Tool blocklist, useful when excluding only a few tools                             |
| `model`           | `str`                                  | No       | For example `"inherit"`, `"auto"`, or a full model ID    | Model configuration for the subagent                                               |
| `maxTurns`        | `int`                                  | No       | For example `8`                                          | Limits how many turns the subagent may execute                                     |
| `effort`          | `"low" \| "medium" \| "high" \| "max"` | No       | For example `"high"`                                     | Controls reasoning effort                                                          |
| `permissionMode`  | `PermissionMode`                       | No       | For example `"default"`, `"acceptEdits"`, `"plan"`       | Controls the permission mode for tool calls inside the subagent                    |
| `skills`          | `list[str]`                            | No       | For example `["review"]`                                 | Skills preloaded into the subagent context                                         |
| `mcpServers`      | `list[str \| dict[str, Any]]`          | No       | For example `["orders"]` or `[{"kb": {...}}]`            | Limits or adds MCP servers for the subagent                                        |
| `initialPrompt`   | `str`                                  | No       | First-turn automatic input                               | Only takes effect when this subagent becomes the main session role through `agent` |

The Python SDK's `AgentDefinition` field names use protocol-style camelCase, such as `disallowedTools`, `maxTurns`, `initialPrompt`, and `permissionMode`, not `disallowed_tools` or `max_turns`.

<div id="configuring-the-subagent-role" />

<div id="configuringthesubagentrole" />

## Configuring the Subagent Role

`description` and `prompt` are the two most important fields for a custom subagent.

<div id="description" />

### `description`

`description` explains when this subagent should be used. The model uses it to decide whether to delegate.

```python theme={null}
description="Runs project tests, analyzes failing output, and suggests fixes."
```

A good `description` should state the task boundary clearly. Avoid generic descriptions such as `A helpful agent` or `Helper`.

<div id="prompt" />

### `prompt`

`prompt` defines the subagent's role, boundaries, and output format. The Python `AgentDefinition` constructor requires this field.

```python theme={null}
prompt="""You are a code review specialist.
Only review the requested code; do not edit files.
Return findings sorted by severity, with file paths and suggested fixes."""
```

At minimum, `prompt` should explain three things:

| What to explain       | Example                                                |
| --------------------- | ------------------------------------------------------ |
| What task it owns     | `Review code for security and maintainability issues.` |
| What it should not do | `Do not edit files. Do not run commands.`              |
| How to return results | `Return findings sorted by severity with file paths.`  |

<div id="configuring-subagent-model-and-reasoning" />

<div id="configuringsubagentmodelandreasoning" />

## Configuring Subagent Model and Reasoning

First make `description` and `prompt` clear, then consider `model`, `effort`, and `maxTurns`. The former decide whether the subagent is invoked correctly and whether it understands its boundaries once invoked. The latter mainly tune quality, speed, and cost after the role is clear.

| Option     | Controls                                                | When to adjust first                                                                          |
| ---------- | ------------------------------------------------------- | --------------------------------------------------------------------------------------------- |
| `model`    | Selects which model or model alias the subagent uses    | This subagent repeatedly handles a fixed type of task and you need stable capability and cost |
| `effort`   | How much reasoning budget to spend under the same model | The same subagent occasionally receives a more complex task that needs more careful reasoning |
| `maxTurns` | The maximum number of turns                             | The task may explore too deeply or run too long, or you want a hard cost limit                |

At the Python type level, `model` is `str | None`. Common values include `"inherit"`, `"auto"`, model aliases, or any full model ID supported by the current CLI / backend. Actual usable values depend on qodercli and backend configuration.

Example: give different subagents different strategies.

```python theme={null}
agents = {
    "explorer": AgentDefinition(
        description="Quickly searches code and summarizes relevant files.",
        prompt="Find relevant files and return a concise summary. Do not edit.",
        tools=["Read", "Grep", "Glob"],
        model="inherit",
        effort="low",
        maxTurns=5,
    ),
    "architect": AgentDefinition(
        description="Designs complex implementation plans across modules.",
        prompt="Analyze tradeoffs carefully and return an implementation plan with risks.",
        tools=["Read", "Grep", "Glob"],
        model="auto",
        effort="high",
        maxTurns=10,
    ),
}
```

For complete field reference, see [Agents Reference - model](/en/cli/sdk/python/references#agentdefinition-model), [Agents Reference - maxTurns](/en/cli/sdk/python/references#agentdefinition-maxturns), and [Agents Reference - effort](/en/cli/sdk/python/references#agentdefinition-effort).

<div id="controlling-subagent-tools" />

<div id="controllingsubagenttools" />

## Controlling Subagent Tools

Custom subagents and the main session use the same tool names. Built-in tool names include `Read`, `Grep`, `Glob`, and `Bash`; custom MCP tools use the full format `mcp__{serverName}__{toolName}`.

<div id="the-main-sessions-agent-tool" />

<div id="themainsessionsagenttool" />

### The Main Session's `Agent` Tool

`agents` only registers subagents; it does not automatically make the model call them. To delegate a task, the main session's tool set must contain `Agent`. If you set `QoderAgentOptions.tools` to limit the main session's available tools, remember to include `Agent`. If you set `disallowed_tools=["Agent"]`, delegation is disabled.

<div id="tool-allowlist-tools" />

<div id="toolallowlisttools" />

### Tool Allowlist: `tools`

`tools` is the subagent's tool allowlist. Once set, the subagent can only use listed tools.

```python theme={null}
tools=["Read", "Grep", "Glob"]
```

Common tool combinations:

| Scenario            | Recommended tools                       | Description                                               |
| ------------------- | --------------------------------------- | --------------------------------------------------------- |
| Read-only analysis  | `Read`, `Grep`, `Glob`                  | Can inspect code; cannot modify files or run commands     |
| Run tests           | `Bash`, `Read`, `Grep`                  | Can execute test commands and analyze output              |
| Write code          | `Read`, `Edit`, `Write`, `Grep`, `Glob` | Can read and write files but cannot run commands directly |
| Call business tools | `mcp__server__tool`                     | Only allows specific custom tools                         |

<div id="tool-blocklist-disallowedtools" />

<div id="toolblocklistdisallowedtools" />

### Tool Blocklist: `disallowedTools`

`disallowedTools` is useful when you want to allow most tools while excluding a few.

```python theme={null}
disallowedTools=["Bash", "Write"]
```

Usually avoid setting both `tools` and `disallowedTools` unless you are certain of the final tool set.

<div id="relationship-to-main-session-tool-configuration" />

<div id="relationshiptomainsessiontoolconfiguration" />

### Relationship to Main Session Tool Configuration

A subagent's `tools` / `disallowedTools` only apply to that subagent. They do not inherit the main session's tool allowlist or blocklist trimming. Even if the main session only pre-authorizes the `Agent` delegation path, the subagent can still use its own configured `Read`, `Grep`, and related tools.

```python theme={null}
options = QoderAgentOptions(
    allowed_tools=["Agent"],
    agents={
        "analyst": AgentDefinition(
            description="Reads and summarizes code structure.",
            prompt="Inspect relevant files and return a concise summary. Do not edit files.",
            tools=["Read", "Grep", "Glob"],
        ),
    },
)
```

<div id="controlling-subagent-permissions" />

<div id="controllingsubagentpermissions" />

## Controlling Subagent Permissions

The tool set decides which tools a subagent can call. Permission settings decide how those tool calls are approved or blocked. You can configure `permissionMode` separately on a subagent to control permission behavior for its internal tool execution.

```python theme={null}
AgentDefinition(
    description="Plans implementation work without making changes.",
    prompt="Read relevant files and return an implementation plan. Do not edit files.",
    tools=["Read", "Grep", "Glob"],
    permissionMode="plan",
)
```

For complete values and semantics of `permissionMode`, see [Agents Reference - permissionMode](/en/cli/sdk/python/references#agentdefinition-permissionmode). If the host needs to approve tool calls one by one, use the session-level `can_use_tool` callback; the `context.agent_id` received by the callback can be used to identify whether the call comes from a subagent.

<div id="loading-skills-for-subagents" />

<div id="loadingskillsforsubagents" />

## Loading Skills for Subagents

`skills` preloads specialized skills for a subagent. It is useful when you want to bind a specific workflow, team convention, or tool usage pattern to one subagent instead of putting it in every prompt.

```python theme={null}
AgentDefinition(
    description="Reviews pull requests using the team review workflow.",
    prompt="Review the requested changes and return actionable findings.",
    tools=["Read", "Grep", "Glob"],
    skills=["review"],
)
```

A subagent's `skills` only affect that subagent's context. They are not the same as the main session's `QoderAgentOptions.skills`. For session-level skill behavior, see [Skills](/en/cli/sdk/python/skills).

<div id="configuring-subagent-mcpservers" />

<div id="configuringsubagentmcpservers" />

## Configuring Subagent mcpServers

`mcpServers` limits or adds MCP servers for a subagent. It is suitable for exposing business tools only to the subagents that need them, such as order lookup, ticket search, or internal knowledge base search.

You can reference an MCP server already configured at the session level:

```python theme={null}
options = QoderAgentOptions(
    mcp_servers={
        "orders": {
            "command": "python",
            "args": ["servers/orders.py"],
        },
    },
    allowed_tools=["Agent"],
    agents={
        "support": AgentDefinition(
            description="Answers customer support questions using order tools.",
            prompt="Use order tools when needed and return a concise answer.",
            mcpServers=["orders"],
            tools=["mcp__orders__lookup_order"],
        ),
    },
)
```

You can also configure a dedicated MCP server for a specific subagent:

```python theme={null}
options = QoderAgentOptions(
    allowed_tools=["Agent"],
    agents={
        "knowledge": AgentDefinition(
            description="Searches the internal knowledge base.",
            prompt="Search the knowledge base and cite the relevant entries.",
            mcpServers=[
                {
                    "kb": {
                        "command": "python",
                        "args": ["servers/kb.py"],
                    },
                },
            ],
            tools=["mcp__kb__search"],
        ),
    },
)
```

Recommendations:

| Scenario                                  | How to configure                                                                                                              |
| ----------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------- |
| Multiple subagents share one MCP server   | Configure the server in session-level `QoderAgentOptions.mcp_servers`, then reference its name in the subagent's `mcpServers` |
| Only one subagent needs a business tool   | Put the server in that subagent's `mcpServers` and use `tools` to limit callable tools                                        |
| You only want to call a specific MCP tool | Also set `tools=["mcp__server__tool"]` to avoid exposing every tool from the server                                           |

For complete field status, see [Agents Reference - mcpServers](/en/cli/sdk/python/references#agentdefinition-mcpservers).

<div id="invoking-subagents" />

<div id="invokingsubagents" />

## Invoking Subagents

Subagents have three common invocation modes.

<div id="automatic-invocation" />

<div id="automaticinvocation" />

### Automatic Invocation

The model decides whether to call a subagent based on the task and each subagent's `description`. Clear descriptions improve routing accuracy.

<div id="explicit-invocation" />

<div id="explicitinvocation" />

### Explicit Invocation

If you want the model to use a specific subagent, name it in the prompt.

```python theme={null}
async for message in query(
    prompt="Use the tester agent to run the unit tests and summarize failures.",
    options=QoderAgentOptions(
        allowed_tools=["Agent"],
        agents={
            "tester": AgentDefinition(
                description="Runs tests and analyzes failures.",
                prompt="Run the requested tests and explain failures clearly.",
                tools=["Bash", "Read", "Grep"],
            ),
        },
    ),
):
    print(message)
```

### Run as the Main Session Role

`QoderAgentOptions.agent` makes the main session run directly as a subagent identity.

```python theme={null}
options = QoderAgentOptions(
    agents={
        "planner": AgentDefinition(
            description="Plans implementation work before code changes.",
            prompt="Break the task into clear steps, risks, and validation checks.",
            tools=["Read", "Grep", "Glob"],
            model="inherit",
        ),
    },
    agent="planner",
)
```

`agent` can reference a custom subagent in `agents`, or a built-in / user / project / plugin subagent discovered by the current CLI.

<div id="subagent-context-and-results" />

<div id="subagentcontextandresults" />

## Subagent Context and Results

A subagent runs in an independent context. It receives its own system prompt and delegation prompt, but it does not directly inherit the parent session's full history.

| Subagent can see                                                    | Subagent cannot see                                        |
| ------------------------------------------------------------------- | ---------------------------------------------------------- |
| Its own `prompt`                                                    | Full parent-session conversation history                   |
| The task prompt passed by the main session through the `Agent` tool | Intermediate tool results from the parent session          |
| Its own available tool definitions                                  | Parent session private reasoning that was not passed to it |
| Skills preloaded by configuration                                   | Intermediate context from other Agents                     |

The main channel for passing information from the parent session to a subagent is the task prompt passed when calling the Agent tool. If a subagent needs specific file paths, error messages, or business context, make the main session pass them explicitly during delegation.

When a subagent completes, the parent session receives its final response, not the full context of every internal tool call.

<div id="combined-examples" />

<div id="combinedexamples" />

## Combined Examples

<div id="multi-role-collaboration" />

<div id="multirolecollaboration" />

### Multi-role Collaboration

Register multiple subagents with different roles. The main session decides whether and when to call them based on the task.

```python theme={null}
options = QoderAgentOptions(
    allowed_tools=["Agent"],
    agents={
        "researcher": AgentDefinition(
            description="Reads existing code to understand patterns and constraints.",
            prompt="Research relevant files and report implementation constraints. Do not edit.",
            tools=["Read", "Grep", "Glob"],
            maxTurns=8,
        ),
        "implementer": AgentDefinition(
            description="Implements code changes following existing project conventions.",
            prompt="Implement the requested change with minimal, idiomatic edits.",
            tools=["Read", "Edit", "Write", "Grep", "Glob"],
            maxTurns=12,
        ),
        "tester": AgentDefinition(
            description="Runs tests and explains failures.",
            prompt="Run relevant tests, summarize results, and identify failing cases.",
            tools=["Bash", "Read", "Grep"],
            maxTurns=6,
        ),
    },
)
```

<div id="automatically-run-the-first-task-after-startup" />

<div id="automaticallyrunthefirsttaskafterstartup" />

### Automatically Run the First Task After Startup

`initialPrompt` only takes effect when that subagent becomes the main session role through `agent`:

```python theme={null}
options = QoderAgentOptions(
    agents={
        "auditor": AgentDefinition(
            description="Audits code for security risks.",
            prompt="Scan code for security risks and produce a concise report.",
            initialPrompt="Start with the authentication and session management code.",
            tools=["Read", "Grep", "Glob"],
            effort="high",
        ),
    },
    agent="auditor",
)

async for message in query(prompt="", options=options):
    print(message)
```

If `auditor` is called as a subagent through the main session's `Agent` tool, `initialPrompt` is ignored.

<div id="common-pitfalls" />

<div id="commonpitfalls" />

## Common Pitfalls

* When directly using a built-in subagent, do not redefine a subagent with the same name in `agents` unless you intentionally want to override it.
* Calling subagents depends on the main session's `Agent` tool. `allowed_tools=["Agent"]` pre-authorizes it; if you use `tools` to restrict main-session tools, include `Agent` there too.
* Subagent names are case-sensitive and must match the discovered result, such as `Explore` and `Plan` with capitalized first letters.
* `description` tells the model when to call the subagent; `prompt` tells the subagent what to do after it is called.
* Subagents cannot spawn their own subagents. Do not put `Agent` in a subagent's `tools`.
* `initialPrompt` only takes effect for the main session role specified by `agent`; it is ignored when the agent is delegated to as a subagent.
* `AgentDefinition` field names are camelCase, not snake\_case.
* Fields like `background`, `memory`, and `criticalSystemReminder_EXPERIMENTAL` exist as types, but the SDK registration pipeline does not currently use them to change runtime behavior. Check [Agents Reference](/en/cli/sdk/python/references#agentdefinition) before relying on them.

<div id="continue-reading" />

<div id="continuereading" />

## Continue Reading

* [Agents Reference](/en/cli/sdk/python/references#agents-reference): Complete reference for `AgentDefinition`, `AgentInfo`, `agent`, and `agents`.
* [Tools](/en/cli/sdk/python/tools): Built-in tools, custom tools, and tool permissions.
* [Permissions](/en/cli/sdk/python/permissions): `permissionMode`, `allowed_tools`, and `can_use_tool`.
* [Skills](/en/cli/sdk/python/skills): Session-level and subagent-level skill configuration.
