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

# Designing declared state

> Choose facts that help the next task, keep requested changes separate from saved outcomes, and avoid repeated questions.

Declare a variable when another part of the call needs a reliable fact.
Then reference it only in the prompts or tools that need it. Keeping a value
in call state does not put it in every model request.

On this page:

* [One saved fact, end to end](#one-saved-fact-end-to-end) - declare, save, read
* [Start with the next reader](#start-with-the-next-reader) - who needs this value
* [Separate a request from an outcome](#separate-a-request-from-an-outcome) - asked for, not booked
* [Group fields that describe one result](#group-fields-that-describe-one-result) - when to use a shape
* [Match the type to the actual value](#match-the-type-to-the-actual-value) - what your tools return
* [Choose a current value or a list](#choose-a-current-value-or-a-list) - latest record, or every one
* [Finish as soon as the work succeeds](#finish-as-soon-as-the-work-succeeds) - save, then finish at once
* [Reuse verification deliberately](#reuse-verification-deliberately) - and what confirmed means
* [Write for a missing value](#write-for-a-missing-value) - write for the empty case
* [Check the whole path](#check-the-whole-path) - both prompts, then a trace

## One saved fact, end to end

Every saved fact has the same three parts. Declare it, save it in the step
that learns it, and read it in the prompt that needs it:

```yaml agent.yaml theme={null}
variables:
  appointment:
    type: Appointment
    description: The latest booking successfully saved by the booking task.

agents:
  concierge:
    tasks:
      - name: manage_booking
        when: The caller wants to book, move, or cancel an appointment.
        instructions: tasks/booking.md
        assign:
          - appointment: result.appointment
```

```markdown instructions.md theme={null}
Latest saved appointment: {{appointment}}
Use it when the caller refers to a booking just made.
```

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

The rest of this page is how to choose those three parts: what to declare,
who saves it, and who reads it next.

## Start with the next reader

For each value, identify who saves it and who needs it later:

| Value                                | Who saves it                              | Who reads it                                                                        |
| ------------------------------------ | ----------------------------------------- | ----------------------------------------------------------------------------------- |
| A confirmed phone number             | The verification task, through `confirm:` | `skip_when_confirmed:` on a task-group step, so a second booking skips verification |
| Requested new booking time           | The selection task                        | A reset task that performs the move                                                 |
| Successfully saved appointment       | The booking task                          | The owner and customer care                                                         |
| A caller's preferred contact channel | The intake task                           | Any later task that has to reach them                                               |

If nothing reads a value, you probably do not need it. If a later prompt needs
it, add the placeholder there. A description alone does not share the value.

## Separate a request from an outcome

A caller asking for Friday does not mean Friday is booked. Keep the requested
date separate from the successfully saved appointment. Update the saved
appointment only after the booking tool reports success.

This prevents a failed change from looking like a confirmed booking. It also
gives later tasks a clear answer when the conversation mentions both the old
and new times.

## Group fields that describe one result

Start with separate variables for independent facts, such as a caller's name
and preferred language. Use a shape when the fields describe the same record
and should be saved together.

For a booking flow:

1. Look at the successful booking tool result. Identify the fields later
   tasks need, such as its ID, service, date, and time.
2. Declare an `Appointment` shape with those fields. Use `Id` only if the
   actual booking ID fits its limits, and `Date` and `Time` for the saved time.
3. Declare `appointment` with `type: Appointment`. Give it a description such
   as "The latest appointment successfully saved by the booking tool."
4. Assign `appointment: result.appointment` in the booking task. Tell the task
   to copy the successful result and finish immediately.
5. Reference `{{appointment}}` in the owner, or just `{{appointment.date}}`
   in a prompt that needs only the date.

This keeps the booking ID and its current time together. Do not add unrelated
caller details to the shape just because the booking task can see them.
The [Variables guide](/build/variables#group-fields-into-a-shape)
shows the YAML declaration and field descriptions.

## Match the type to the actual value

Use a shape for fields that belong together. Include fields your tools return
or the caller can supply. Do not require an ID that no tool produces.

Use `T | None` when a successful result may legitimately have no value. A
required `Id` cannot be replaced by an empty string just to finish the task.

An external identifier may need `str`. For example, a booking slot containing
`|` does not fit `Id`. Preserve the exact value the tool returned. The
[type reference](/reference/variables#text-types-and-their-limits) lists the
format checks and their limits.

## Choose a current value or a list

Use one shaped variable for the latest successful appointment. Replacing it
makes the new date the current one.

Use a list when later tasks need several records. Append with `+`:

```yaml theme={null}
assign:
  - notes+: result.note
```

This needs a variable declared as `list[str]`, or `list[Note]` for a shape.
An identical structured item is not added twice. A changed item is added
separately; append does not find and replace an earlier record with the same
ID. Plain values may repeat.

## Finish as soon as the work succeeds

A task that performs an action and then waits for another caller turn can
accidentally absorb a new request. For example, a booking task might complete
a move, hear a complaint, and return `unserved` instead of saving the move.

Write the task prompt to save the successful result and make the `finish` call
immediately. Let the owner read the saved value and confirm it once. For a task
designed to save one record, finish after that record; run it again for another
request.

Better still, when the task's last action is a tool, name that tool under
`finish:`. The task then ends on the tool's success result by itself, saves its
`assign:` from that result, and the model never has to decide that the work is
done. See
[Say what success looks like](/build/orchestration/tasks#say-what-success-looks-like).

A non-empty `unserved_request` saves no assignments and returns only a status.
It does not undo an action already completed by a tool.

## Reuse verification deliberately

When verification is the first step of a task group, declare the skip rather
than asking a prompt to remember it. Put `skip_when_confirmed:` on that step,
naming the variable the step confirms. The group then skips the step when
that variable is confirmed at the moment the group starts, and runs it
otherwise. See
[Skip a step whose work is already done](/build/orchestration/task-groups#skip-a-step-whose-work-is-already-done).

Confirmed here is a real mark on the variable, set by `confirm:` alone: when
the task it names saves the value, and cleared by any other write. A prompt
sentence saying the caller was verified is not that mark, and neither is a
separate status variable a task assigns on success. Do not also keep a
separate status variable for this: once the group reads the confirm mark
itself, nothing needs a second copy of the same fact.

Use [`confirm:`](/build/prefetch#always-check-a-value-with-the-caller) for a
candidate value that must be checked with the caller. When that candidate
changes, prefetched values derived from the old candidate are cleared, and
the group runs the confirming step again on its own.

## Write for a missing value

Prefer a label and a clear fallback:

```markdown theme={null}
Latest saved appointment: {{appointment}}
Use it to identify the booking the caller just made. If no appointment is
recorded, ask which booking they mean and look it up.
```

An unset value renders as `none recorded yet.` An empty list renders as `[]`.
Neither proves that your booking system has no records; it means the call
has not saved that information.

## Check the whole path

Read the task prompt and the owner's prompt together. Check who asks the
question, who saves the answer, and who speaks after completion. Then inspect
a trace to confirm that each receiving prompt contains the facts it needs.

## Where to go next

<CardGroup cols={2}>
  <Card title="Reduce context sharing step by step" icon="scissors" href="/best-practices/context-scope">
    A practical walkthrough, one boundary at a time.
  </Card>

  <Card title="Making a task actually run" icon="route" href="/best-practices/step-scoping">
    Task structure and tool placement, so the step gets entered.
  </Card>

  <Card title="Variables" icon="braces" href="/build/variables">
    The YAML for declaring a value, a shape, and a list.
  </Card>

  <Card title="Checking what the agent did" icon="chart-line" href="/best-practices/verifying-behaviour">
    Reading a trace to see which saved value each prompt received.
  </Card>
</CardGroup>
