Skip to main content
A handoff moves the caller from one agent to another. The receiving agent owns the rest of the call. Nothing returns automatically. Use a handoff when two roles need different instructions, tools, or permissions. Use a task when the work should return control to the same agent. On this page:

Declare a handoff

agent.yaml
The agent that hands over writes the block. Another agent that wants the same handoff lists its bare name, - to_appointment_manager. A bare name nobody defines is refused.

Every key a handoff takes

string
required
A lower snake case name, unique across the package.
string
required
An existing agent name. The conversation moves to that agent and does not return. No destination is inferred.
string
The situation the model reads to decide whether to hand over. Omission supplies no trigger guidance, so write one.
list of strings
Any number of fixed lines. One is picked each time the handoff runs, never the one said last, and the next agent’s voice says it. A line takes no {{ }} placeholder and a blank line is refused. Omit for a silent handoff.
list of one-key pairs
Pairs of variable: result.field saved as the handoff happens. Omit to save nothing.
object
A tool of the receiving agent, run in code as it takes the call, so its first turn comes from the tool and not from a model request. Keys call and with.
string
required
Name of the receiving agent’s tool. Required inside start.
list of one-key pairs
The tool’s inputs, as - day: state.requested_day. A ? after the value lets the call run without it; a value without one is required.
object
The history fields. Omitted means messages. Saved values are visible only where the receiving prompt names them.

Share only intentional saved values

Declare a value once and reference it in the receiving prompt:
state.py
agents/appointment-manager.md
The receiving agent gets the saved appointment_id because its prompt names it. It does not receive other variables automatically. A dotted placeholder sends only that field. With messages, it can also read facts spoken earlier. To avoid repeating verification or asking for an appointment already selected, reference the saved verification status and appointment in the receiving prompt, then explain how to use them. The context guide walks through this choice and the return behavior of tasks.

Choose conversation history

History defaults to messages when context or history is omitted.
agent.yaml
With reset, no trigger sentence or automatic briefing is added. Save the needed facts before the handoff and reference them in the receiving prompt. If a needed fact was not saved, the receiver asks the caller. messages keeps spoken content. It is useful context sharing, not transcript redaction.

A handoff does not return

The second agent owns the call from that point. Returning to the first agent is another declared handoff in the opposite direction. When a task invokes a handoff, that task and the remaining flow steps end before the receiving agent starts. On LiveKit, the receiving agent’s own handoffs are hidden for its first automatic turn. They return on the next caller turn. This prevents two agents from bouncing the call before the caller hears anything.

Try it

The salon is the shipped example with a handoff in each direction between the concierge and the complaint specialist. These commands need a clone of the unmute repo:

Choosing a structure

Tools, tasks, flows, or a second agent: which split to reach for, and what it costs.

Where to go next

Tasks

When control should come back instead.

Choosing a structure

Task, flow or handoff, and what each one costs.

Context scope

Deciding what the receiving agent should be able to read.

Human transfers

Handing the caller to a person, which is a different thing.