Handoffs are secure by default — the target agent only inherits tools shared with the source agent. See Handoff Tool Policy.
Quick Start
Pass agents directly
Pass specialist agents to
handoffs and the routing agent gets a transfer tool for each.How It Works
When you sethandoffs, PraisonAI converts each target into a transfer_to_<agent> tool, adds routing instructions to the agent’s prompt, and passes conversation history when control transfers.
| Phase | What happens |
|---|---|
| 1. Detect | The routing agent decides a specialist is needed |
| 2. Transfer | The matching handoff tool is called |
| 3. Run | The target agent runs its full chat() pipeline |
| 4. Return | The specialist’s response flows back to the user |
Which Handoff Setup to Use?
Configuration Options
handoff() builds a configured transfer tool for a target agent.
Handoff Tool Policy — tool security boundary options
| Option | Type | Default | Description |
|---|---|---|---|
agent | Agent | required | Target agent to hand off to |
tool_name_override | str | None | None | Custom tool name (default transfer_to_<agent>) |
tool_description_override | str | None | None | Custom tool description shown to the LLM |
on_handoff | Callable | None | None | Callback run when the handoff is invoked |
input_type | type | None | None | Expected input type for structured data |
input_filter | Callable | None | None | Function to filter/transform passed history |
tool_policy_mode | "intersect" | "passthrough" | "intersect" | Which tools the target inherits |
blocked_tools | list[str] | None | None | Tools always stripped from the target |
Common Patterns
Pattern 1 — Callback on handoff
Pattern 2 — Filter passed history
Pattern 3 — Type-safe handoff
Handoff Results
handoff_to() returns a HandoffResult describing the outcome.
| Field | Type | Description |
|---|---|---|
success | bool | Whether the handoff completed successfully |
response | str | Response from the target agent |
target_agent | str | Name of the agent that received the handoff |
source_agent | str | Name of the agent that initiated the handoff |
duration_seconds | float | Time taken for the handoff |
error | str | Error message if the handoff failed |
outcome | AgentRunOutcome | Typed outcome with .status and .is_retryable() |
Best Practices
Give each agent one clear responsibility
Give each agent one clear responsibility
A specialist with a focused role routes cleanly. Overlapping responsibilities make the routing agent’s tool choice ambiguous.
Filter history to cut tokens
Filter history to cut tokens
Pass
input_filter=handoff_filters.remove_all_tools or handoff_filters.keep_last_n_messages(5) so the target agent gets only the context it needs.Use TypedHandoff for structured data
Use TypedHandoff for structured data
When a specialist needs typed fields, use
TypedHandoff(agent=..., input_schema=Model) — the framework validates the payload at the boundary.Keep a fallback path
Keep a fallback path
Let the routing agent answer requests it cannot route rather than failing silently.
Related
Handoff Tool Policy
Secure tool boundaries during handoff
Typed Handoffs
Schema-validated handoffs with Pydantic models

