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

# Your first agent

> The smallest real agent: a prompt, four models, and one file that says who is answering.

An Unmute package is a directory. The agent lives in `agent.yaml`, the prompt
lives in a Markdown file next to it, and the target choice lives in
`targets.yaml`. This page walks that file, key by key. Everything else in this
section adds to it.

Make one now, then read along in the file it writes. Already ran this in the
quickstart? You are sitting inside that `my-agent/` directory: `cd ..` first,
or skip the command and read along in the file already on disk.

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

```text theme={null}
created my-agent/agent.yaml
created my-agent/.env.example
created my-agent/.gitignore
created my-agent/instructions.md
created my-agent/targets.yaml
created my-agent/tools/end_call.yaml
```

<Tip>
  That package already validates and already runs. One agent, browser audio, one
  built-in tool so it can hang up, no phone number and no third-party account.
  Everything below is a tour of what is in it, so nothing here is a detour.
</Tip>

On this page:

* [The agent file](#the-agent-file) - every top-level key `unmute init` writes
* [The target file](#the-target-file) - where this package compiles to
* [Try it](#try-it) - validate, then talk to it in a browser

## The agent file

The small snippets below keep one block on screen at a time. Expand the full
file when you want to see how they fit together. This is
`my-agent/agent.yaml` as the scaffold wrote it, with its explanatory comments
taken out so the shape is visible.

<Accordion title="Complete agent.yaml">
  ```yaml theme={null}
  version: 1
  name: my-agent
  entry_agent: assistant

  agents:
    assistant:
      instructions: instructions.md
      think: assistant_model
      speak: assistant_voice
      tools:
        - end_call

  secrets:
    - OPENAI_API_KEY
    - SLNG_API_KEY

  models:
    think:
      assistant_model:
        description: default reasoning model
        provider: openai
        model: "gpt-5.6-terra"
        params:
          reasoning_effort: none
    speak:
      assistant_voice:
        description: default voice
        provider: slng
        model: "deepgram/aura:2"
        voice: "aura-2-thalia-en"
    listen:
      transcriber:
        provider: slng
        model: "deepgram/nova:3"
    turn:
      detector:
        provider: livekit
        model: turn-detector-mini

  tools:
    - end_call

  conversation:
    greeting:
      speaks_first: agent
      text: "Hi there, I'm listening. What can I help you with?"

  channels:
    web:
      kind: realtime_audio

  capacity:
    peak_sessions: 10
    max_sessions: 20
    avg_session_duration: 5m
  ```
</Accordion>

Now each block.

### `name`

```yaml theme={null}
name: my-agent
```

What this agent is called. The deployed name is this joined to the target it was
compiled for, so on a target called `livekit` it deploys as
`my-agent-livekit`. Required, lowercase letters, digits and single
hyphens, and it must not be a name another package in your organisation already
uses: a deploy replaces the agent whose name it matches. The
[`name` reference](/reference/agent-yaml#name) has the whole rule.

### `entry_agent`

```yaml theme={null}
entry_agent: assistant
```

Which agent answers. A package can hold several agents; exactly one starts the
call. The name has to be a key in the `agents:` map.

### `agents`

```yaml theme={null}
agents:
  assistant:
    instructions: instructions.md
    think: assistant_model
    speak: assistant_voice
```

An agent is a prompt plus the models it speaks and thinks with. `instructions`
is a path to a Markdown file in the package. Writing the prompt in its own file
means it reviews like prose, not like YAML.

### `secrets`

```yaml theme={null}
secrets:
  - OPENAI_API_KEY
  - SLNG_API_KEY
```

A list of environment variable names. Never values. Unmute writes these into
the generated `.env.example` and into a startup check inside the generated
project, so a missing key stops the container with a clear message instead of
failing on the first spoken word.

<Warning>
  There is no way to write a secret's value in the package, on purpose. See
  [secrets](/reference/secrets).
</Warning>

### `models`

Four kinds of model, grouped by what they do:

| Section  | Job                                           | Common name           |
| -------- | --------------------------------------------- | --------------------- |
| `think`  | decides what to say and which tool to call    | LLM                   |
| `speak`  | turns text into audio                         | TTS                   |
| `listen` | turns audio into text                         | STT                   |
| `turn`   | decides when the caller has finished speaking | turn detection or VAD |

Each section holds named entries. The name is yours: `assistant_model`,
`assistant_voice`, `transcriber`, `detector` above. An agent then points at the
entries it wants by name.

```yaml theme={null}
models:
  think:
    assistant_model:
      provider: openai
      model: "gpt-5.6-terra"
      params:
        reasoning_effort: none
```

`provider` names the integration; `model` and `voice` are passed to that
provider exactly as you wrote them. Unmute does not keep a list of valid model
ids, so a typo shows up as a provider error at run time, not at compile time.

`params:` is normally passthrough for anything else the provider takes. The one
line here earns its place: `gpt-5.6-terra` is a reasoning model, and OpenAI
refuses a chat request that carries function tools unless it sets
`reasoning_effort`. This package has a tool, `end_call`, so the line is doing
real work from the first run. The LiveKit Responses compiler directive is the
narrow exception; [Reasoning model](/models/llm) has both forms.

<Note>
  You can define more entries than you use. Unused entries are legal
  alternates, which makes swapping a voice a one line change.
</Note>

The `listen` and `turn` sections have one entry each here, so nothing needs to
select them. With two or more entries you add a top level `listen:` or `turn:`
line naming the one to use.

### `conversation`

```yaml theme={null}
conversation:
  greeting:
    speaks_first: agent
    text: "Hi there, I'm listening. What can I help you with?"
```

Who speaks first and what they say. The greeting is spoken word for word without
going through the model, so changing it changes nothing else. `conversation` also
holds `interruption:`, `inactivity:` and `max_duration:`, which the scaffold
leaves out; the
[`conversation` reference](/reference/agent-yaml#conversation) has them.

### `channels` and `capacity`

```yaml theme={null}
channels:
  web:
    kind: realtime_audio

capacity:
  peak_sessions: 10
  max_sessions: 20
  avg_session_duration: 5m
```

`channels` says how people reach this agent. `web: realtime_audio` is browser
audio, which is what `unmute dev` serves. Phones come later, in
[Telephony](/telephony/overview).

`capacity` is your traffic estimate. The compiler turns it into worker counts
and quota numbers in the generated project, and marks them unbenchmarked
because they come from a conservative assumption, not from a measurement of
your agent.

## The target file

```yaml targets.yaml theme={null}
targets:
  livekit:
    provider: livekit
    version: "1.8.1"
    sdk_language: python
```

One target. Nothing in `agent.yaml` names a target, so this file is the only
place the choice lives, and one package can declare several. A second instance
here compiles a second complete project from the same agent, and a target that
cannot run a model entry as written overrides that entry by name rather than
changing the agent. [Targets](/targets/overview) has both.

## Try it

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

The scaffolded package validates clean. A warning, when you do get one, does
not stop the command: it names a real difference worth reading. Now talk to
the agent in your browser:

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

## Agent fields

<ParamField path="instructions" type="string" required>
  Path to a Markdown prompt inside the package. No prompt is inferred.
</ParamField>

<ParamField path="think" type="string" required>
  Name of an entry in `models.think`. No profile is inferred.
</ParamField>

<ParamField path="speak" type="string" required>
  Name of an entry in `models.speak`. No profile is inferred.
</ParamField>

<ParamField path="tools" type="list of strings">
  Names of loaded tool files this agent may call. Omit for no ordinary tools.
</ParamField>

<ParamField path="tasks" type="list of definitions or names">
  Nested task definitions or bare names of tasks defined by another agent. Omit for no
  tasks. See [task fields](/build/orchestration/tasks#every-key-a-task-takes).
</ParamField>

<ParamField path="task_groups" type="list of strings">
  Names from the top-level `task_groups` catalog. Omit for no groups.
</ParamField>

<ParamField path="handoffs" type="list of strings">
  Names from the top-level `handoffs` catalog. Omit for no agent handoffs.
</ParamField>

<ParamField path="escalations" type="list of strings">
  Names from the top-level `escalations` catalog. Omit for no human transfers.
</ParamField>

## Where to go next

<Columns cols={2}>
  <Card title="How a package fits together" icon="map" href="/build/how-a-package-fits-together">
    One rule that gets you from this agent to several.
  </Card>

  <Card title="Variables" icon="braces" href="/build/variables">
    Personalize each call and pass values without exposing them to the model.
  </Card>

  <Card title="Agent configuration" icon="file-code" href="/reference/agent-yaml">
    Every supported `agent.yaml` key and value.
  </Card>
</Columns>
