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

# Designing for voice

> Write skills, responses, and agent settings that work well when the customer is listening rather than reading.

A skill you write once runs on chat and on voice. Mantle already adapts the
basics for a call: it tells the model to speak in short sentences with no
formatting, says numbers and dates as words, and fills pauses while tools run.
See [Voice agents](https://rasa.com/docs/mantle/voice/overview.md) for everything it does by default.

What it cannot do is redesign the conversation for someone who is listening.
A caller cannot scroll back, skim a list, or tap a button, and they hear every
pause. This page covers the changes worth making for that.

## Keep skill instructions channel-neutral

Write the skill body once, for both channels. Put channel style in
`agent.yml` instead, under `orchestrator.voice_rules` and `orchestrator.text_rules`.
Mantle renders the matching set on every turn, based on the channel the
conversation arrived on.

When an instruction only matters on a call, phrase it so it holds on chat too.
"Mention the three most recent transactions, then offer to read more" works in
both places, and reads better in chat than a long table would.

## Tune the voice rules carefully

With no `voice_rules` set, Mantle uses built-in rules: speak naturally, use short
sentences, ask one question per turn, use no formatting, and say dates, amounts,
URLs, and email addresses in spoken form. The full text is on
[Prompt templates](https://rasa.com/docs/mantle/reference/prompt-templates.md).

Setting `voice_rules` **replaces** those built-in rules rather than adding to
them. If you override them to add a rule of your own, copy the parts of the
default you want to keep:

```yaml agent.yml theme={null}
orchestrator:
  voice_rules: |
    You are on a voice call. Keep every response to four sentences or fewer.
    Do not use lists, markdown, or any structured layout.
    When presenting several items, describe each one in a natural sentence.
    Ask one question at a time, then wait for the answer.
    Say dates, times, numbers, and amounts the way a person would say them
    aloud, for example "forty-two dollars and fifty cents".
```

## Speak first when the caller expects it

The bundled `default_session_start` skill does not greet, so the agent waits
for the customer to speak. That suits chat, but in a voice conversation the caller
usually expects to hear the agent first. Voice channels send `/session_start`
when a call connects, so replace the bundled skill with one that greets. The
example is on [Getting Started](https://rasa.com/docs/mantle/getting-started.md#8-make-it-sound-right-on-a-call-optional),
and [Start a conversation](https://rasa.com/docs/mantle/orchestration/runtime-loop.md#start-a-conversation) covers the
mechanics.

A recording or compliance notice belongs here too. Deliver it from the greeting
skill, or from an `utter:` trigger with `on: activate` on the skill that needs
it. See [Responses](https://rasa.com/docs/mantle/concepts/responses.md#delivering-a-response).

## Shape the acknowledgements

On voice, Mantle has the model say a short acknowledgement before it calls a
tool, so the caller hears something while the tool runs. The built-in
instruction asks for one that stays true whatever the tool returns, without
promising a result the tool may not deliver. Give it examples in your agent's tone of
voice, worded the same way:

```yaml agent.yml theme={null}
fillers:
  examples:
    - user: I lost my card
      ack: Oh no, let me take a look.
    - user: It was stolen actually
      ack: I'm sorry to hear that. Let me see what I can do.
```

`fillers.enabled` is on for voice and off for text unless you set it. Setting it
explicitly applies to both channels. See [`fillers`](https://rasa.com/docs/mantle/reference/agent-yml#fillers).

## Read lists in small pieces

A caller holds two or three items in mind, not ten. When a tool returns many
rows (accounts, transactions, orders), tell the model how much to read at once:

```markdown skills/view_transactions/skill.md theme={null}
Present the most recent three transactions, each as one short sentence with
the date, merchant, and amount. Then ask if they want to hear more.
```

Write choices the same way. Offer two or three options by name, and let the
customer answer in their own words.

## Use exact wording for numbers that must be right

A model can paraphrase or round a value it reads from a tool result. When the
caller has to hear an exact order number, reference, or serial number, deliver
it in a [response](https://rasa.com/docs/mantle/concepts/responses.md) with a memory placeholder rather than
leaving it to the model. [Use a response when the words have to be exact](https://rasa.com/docs/mantle/best-practices/when-prose-is-not-enough.md#use-a-response-when-the-words-have-to-be-exact)
shows the pattern.

Speech providers differ in how they read long digit strings. Listen to your
identifiers in the Inspector. If one is read as a single large number, have the
tool store a spoken form in memory (for example, digits separated by spaces) and
use that in the response.

For a worked community example, follow
[Verbatim responses for voice](https://rasa.community/library/tutorials/voice-ai-agent/06-verbatim-responses/)
and inspect its [baggage-report responses](https://github.com/RasaHQ/rasa-community-resources/blob/4aa0c4419dc193fef7a969c12d59edcf720f2606/tutorials/rasa-voice-agent-tutorial/tutorial/snippets/step-05-baggage/skills/report_baggage/responses.yml).
That travel-agent example shows authored wording with memory placeholders;
check the tutorial's tested version before reusing its files.

## Confirm before anything irreversible

On chat, a customer can reread the order before they agree to it. On voice, they
only hear it once. Put [`requires_confirmation`](https://rasa.com/docs/mantle/build-guide/tool-constraints#explicit-confirmations)
on any tool that changes something, and make the confirmation question restate
the facts the customer is agreeing to:

```yaml skills/card_replace/responses.yml theme={null}
responses:
  utter_ask_replacement_confirmation:
    - text: >-
        I'll order a replacement for your {session.card_replace.selected_card_label},
        shipped {session.card_replace.shipping_type}. Shall I go ahead?
```

The engine speaks the question exactly as written and ends the turn. On the
caller's next turn, the model interprets their reply, and the engine runs the
tool only if it reads it as a yes. Leave `rephrase` off on the question:
rewording adds a model call before the caller hears anything, and a reply to the
previous sentence can interrupt the question before it plays. A placeholder with
no value is read out as written, so add every field the question uses to the
tool's `requires:`. Do not also ask in the skill prose, or the customer confirms
twice.

## Recover when recognition gets a value wrong

Treat a transcript as what the recognizer heard, not proof that an account,
name, or reference exists. Have lookup tools validate it against your system.
If the lookup fails, ask for the value again or offer a choice from records the
caller is authorized to access. After repeated failures, provide your project's
handoff or alternate-channel path.

Read back the resolved record and important values before a change. A spoken
confirmation helps the caller correct them; it does not authenticate the caller
or guarantee that speech recognition was right. Keep authorization and data
validation in the tools as well as the
[confirmation constraint](https://rasa.com/docs/mantle/build-guide/tool-constraints.md#explicit-confirmations).

The community guide
[How to handle misheard names](https://rasa.community/library/guides/seven-entry-vocabulary-voice-agent-names/)
shows how to test names separately from amounts and dates. Its vocabulary example
uses a community Speechmatics adapter, not a built-in Mantle setting. Check the
recognizer's supported options before applying a similar technique.

## Collect digits from the keypad

Some values are easier, or safer, to enter on the phone keypad than to say
aloud: account numbers, PINs, and menu choices. A `collect:` step can accept
keypad (DTMF) input. See [DTMF collect steps](https://rasa.com/docs/mantle/reference/ordered-block-steps.md#dtmf).

## Plan for interruptions

On a call, the customer can talk over the agent. With
[interruptions](https://rasa.com/docs/mantle/reference/integrations-yml.md#interruptions) enabled on the
channel (the Inspector enables them by default), Mantle stops playback and ends
the turn when it accepts an interruption, including any tool that is still
running. Short speech that the backchannel classifier scores as an acknowledgement
does not interrupt; see
[How backchannels are classified](https://rasa.com/docs/mantle/reference/integrations-yml.md#how-backchannels-are-classified).

For tools that change something, check `context.is_cancelled` before starting
the irreversible step. Cancellation does not roll back a request already
accepted by another service. A cancelled tool may run again, so use that
service's idempotency mechanism and check the outcome of an uncertain request
before retrying. See [Cancellation](https://rasa.com/docs/mantle/reference/tools.md#cancellation).

## End the call cleanly

When the conversation is over, say goodbye once and stop. A rule in
`agent.yml` covers the model's side:

```yaml agent.yml theme={null}
rules:
  - >
    When the customer says they are done, give exactly one brief goodbye and
    stop. Do not ask another question after that.
```

To hang up from a skill, end an ordered block with an authored goodbye followed
by `action: hangup`:

```yaml theme={null}
- id: goodbye
  action: utter_goodbye
- id: hang_up
  action: hangup
  next: END
```

When the customer goes quiet, the bundled silence-timeout skill checks in three
times, then says goodbye and hangs up. You can reword those messages; see
[Silence timeout](https://rasa.com/docs/mantle/reference/default-skills.md#silence-timeout).

## Use caller details from the channel

Telephony channels can pass facts about the call, such as the caller's phone
number, when the conversation starts. To make one available to every skill,
declare a project memory field with `seed: true`. See
[Seeding from session start](https://rasa.com/docs/mantle/reference/memory-yml.md#seeding-from-session-start).

## Next steps

> **[Build a voice agent](https://rasa.com/docs/mantle/voice/tutorial.md)**
>
> Apply these patterns to a card replacement skill, step by step.

> **[Test and monitor voice](https://rasa.com/docs/mantle/voice/testing.md)**
>
> Listen in the Inspector, then watch latency and interruptions in production.


## Related topics

- [Voice agents](https://rasa.com/docs/mantle/voice/overview.md)
- [Test and monitor voice](https://rasa.com/docs/mantle/voice/testing.md)
- [Build a voice agent](https://rasa.com/docs/mantle/voice/tutorial.md)
- [Writing prose](https://rasa.com/docs/mantle/best-practices/writing-prose.md)
- [Designing the Logic Behind Conversations](https://rasa.com/docs/learn/concepts/dialogue-management.md)


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.