> ## 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.

# How a package fits together

> One rule explains the whole file: every list on an agent has a matching top-level block.

A package is one `agent.yaml` plus the prompts, tool files and knowledge
folders it points at. It answers three questions: who answers the call, what
each agent may do, and what each of those things actually is.

One rule explains the whole file:

> **Every list on an agent has a matching top-level block with the same name.
> The list holds names. The block holds the definitions.**

On this page:

* [Quickstart](#quickstart) - the smallest package with two agents
* [The five things an agent can do](#the-five-things-an-agent-can-do) - and which give the caller back
* [Every key an agent takes](#every-key-an-agent-takes) - three required, five lists
* [Build one in four steps](#build-one-in-four-steps) - the worked version
* [How a value gets from one step to the next](#how-a-value-gets-from-one-step-to-the-next) - `variables:`, `assign:`, `context:`
* [What the compiler holds for you](#what-the-compiler-holds-for-you) - the errors you cannot write past

## Quickstart

Two agents. `front_desk` answers, and can hand the caller to
`complaint_specialist`:

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

agents:
  front_desk:
    instructions: instructions.md
    think: reasoning
    speak: voice
    handoffs:
      - to_complaints

  complaint_specialist:
    instructions: agents/complaints.md
    think: reasoning
    speak: voice

handoffs:
  to_complaints:
    to: complaint_specialist
    when: The caller has a complaint.
```

```sh theme={null}
unmute validate my-agent
```

`front_desk` lists the **name** `to_complaints`. The top-level `handoffs:`
block holds the **definition**. That is the rule, and every other list works
the same way.

Tasks are the one exception: a task is defined right inside the agent that uses
it first, under that agent's own [`tasks:`](/build/orchestration/tasks) list. A
second agent that runs the same task just names it.

## The five things an agent can do

An agent is a person on the phone. It can do five kinds of things, and each
kind has its own list:

| List on the agent                                  | What it means                                                   | Does the agent get the caller back?      |
| -------------------------------------------------- | --------------------------------------------------------------- | ---------------------------------------- |
| [`tools:`](/build/tools/overview)                  | do real work: look something up, call an API                    | yes, a tool just returns data            |
| [`tasks:`](/build/orchestration/tasks)             | run a smaller job with its own prompt, and use its typed result | yes, the task finishes and reports back  |
| [`task_groups:`](/build/orchestration/task-groups) | run several tasks in a fixed order, then use the merged result  | yes, the group finishes and reports back |
| [`handoffs:`](/build/orchestration/handoffs)       | give the caller to another agent                                | no, the other agent takes over           |
| [`escalations:`](/transfers/overview)              | give the caller to a human                                      | no, the call leaves the system           |

If you remember one thing, remember the third column. Tools, tasks and task
groups come back. Handoffs and escalations do not.

### Every key an agent takes

An agent has three required keys and five optional lists. There are no others.

<ParamField path="instructions" type="file path" required>
  The Markdown file holding this agent's prompt, relative to the package root.
</ParamField>

<ParamField path="think" type="model name" required>
  Which reasoning model this agent uses. Names one entry under
  [`models.think`](/models/llm).
</ParamField>

<ParamField path="speak" type="model name" required>
  Which voice this agent speaks in. Names one entry under
  [`models.speak`](/models/tts).
</ParamField>

<ParamField path="tools" type="list of names">
  Tools this agent may call. Each name is a file under `tools/<name>.yaml`.
</ParamField>

<ParamField path="tasks" type="list of tasks or names">
  Tasks this agent may run. Write the task in full to define it here, or write
  a bare name to run a task another agent already defined.
</ParamField>

<ParamField path="task_groups" type="list of names">
  Task groups this agent may run. Each name is an entry under the top-level
  `task_groups:`.
</ParamField>

<ParamField path="handoffs" type="list of names">
  Agents this one can hand the caller to. Each name is an entry under the
  top-level `handoffs:`.
</ParamField>

<ParamField path="escalations" type="list of names">
  People this agent can put the caller through to. Each name is an entry under
  the top-level `escalations:`.
</ParamField>

## Build one in four steps

Say you want two agents, and each one can run a task.

**Step 1. Say who answers.**

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

**Step 2. Write the agents, with their tasks nested right inside.** A task
carries both what it is and when to run it, so there is one name and one
place to read it. You have not defined the handoffs and escalations yet.
That is fine, you will in the next step.

```yaml agent.yaml theme={null}
agents:
  front_desk:
    instructions: instructions.md
    think: reasoning
    speak: voice
    tools:
      - look_up_prices
    tasks:
      - name: verify_customer
        when: Confirm who the caller is before anything personal.
        instructions: tasks/verify-customer.md
        assign:
          - customer_phone: result.customer_phone
      - name: manage_booking
        when: The caller wants to create, change, or cancel a booking, once the caller is identified.
        instructions: tasks/booking.md
        assign:
          - booking_id: result.booking_id
    handoffs:
      - to_complaints
    escalations:
      - to_manager

  complaint_specialist:
    instructions: agents/complaints.md
    think: reasoning
    speak: voice
    tools:
      - record_complaint
    # front_desk already defines this task. A bare name runs the same one
    # from here, so there is one definition and both agents can offer it.
    tasks:
      - verify_customer
    handoffs:
      - to_front_desk
    escalations:
      - to_manager
```

Read `front_desk` top to bottom. You already know everything it can do, and
which kind of thing each one is. That glance is the point of the five lists.

**Step 3. Define the handoffs and escalations.**

Each handoff may choose how much conversation travels with the caller. Omitted
history means `messages`. Saved values reach the receiving model only through
placeholders in its prompt.

```yaml agent.yaml theme={null}
handoffs:
  to_complaints:
    to: complaint_specialist
    when: The verified caller has a complaint.
    context:
      history: full
  to_front_desk:
    to: front_desk
    when: The caller is done complaining and wants something else.
    context:
      history: full

escalations:
  to_manager:
    when: The caller asks for a manager.
    cold:
      destination: manager_line
      ring_timeout: 30s
      on_unavailable: hangup
```

**Step 4. Define the tools.** Tools are the one place the rule bends: a tool
is its own file under `tools/<name>.yaml`, so the top-level `tools:` is a
plain list of names rather than a block of definitions:

```yaml agent.yaml theme={null}
tools:
  - look_up_prices
  - record_complaint
```

Done. Notice you never wrote `verify_customer` twice. It is defined once,
inside `front_desk`, and `complaint_specialist` just names it. Sharing is
naming the same thing.

## How a value gets from one step to the next

Three keys do this, and they each do one thing. Each has its own page.

<ParamField path="variables:" type="top-level block">
  Declares a value the call can hold, and what type it is. A variable is the
  box. Nothing fills it by itself.

  [Variables](/build/variables)
</ParamField>

<ParamField path="assign:" type="on a task">
  Fills a variable when the task finishes. `- customer_phone: result.phone`
  means "put the task's `phone` answer into `customer_phone`".

  [Tasks](/build/orchestration/tasks)
</ParamField>

<ParamField path="context:" type="on a task or a handoff">
  Chooses how much of the conversation so far the next step can read. It moves
  the transcript, not your saved values.

  [Context scope](/best-practices/context-scope)
</ParamField>

Saved values are never added to a prompt on their own. A prompt reads a value
only when it names it, as `{{customer_phone}}`.

### Ordering work without a gate

In the example above, `verify_customer` fills `customer_phone` with `assign:`,
and `manage_booking`'s own `when:` says it runs only once the caller is
identified. That is how "verify before booking" works: the order lives in the
prompt, not in a gate, so the caller hears nothing about it.

Put that clause on the work that needs the value, not on the route to it. And
never hold up the way to a person: somebody asking for a manager should not be
interviewed first.

## Tasks attach handoffs, and nothing else

A task has `tools:` and `handoffs:` and no other list. There is no `tasks:`,
no `task_groups:` and no `escalations:` key on a task, so a task cannot run
another task or task group, or reach a person directly. That is not a rule
you have to remember. The key does not exist, so the file cannot be written.

## What the compiler holds for you

* Every name in an agent's list must exist in the matching top-level block,
  or, for a task, be defined inline by some agent. A typo is a build error,
  not a silent gap.
* A name listed under the wrong kind is refused, and the message names the
  list it belongs on.
* All five kinds share one namespace, because every name becomes a callable
  function at runtime. Two things cannot share a name, and two agents
  defining a task under the same name is refused the same way.
* A handoff, escalation, task group or tool that no agent reaches is also a
  build error. There is no dead config to forget about.
* A task can list `tools:` and `handoffs:` only, enforced by the shape of the
  file.

Two of those errors, as you will actually see them:

```text theme={null}
agent.yaml:31: "verify_customer" is a task, so move it out of the tools: list
  and into the tasks: list
```

```text theme={null}
agent.yaml:47: escalation "to_manager" is declared but no agent reaches it; add it
  to the escalations: of one of these agents: front_desk, complaint_specialist
```

## Order, and what it does not mean

Nothing an agent lists runs in list order. The model picks what to use from the
`when:` text. Two things in a package do run in a fixed order: the `steps:` of
a task group, and the entries of [`prefetch:`](/build/prefetch). Pre-fetch
entries resolve top to bottom, and an entry that reads a value only a later
entry assigns stops the build.

Order is not free everywhere, though: the order of names in a list is the
order the tools are declared to the model in the generated code, so
reordering a list produces a different file. Treat that as presentation, not
as control flow.

## The order to write the file in

```
version, name, entry_agent
agents
handoffs
escalations
task_groups
variables
prefetch
secrets, destinations, knowledge, models, tools
conversation, tracing, channels, capacity
```

That order is a convention, not a schema rule, and it exists so a reader meets
the agents first and the plumbing last. `unmute init` writes the shape without
`prefetch:`, since the scaffold declares none. `examples/salon-concierge` shows
where it lands once a package uses it: right after `variables:`.

Every one of those keys, with its type, whether it is required, and what values
it accepts, is in the
[`agent.yaml` key table](/reference/agent-yaml#all-keys).

## Where to go next

<Columns cols={2}>
  <Card title="Your first task" icon="footprints" href="/build/orchestration/first-task">
    Add one task to the agent you just made, one key at a time.
  </Card>

  <Card title="Tasks" icon="list-checks" href="/build/orchestration/tasks">
    Nested tasks and typed results.
  </Card>

  <Card title="Handoffs" icon="users" href="/build/orchestration/handoffs">
    When to split into two agents.
  </Card>

  <Card title="Task groups" icon="list-ordered" href="/build/orchestration/task-groups">
    Tasks in a fixed order, sharing what they learn.
  </Card>

  <Card title="Human transfers" icon="phone-forwarded" href="/transfers/overview">
    Cold and warm escalation to a person.
  </Card>
</Columns>
