# Subagent System

Hierarchical agent architectures where a main agent delegates specialized tasks to child agents.

## Overview

- **Markdown-based Configuration**: Define subagents using markdown files with YAML frontmatter
- **Tool Inheritance**: Subagents inherit tools from parent toolset with optional filtering
- **Auto-Inherit Tools**: Management tools (task\_\*, summarize) are automatically inherited by all subagents
- **Model Flexibility**: Subagents can use different models or inherit from parent
- **Dynamic Availability**: Subagent tools are automatically disabled when required tools are unavailable
- **Unified Delegation** (Recommended): Single `delegate` tool to call any subagent by name

```mermaid
flowchart TB
    subgraph MainAgent["Main Agent"]
        MainToolset["Toolset"]
        DelegateTool["delegate Tool"]
    end

    subgraph Subagents["Subagents"]
        Debugger["debugger"]
        Explorer["explorer"]
        Searcher["searcher"]
    end

    MainToolset -->|subset| Subagents
    DelegateTool -->|delegates by name| Subagents
    Subagents -->|returns result| MainAgent
```

## Quick Start (Recommended: create_agent with unified_subagents)

The simplest way to use subagents is via `create_agent` with `unified_subagents=True`:

```python
from ya_agent_sdk.agents import create_agent
from ya_agent_sdk.subagents import SubagentConfig

# Define custom subagents
configs = [
    SubagentConfig(
        name="researcher",
        description="Research specialist",
        system_prompt="You are a research specialist...",
        tools=["search", "scrape"],
    ),
    SubagentConfig(
        name="analyst",
        description="Data analyst",
        system_prompt="You are a data analyst...",
        tools=["view", "grep"],
    ),
]

# Create agent with unified subagents (single 'delegate' tool)
runtime = create_agent(
    "anthropic:claude-sonnet-4",
    tools=[...],
    subagent_configs=configs,
    unified_subagents=True,  # Creates single 'delegate' tool
)

# Or with builtin subagents
runtime = create_agent(
    "anthropic:claude-sonnet-4",
    tools=[...],
    include_builtin_subagents=True,
    unified_subagents=True,
)
```

### Unified Tool Signature

```python
async def delegate(
    subagent_name: str,  # Name of subagent to call (e.g., "self", "debugger", "explorer")
    prompt: str,         # Task to delegate
    agent_id: str | None = None,  # Optional ID to resume conversation
) -> str:
    ...
```

### Self Fork

Unified delegate includes the built-in `subagent_name="self"` target. A self fork uses the current agent's system prompt, message history, model, capabilities, and ordinary tools, while delegation tools are hidden from the fork.

Use self forks for full-context subtasks:

- plan-then-execute workflows where independent plan steps can run in parallel
- mid-task repository exploration while the parent continues implementation
- assumption checks, approach comparisons, and implementation spikes

Ask each self fork to return concise findings, changed files, tests run, and risks.

```python
# After creating a plan, issue independent calls in the same model response.
delegate(subagent_name="self", prompt="Implement plan step 1. Return changed files and test results.")
delegate(subagent_name="self", prompt="Explore the data-loading path and report relevant files, assumptions, and risks.")
```

### Key Benefits

| Aspect      | Unified (Recommended)             | Individual Tools        |
| ----------- | --------------------------------- | ----------------------- |
| Tool Count  | 1 tool                            | N tools                 |
| Instruction | Single combined instruction       | N separate instructions |
| Selection   | `subagent_name` parameter         | Tool name selection     |
| Flexibility | Dynamic availability per subagent | Per-tool availability   |

## Alternative: Manual Unified Tool Creation

For more control, you can create the unified tool manually:

```python
from ya_agent_sdk.agents import create_agent
from ya_agent_sdk.subagents import (
    SubagentConfig,
    create_unified_subagent_tool,
    load_builtin_unified_subagent_tool,
)
from ya_agent_sdk.toolsets.core.base import Toolset

# Option 1: Load builtin subagents as unified tool
parent_toolset = Toolset(tools=[GrepTool, ViewTool, SearchTool, ...])
DelegateTool = load_builtin_unified_subagent_tool(
    parent_toolset,
    model="anthropic:claude-sonnet-4",
)

# Option 2: Custom subagents as unified tool
DelegateTool = create_unified_subagent_tool(
    configs,
    parent_toolset,
    model="anthropic:claude-sonnet-4",
)

# Use with create_agent
runtime = create_agent(
    "anthropic:claude-sonnet-4",
    tools=[..., DelegateTool],
)
```

## Alternative: Individual Subagent Tools

For cases where you need each subagent as a separate tool:

```python
from ya_agent_sdk.agents import create_agent
from ya_agent_sdk.subagents import SubagentConfig

config = SubagentConfig(
    name="researcher",
    description="Research specialist for web searches",
    system_prompt="You are a research specialist...",
    tools=["search", "scrape"],
)

runtime = create_agent(
    "anthropic:claude-sonnet-4",
    tools=[SearchTool, ScrapeTool, ViewTool],
    subagent_configs=[config],
    include_builtin_subagents=True,
)
```

## Configuration Format

Subagents are defined using markdown files with YAML frontmatter:

```markdown
---
name: debugger
description: Debugging specialist for errors and test failures
instruction: |
  Use the debugger subagent when encountering error messages or stack traces.
tools:
  - grep
  - view
optional_tools:
  - shell
  - edit
model: inherit
model_settings: inherit
model_cfg: inherit
---

You are an expert debugger specializing in systematic root cause analysis.
```

### Configuration Fields

| Field            | Type          | Required | Description                                                      |
| ---------------- | ------------- | -------- | ---------------------------------------------------------------- |
| `name`           | `str`         | Yes      | Unique identifier, used as tool name or subagent_name parameter  |
| `description`    | `str`         | Yes      | Shown to model when selecting tools/subagents                    |
| `instruction`    | `str`         | No       | Injected into parent's system prompt                             |
| `system_prompt`  | `str`         | Yes      | Markdown body content (after frontmatter)                        |
| `tools`          | `list[str]`   | No       | Required tools from parent (ALL must be available)               |
| `optional_tools` | `list[str]`   | No       | Optional tools (included if available)                           |
| `model`          | `str`         | No       | `"inherit"` or model name (e.g., `"anthropic:claude-sonnet-4"`)  |
| `model_settings` | `str \| dict` | No       | `"inherit"`, preset name, or dict config                         |
| `model_cfg`      | `str \| dict` | No       | `"inherit"`, preset name (e.g., `"claude_200k"`), or dict config |

### Tool Availability Rules

- **Required tools** (`tools`): ALL must be available in parent toolset for subagent to be enabled
- **Optional tools** (`optional_tools`): Included if available, not required for availability
- **Auto-inherit tools**: Tools with `auto_inherit=True` are automatically included in all subagents (e.g., `task_*`, `summarize`)
- **No tools specified**: Subagent inherits all tools from parent and is always available

### Auto-Inherit Tools

Some management tools are automatically inherited by all subagents without explicit configuration:

| Tool          | Purpose                                  |
| ------------- | ---------------------------------------- |
| `task_create` | Create tasks for tracking work           |
| `task_update` | Update task status and dependencies      |
| `task_list`   | List all tasks                           |
| `task_get`    | Get task details                         |
| `summarize`   | Summarize context for session management |

To create a custom auto-inherit tool:

```python
class MyManagementTool(BaseTool):
    name = "my_tool"
    description = "A management tool"
    auto_inherit = True  # Automatically inherited by all subagents

    async def call(self, ctx: RunContext[AgentContext]) -> str:
        return "result"
```

## Builtin Presets

Located in `ya_agent_sdk/subagents/presets/`:

| Preset          | Purpose                                         | Required Tools               |
| --------------- | ----------------------------------------------- | ---------------------------- |
| `debugger`      | Systematic debugging and root cause analysis    | `glob`, `grep`, `view`, `ls` |
| `explorer`      | Codebase navigation and structure understanding | `glob`, `grep`, `view`, `ls` |
| `code-reviewer` | Code quality, security, and maintainability     | `glob`, `grep`, `view`, `ls` |
| `searcher`      | Web research for documentation and solutions    | `search`                     |

```python
from ya_agent_sdk.subagents import (
    get_builtin_subagent_configs,
    load_builtin_unified_subagent_tool,  # Recommended
    load_builtin_subagent_tools,         # Individual tools
)

# Inspect configurations
configs = get_builtin_subagent_configs()

# Load as unified tool (recommended)
DelegateTool = load_builtin_unified_subagent_tool(parent_toolset, model="anthropic:claude-sonnet-4")

# Or load as individual tools
subagent_tools = load_builtin_subagent_tools(parent_toolset, model="anthropic:claude-sonnet-4")
```

## API Reference

> Full docstrings and examples: `ya_agent_sdk/subagents/__init__.py`

### Core

| Function/Class            | Description                                      |
| ------------------------- | ------------------------------------------------ |
| `SubagentConfig`          | Pydantic model for subagent configuration        |
| `INHERIT`                 | Special value indicating inheritance from parent |
| `parse_subagent_markdown` | Parse markdown string to SubagentConfig          |
| `load_subagent_from_file` | Load SubagentConfig from a markdown file         |
| `load_subagents_from_dir` | Load all SubagentConfigs from a directory        |

### Unified Subagent Factory (Recommended)

| Function                              | Description                                       |
| ------------------------------------- | ------------------------------------------------- |
| `create_unified_subagent_tool`        | Create single delegate tool from multiple configs |
| `load_unified_subagent_tool_from_dir` | Load from directory as unified tool               |
| `load_builtin_unified_subagent_tool`  | Load builtin presets as unified tool              |
| `get_available_subagent_names`        | Get subagent names from unified tool class        |

### Individual Subagent Factory

| Function                             | Description                              |
| ------------------------------------ | ---------------------------------------- |
| `create_subagent_tool_from_config`   | Create tool from SubagentConfig          |
| `create_subagent_tool_from_markdown` | Create tool from markdown file or string |
| `load_subagent_tools_from_dir`       | Load all subagent tools from a directory |
| `get_builtin_subagent_configs`       | Get builtin preset configurations        |
| `load_builtin_subagent_tools`        | Load builtin presets as individual tools |

### Low-Level (Advanced)

| Function                    | Description                                 |
| --------------------------- | ------------------------------------------- |
| `create_subagent_tool`      | Create tool from custom call function       |
| `create_subagent_call_func` | Create call function from pydantic-ai Agent |

## Best Practices

1. **Use Unified Subagent**: Prefer `create_unified_subagent_tool` over individual tools for cleaner interface
2. **Focused Responsibility**: Each subagent should have a clear, specific purpose
3. **Minimal Required Tools**: Only require essential tools; use `optional_tools` for nice-to-haves
4. **Clear Instructions**: Write `instruction` to help parent agent decide when to delegate
5. **Handle Missing Tools**: Subagents auto-disable when required tools are unavailable
6. **Execution Model**: Delegate calls are blocking. Multiple delegates in the same model response run concurrently (parallel-but-blocking), but the agent waits until all complete. This is not async/fire-and-forget.

## Integration with Task Manager

Subagents work well with the task manager for concurrent execution of independent tasks.
Note that delegate calls are **blocking** -- multiple delegates in the same model response
run concurrently, but the agent cannot do other work while waiting for them.

```python
# In your workflow:
# 1. Create tasks with task_create
# 2. Call multiple delegates in a single response for concurrent execution
# 3. Agent is blocked until ALL delegates in that response complete
# 4. Update task status when subagents return
```

The task manager can assign tasks to subagents using the `owner` field:

```python
task_update(task_id="TASK-1", owner="debugger", status="in_progress")
# Then delegate to debugger subagent
delegate(subagent_name="debugger", prompt="Fix the error in TASK-1...")
```

## See Also

- [context.md](context.md) - AgentContext and subagent history management
- [toolset.md](toolset.md) - Toolset architecture and tool creation
- [model.md](model.md) - Model configuration and presets
