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

# Handoffs from agents.yaml

> Declare handoffs and HandoffConfig from YAML or CLI — no Python needed

Declare which agents can hand off to which — and their execution limits — directly in `agents.yaml`.

```mermaid theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
graph LR
    subgraph "YAML Handoffs"
        Y[📄 agents.yaml<br/>handoff: to: - billing] --> W[🔧 _wire_handoffs]
        W --> H[🤝 Agent.handoffs<br/>+ HandoffConfig]
        H --> T[✅ Handoff tools]
    end

    classDef input fill:#6366F1,stroke:#7C90A0,color:#fff
    classDef process fill:#189AB4,stroke:#7C90A0,color:#fff
    classDef output fill:#10B981,stroke:#7C90A0,color:#fff

    class Y input
    class W,H process
    class T output
```

## Quick Start

**1. Declare handoff: in agents.yaml**

Add a `handoff:` block under any agent. `to:` lists the target agent keys.

```yaml theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
# agents.yaml
agents:
  triage:
    role: Customer Service Triage
    goal: Route the customer to the right specialist
    handoff:
      to: [billing, tech, refund]
      timeout: 30
      max_depth: 3
      max_concurrent: 1
      detect_cycles: true
  billing:
    role: Billing Specialist
    goal: Resolve billing questions
  tech:
    role: Technical Support
    goal: Fix technical issues
  refund:
    role: Refund Specialist
    goal: Process refunds
```

**2. Run it**

The adapter wires the `handoff:` dict into core `Agent.handoffs` — no Python required.

```bash theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
praisonai run agents.yaml
```

***

## Three Surfaces, Same Wiring

YAML, CLI, and Python all populate the same `Agent.handoffs` with the same `HandoffConfig`.

> [tab] YAML
>
> ```yaml theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
> # agents.yaml
> agents:
>   triage:
>     role: Customer Service Triage
>     goal: Route the customer to the right specialist
>     handoff:
>       to: [billing, tech, refund]
>       timeout: 30
>       max_depth: 3
>       max_concurrent: 1
>       detect_cycles: true
> ```

> [tab] CLI
>
> ```bash theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
> praisonai --handoff to=billing,tech,refund \
>           --handoff-timeout 30 \
>           --handoff-max-depth 3 \
>           --handoff-max-concurrent 1 \
>           --handoff-detect-cycles
> ```

> [tab] Python
>
> ```python theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
> from praisonaiagents import Agent
> from praisonaiagents.agent.handoff import HandoffConfig
>
> billing = Agent(name="billing", role="Billing Specialist", goal="Resolve billing questions")
> tech = Agent(name="tech", role="Technical Support", goal="Fix technical issues")
> refund = Agent(name="refund", role="Refund Specialist", goal="Process refunds")
>
> triage = Agent(
>     name="triage",
>     role="Customer Service Triage",
>     goal="Route the customer to the right specialist",
>     handoffs=[billing, tech, refund],
>     handoff_config=HandoffConfig(
>         timeout_seconds=30,
>         max_depth=3,
>         max_concurrent=1,
>         detect_cycles=True,
>     ),
> )
> ```
>
> The Python API is documented in full on the [Agent Handoffs](https://praison.ai/docs/features/handoffs.md) page.

***

## How It Works

The adapter runs a wiring pass after every agent is built, then resolves each `to:` role by name.

```mermaid theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
sequenceDiagram
    participant YAML as agents.yaml
    participant Adapter as PraisonAI adapter
    participant Wire as _wire_handoffs
    participant Core as Agent.handoffs

    YAML->>Adapter: parse specs
    Adapter->>Adapter: _build_agents_and_tasks
    Adapter->>Wire: run after all agents built
    Wire->>Wire: map keys → HandoffConfig
    Wire->>Wire: resolve to: roles by name
    Wire->>Core: populate handoffs (+ config)
    Core->>Core: _process_handoffs() → tools
```

Unknown target roles are logged and skipped — they never raise.

***

## Configuration Options

Every key under `handoff:` maps onto a field of core `HandoffConfig`.

| YAML key | Type | Default | HandoffConfig field | Description |
| - | - | - | - | - |
| `to` | `List[str]` | required | — (resolved to `handoffs=[…]`) | Target agent keys. Unknown roles warned + skipped. |
| `timeout` | `int` (seconds) | `300.0` | `timeout_seconds` | Per-handoff execution timeout. |
| `max_depth` | `int` | `10` | `max_depth` | Maximum nested handoff chain length. |
| `max_concurrent` | `int` | `5` | `max_concurrent` | Maximum parallel handoffs (`0` = unlimited). |
| `detect_cycles` | `bool` | `true` | `detect_cycles` | Refuse to hand off if it would form a cycle. |
| `policy` | `str` | — | *(not yet mapped)* | Wrapper-only orchestration hint. Currently a no-op — core has no equivalent. |

> [!NOTE]
>
> Only keys that are present are forwarded. Omit a key to keep the `HandoffConfig` default.

***

## Common Patterns

**Triage router** — one agent fans out to specialists with a single-hop limit:

```yaml theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
agents:
  triage:
    role: Triage
    goal: Send each request to the right specialist
    handoff:
      to: [billing, tech]
      max_depth: 1
```

**Safe chains** — cap depth and refuse cycles for deep delegation graphs:

```yaml theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
agents:
  planner:
    role: Planner
    goal: Break work into steps and delegate
    handoff:
      to: [researcher, writer]
      max_depth: 3
      detect_cycles: true
```

***

## Best Practices

> [accordion] Match to: entries to agent keys, not display names
>
> `_wire_handoffs` resolves each `to:` value against the agent keys in the same `agents:` map. A typo is logged and skipped, so the handoff silently disappears — check your logs if a target never fires.

> [accordion] Set max\_depth for router agents
>
> The default depth is `10`. For a simple triage router, set `max_depth: 1` so a request cannot bounce through multiple specialists.

> [accordion] Keep detect\_cycles on
>
> Cycle detection defaults to `true`. Leave it enabled unless you have a deliberate loop — it prevents two agents from handing off to each other forever.

> [accordion] policy: is a no-op today
>
> The wrapper `policy:` key (e.g. `round-robin`) has no core equivalent yet, so it is parsed but ignored. Do not rely on it to change routing behaviour.

***

## Related

> [card] [Agent Handoffs](https://praison.ai/docs/features/handoffs.md)
>
> The full Python handoff API and context policies

> [card] [Handoff Tool Policy](https://praison.ai/docs/features/handoff-tool-policy.md)
>
> Control which tools a target agent inherits on handoff


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.