Skip to main content
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 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. 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:
agent.yml

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, and 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.

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:
agent.yml
fillers.enabled is on for voice and off for text unless you set it. Setting it explicitly applies to both channels. See 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:
skills/view_transactions/skill.md
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 with a memory placeholder rather than leaving it to the model. 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 and inspect its baggage-report responses. 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 on any tool that changes something, and make the confirmation question restate the facts the customer is agreeing to:
skills/card_replace/responses.yml
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. The community guide How to handle misheard 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.

Plan for interruptions

On a call, the customer can talk over the agent. With 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. 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.

End the call cleanly

When the conversation is over, say goodbye once and stop. A rule in agent.yml covers the model’s side:
agent.yml
To hang up from a skill, end an ordered block with an authored goodbye followed by action: hangup:
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.

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.

Next steps

Build a voice agent

Apply these patterns to a card replacement skill, step by step.

Test and monitor voice

Listen in the Inspector, then watch latency and interruptions in production.