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

# Cascade

> Build an agent with separate listening, reasoning, and speaking models, then extend it with tasks and state.

Use separate models to choose how your agent hears a caller and speaks its answer.
In a cascade, transcription produces text, a reasoning model answers, and a synthesizer speaks.
Turn detection decides when to start the reply. Streaming lets some stages overlap.

On this page:

* [Quickstart](#quickstart) - a complete voice desk
* [Pros and cons](#pros-and-cons) - control and complexity
* [Bind the models](#1-bind-the-three-models) - one job per entry
* [Choose the turn](#2-choose-when-the-agent-replies) - defaults and selectors
* [Extend the desk](#3-add-tools-tasks-or-saved-state) - grow the workflow
* [Advanced](#advanced) - switch architecture
* [Troubleshooting](#troubleshooting) - correct common failures
* [Where to go next](#where-to-go-next) - model references

## Quickstart

Create a new package with a LiveKit target. If initialization opens the console, select LiveKit and finish creating the package.

```sh Terminal theme={null}
unmute init voice-desk
```

Replace `voice-desk/agent.yaml` with this **complete file**:

```yaml voice-desk/agent.yaml theme={null}
version: 1
name: voice-desk
architecture: cascade
entry_agent: desk
secrets:
  - OPENAI_API_KEY
  - SLNG_API_KEY
models:
  turn:
    detector:
      provider: livekit
      model: turn-detector-mini
  listen:
    transcriber:
      provider: slng
      model: "deepgram/nova:3"
  think:
    reasoning:
      provider: openai
      model: gpt-5.6-terra
      params:
        reasoning_effort: none
  speak:
    voice:
      provider: slng
      model: "deepgram/aura:2"
      voice: aura-2-thalia-en
agents:
  desk:
    instructions: instructions.md
    think: reasoning
    speak: voice
channels:
  web:
    kind: realtime_audio
capacity:
  peak_sessions: 1
  max_sessions: 2
  avg_session_duration: 3m
```

Keep the scaffold's `targets.yaml`, but remove its target-level `models:` overrides because the model palette above replaces the scaffold's.
Keep its framework provider and version pin, and remove any phone `connection:` for this browser example. Replace `voice-desk/instructions.md` with this complete prompt:

```markdown voice-desk/instructions.md theme={null}
You are a friendly information desk. Answer in short spoken sentences.
Ask one question at a time. If you do not know an answer, say so.
```

Set `OPENAI_API_KEY` and `SLNG_API_KEY` in your shell or the package's `.env`, then run:

```sh Terminal theme={null}
unmute validate voice-desk
unmute compile voice-desk
unmute dev voice-desk --target livekit
```

Use Docker for this LiveKit run. The [Pipecat target](/targets/pipecat) is another option; it runs locally with `uv`.
The example below stays with this same `desk` agent.

## Pros and cons

### Pros

* **Control the workflow.** On LiveKit and Pipecat, combine tasks, handoffs, saved values, and tool calls. Each step can have its own instructions and access to the values it needs.
* **Choose each role.** Use a supported transcriber, reasoning model, and voice independently. Spend more on the part that needs better quality without replacing the others.
* **Find the failing stage.** Compare the recognized text, model reply, tool result, and spoken output. A wrong transcription needs a different fix from a failed tool.

### Cons

* **More sources of delay.** Turn detection, transcription, reasoning, speech generation, and tools all contribute. Streaming reduces the wait, but does not remove those costs.
* **More parts to operate.** Several integrations bring separate credentials, availability limits, and failure modes.
* **Less audio context for reasoning.** A transcript carries the words, but can lose tone, hesitation, and other clues in the caller's voice.

[LiveKit's comparison](https://livekit.com/blog/realtime-vs-cascade) explains these
component tradeoffs. [Coval's comparison](https://www.coval.ai/blog/speech-to-speech-vs-cascaded-voice-ai-which-architecture-should-you-deploy/)
shows why control and diagnosis matter when the agent must complete real work.

## 1. Bind the three models

The quickstart names the transcriber, reasoning model, and voice under `models`.
The agent binds its reasoning and voice by name. A single transcriber is selected automatically for the package.

<ParamField path="architecture" type="cascade | realtime | live">
  Set `cascade`, or omit the key for the same result. Cascade is supported on all three targets, subject to each target's model and feature limits.
</ParamField>

<ParamField path="think" type="a models.think entry name" required>
  Agent-level reasoning binding, such as `agents.desk.think: reasoning`.
</ParamField>

<ParamField path="speak" type="a models.speak entry name" required>
  Agent-level voice binding, such as `agents.desk.speak: voice`.
</ParamField>

<ParamField path="listen" type="a models.listen entry name">
  Package-level selector. Omit it when there is one transcriber; name an entry when there is more than one. It does not belong under an agent.
</ParamField>

| Role      | Where to configure it           |
| --------- | ------------------------------- |
| Listening | [Transcription](/models/stt)    |
| Reasoning | [Reasoning models](/models/llm) |
| Speaking  | [Voices](/models/tts)           |

A model name is forwarded to its provider. Validation checks the binding, not whether your account can use that model.

## 2. Choose when the agent replies

The quickstart binds LiveKit’s local turn detector. A cascade needs a turn binding.
When adding Pipecat, override `detector` for that target with `provider: local` and `model: silero`.
Follow [Turn detection](/models/turn-detection) for the target override shape and timing options.

<ParamField path="turn" type="a models.turn entry name">
  Package-level selector. One turn entry is selected automatically. With several entries, name the one to use here.
</ParamField>

Listen for pauses and interruptions before changing settings.
A shorter silence window can answer faster but may cut off callers who pause mid-sentence.

## 3. Add tools, tasks, or saved state

Extend the same desk with a [local tool](/build/tools/python), then add a [task](/build/orchestration/tasks) when a job needs its own steps.
For example, the caller wants to change an existing request:

1. Look up the request with a tool.
2. Collect the change in a task and save its result.
3. Confirm the details before running the update tool.
4. Handle a refused update, or hand the call to another agent with the context it needs.

[Variables](/build/variables) hold values across steps. Each prompt names the values it may read; the tool checks the conditions for changing the record.
Separate steps give you places to check the behavior, but do not guarantee a correct tool call.
Test successful updates, missing inputs, and failed actions.

Tasks, task groups, and handoffs are supported on LiveKit and Pipecat cascade targets.
SLNG has its own [target limits](/targets/slng#what-a-slng-package-may-not-ask-for).
Both S2S architectures support tools, but their current Unmute integrations do not support these task and state controls.

The complete [salon concierge](https://github.com/slng-ai/unmute/tree/main/examples/salon-concierge) shows booking, task return, and handoff.
Its phone routes and tracing need their own configuration and credentials.

## Advanced

<Accordion title="Compare latency across architectures">
  Transcription can run while the caller speaks, and synthesis can begin while the model generates text.
  Do not add all stage durations as though every stage waits for the previous one to finish.
  Model choice, turn timing, network placement, and tools affect the wait for the first audio.

  Tune the slow stage before replacing the architecture, and compare completed actions as well as response time.
  See [where the time goes](/optimization/latency#where-the-time-goes) and the [architecture comparison](/build/architecture/overview#pros-and-cons).
</Accordion>

<Accordion title="Switch this desk to speech-to-speech">
  Follow [Switch architecture](/build/architecture/overview#3-replace-the-models-and-agent-bindings).
  Replace the model palette and the agent's `think:`/`speak:` bindings together.
  Remove old target overrides and any features the destination refuses.
</Accordion>

<Accordion title="Switch back from live or realtime">
  Use the quickstart's complete `agent.yaml` for a minimal cascade, keeping your prompt file.
  For an existing package, copy its model palette and `think:`/`speak:` bindings instead, and add the required provider secrets.
  Remove `models.live`, `models.realtime`, and the old agent binding before validating.
  Do not replace a larger package's whole file if you need to retain its tools or workflow.
</Accordion>

## Troubleshooting

### Validation rejects an agent-level listen field

Listening is selected for the package, not for each agent.
**Fix:** move the selector to the top level, or omit it when only one transcriber exists.

### The agent waits too long or cuts callers off

Turn settings or provider latency may be responsible.
**Fix:** inspect the dev measurements and follow [Turn taking](/optimization/turn-taking) before replacing all three models.

### A provider is refused for one role

Targets support different providers for each role.
**Fix:** choose a supported integration from that role's reference, then validate every declared target.

## Where to go next

<Columns cols={2}>
  <Card title="Add a task" icon="list-check" href="/build/orchestration/tasks">Give one job its own workflow.</Card>
  <Card title="Choose architecture" icon="layers" href="/build/architecture/overview">Compare and switch pipelines.</Card>
</Columns>
