Skip to main content
This guide focuses on Coda. The same patterns work with the Mist model family. spell() works on both, with different grouping.
LLMs are trained and post-trained to produce grammatically correct prose for readers. Voice agents need something different: text that sounds natural when spoken. Without guidance, LLM output sent to a TTS model can sound like formal, stiff prose read aloud. That leaves the LLM with two jobs: write conversational speech, then format it so Rime’s normalizer reads it correctly. The drop-in system prompt at the end handles both.

Sound like a person

The agent is not trying to pass as human. Its voice should make callers comfortable enough to respond naturally, which usually leads to better outcomes. Real speech includes fillers, restarts, soft pauses, and occasional phrases like “yeah, no.” Coda doesn’t support SSML. Markup such as <break time="1s"/> isn’t interpreted, and the text normalizer turns it into words the voice reads aloud. Short expressive tags such as <giggle> do reach the model and can shape delivery, but only as best-effort cues: the effect may land elsewhere in the line or color the whole sentence. spell() is the only inline function with defined behavior, so the drop-in system prompt below leaves tags out. Rime deliberately keeps the interface small. Coda uses the meaning of the text to shape emotional delivery, while punctuation controls pacing and emphasis. Exclamation marks and interrobangs add excitement. Commas and ellipses add pauses.

Show, don’t tell

Instructions like “be conversational” are too vague. Give the model examples it can imitate instead. The right register depends on the call type, persona, and caller, so the examples below are not universal. They show the gap between default LLM prose and speech that usually sounds more natural. Even formal calls include occasional fillers and restarts. Use them lightly.

Put disfluencies in the text

Write “um,” “uh,” “so,” “yeah,” and “well” where someone would genuinely hesitate. Don’t rely on tags, and don’t stack fillers. Two “um”s in a row sounds like a bug.

Punctuation controls prosody

  • Comma. Short internal pause with a slight rise.
  • Period. Sentence end, falling pitch.
  • Question mark. Rising intonation.
  • Ellipsis. Hesitant or trailing pause. Use sparingly.
  • Semicolon. Somewhere between a comma and a period.
Keep spoken sentences under 25 words. Long sentences without internal commas sound breathless, so split them.

Describe personality through speech

Replace adjectives like “friendly” or “warm” with observable speech patterns the model can imitate. “Friendly” requires interpretation. “Starts sentences with ‘yeah’” gives the model a behavior. Keep the baseline calm and even. Save exclamation marks for situations that warrant them. A support agent does not need excitement in every reply.

Normalize cleanly

The Rime normalizer reads common formats natively: currency with symbols, full dates, clock times with minutes, phone numbers, percentages, and standard measurements. Pass these values through unchanged:
Expand only the patterns in Pre-normalization before synthesis. Text normalization contains the full reference. Send any tricky string to the /textnorm endpoint before release to confirm how Rime will read it.

Use spell() for IDs

If Rime must read an identifier one character at a time (confirmation codes, account numbers, SKUs, vanity phone letters), wrap it in spell(). On Coda in English, the normalizer spells letters straight through and reads longer digit runs in pairs. In other languages, and on Mist v3, spell() groups the characters in threes where possible and pairs where necessary. Both read symbols such as @ and -. Write the sequence without spaces, as in spell(ABC123XYZ). Each line below covers a different kind of identifier: a mixed code, a lowercase account number, the letters of a vanity number, and an email address.
Do not use spell() for standard phone numbers (digit grouping sounds more natural without it) or for real words that happen to be uppercase. Avoid dashes in numeric IDs because they cause unnatural pauses. Use spaces or spell() instead.

Drop-in system prompt

This system prompt combines the voice and normalization guidance above. Paste it into your LLM’s system message, then adapt it to the agent’s persona.
voice-system-prompt.md