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

> ## Agent Instructions
> Unmute compiles to exactly three targets. Pipecat and LiveKit are code targets: compile writes a Python project you run. SLNG is a hosted target: compile writes a deployment body and SLNG runs the agent, so it has no `unmute dev`. Those three are the only values `provider` accepts in `targets.yaml`. Deepgram and ElevenLabs appear in these docs as model vendors, which is not the same thing as a target, and `slng` is both.
> The Go structs in `internal/spec` and `internal/ir` are the schema truth. Check a field against them, or run `unmute validate`, rather than against what you remember.

# Handoffs

> Move the caller to an agent with different instructions and tools.

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](/build/orchestration/tasks) when the work should
return control to the same agent.

On this page:

* [Declare and attach a handoff](#declare-and-attach-a-handoff) - the two blocks
* [Every key a handoff takes](#every-key-a-handoff-takes) - all four
* [Share only intentional saved values](#share-only-intentional-saved-values) - saving is not sharing
* [Choose conversation history](#choose-conversation-history) - what travels with the caller
* [A handoff does not return](#a-handoff-does-not-return) - the one thing to remember

## Declare and attach a handoff

```yaml agent.yaml theme={null}
entry_agent: booking_desk

agents:
  booking_desk:
    instructions: instructions.md
    think: reasoning
    speak: voice
    handoffs:
      - to_appointment_manager

  appointment_manager:
    instructions: agents/appointment-manager.md
    think: reasoning
    speak: voice

handoffs:
  to_appointment_manager:
    to: appointment_manager
    when: The caller wants to change an existing appointment.
    announce: I’m connecting you with our appointment manager now.
```

### Every key a handoff takes

<ParamField path="to" type="string" required>
  An existing agent name. The conversation moves to that agent and does not return. No
  destination is inferred.
</ParamField>

<ParamField path="when" type="string">
  The situation the model reads to decide whether to hand over. Omission supplies no
  trigger guidance, so write one.
</ParamField>

<ParamField path="announce" type="string">
  Exact text spoken before handing over. Omit for a silent handoff.
</ParamField>

<ParamField path="context" type="object">
  The [history fields](/reference/agent-yaml#context). Omitted means `messages`. Saved
  values are visible only where the receiving prompt names them.
</ParamField>

## Share only intentional saved values

Declare a value once and reference it in the receiving prompt:

```yaml agent.yaml theme={null}
variables:
  appointment_id:
    type: Id
    description: The appointment selected during this call.
```

```markdown agents/appointment-manager.md theme={null}
You are handling appointment {{appointment_id}}.
Ask what the caller wants to change.
```

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](/best-practices/context-scope)
walks through this choice and the return behavior of tasks.

## Choose conversation history

History defaults to `messages` when `context` or `history` is omitted.

```yaml agent.yaml theme={null}
handoffs:
  to_appointment_manager:
    to: appointment_manager
    when: The caller wants to change an existing appointment.
    context:
      history: reset
```

| `history`  | The receiving agent gets                                          |
| ---------- | ----------------------------------------------------------------- |
| `messages` | Earlier caller and agent speech, without tool records.            |
| `full`     | Earlier speech and paired tool records, without old instructions. |
| `last_n`   | The newest bounded entries.                                       |
| `reset`    | No earlier conversation.                                          |
| `summary`  | A generated summary on LiveKit only.                              |

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 task-group 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:

```sh theme={null}
unmute validate examples/salon-concierge
unmute dev examples/salon-concierge --target pipecat
```

<Card title="Choosing a structure" icon="git-branch" href="/build/orchestration/choosing-a-structure">
  Tools, tasks, task groups, or a second agent: which split to reach for, and what it costs.
</Card>

## Where to go next

<Columns cols={2}>
  <Card title="Tasks" icon="list-checks" href="/build/orchestration/tasks">
    When control should come back instead.
  </Card>

  <Card title="Choosing a structure" icon="git-branch" href="/build/orchestration/choosing-a-structure">
    Task, task group or handoff, and what each one costs.
  </Card>

  <Card title="Context scope" icon="scissors" href="/best-practices/context-scope">
    Deciding what the receiving agent should be able to read.
  </Card>

  <Card title="Human transfers" icon="phone-forwarded" href="/transfers/overview">
    Handing the caller to a person, which is a different thing.
  </Card>
</Columns>
