Teardown: a voice agent system prompt, line by line
A reader sent us the prompt behind their phone-line support bot. It was written like a chat prompt: emoji in the sign-off, markdown in the format rules, a wall of dos and don'ts. On a voice channel, most of that is not style. It's a bug the caller can hear.
TL;DR A voice-agent prompt written for a screen ships defects you can hear: decoration a text-to-speech engine has to pronounce (structure/special-character), two length rules that can't both hold on one turn (logic/numeric), and a hedged escalation the model may skip (prompt/hedging). Set the channel, write the rules for the ear, and let the checker catch the rest before a caller does.
The prompt is anonymized but structurally untouched: a persona line, a format section, an authority paragraph, and an escalation rule bolted on after an incident. It is a perfectly ordinary prompt, and it would read fine in a chat window. That is the problem. A phone line has no screen, no scrollback, and a text-to-speech engine that will earnestly try to say every character you leave in. So we ran it through the checker with the channel set to voice, and the defects that a chat prompt gets away with turned into errors. Here are the three that mattered.
§1The decoration the phone tries to speak
The original signs off warm and reads balances back with a little flourish. On a screen, harmless. Down a phone line, the model mirrors the marks into its output and the TTS engine has to pronounce them, so the caller hears a stray "star" before every dollar figure and an emoji name at the end of the call.
# Role You are Ivy, a voice agent for a wireless carrier's phone line. # Constraints - ALWAYS end the call on a warm note 😊. - Read account balances back with a ★ before the amount.
original.tg:5:38 error structure/special-character Emoji is outside the language: the instruction plane is checkable English, and models mirror prompt decoration into output. Remove it, or demonstrate it inside <examples>. original.tg:6:37 error structure/special-character Decorative or symbolic Unicode is outside the language: every mark here has an English or ASCII form the checker reads. Use plain text; illustrations belong in <examples>. ✗ 1 file - 2 error, 0 warning, 0 info
§2Two lengths, one turn
The format section had picked up two rules on different days. One capped replies for the ear: nobody holds five sentences of menu options in their head. The other, added after a compliance note, asked the agent to read the full order summary back. Each is reasonable. Together they ask a single spoken turn to be at most one sentence and at least four, which is no turn at all.
# Role You are a voice agent for a wireless carrier. # Constraints - MUST keep every reply to at most 1 sentence. - MUST read the full order summary back in at least 4 sentences.
original.tg:5:1 error logic/numeric Numeric conflict - "at most 1 sentence" and "at least 4 sentences" can't both hold. (conflicts with line 5) original.tg:6:1 error logic/numeric Numeric conflict - "at most 1 sentence" and "at least 4 sentences" can't both hold. (conflicts with line 4) ✗ 1 file - 2 error, 0 warning, 0 info
The fix is a decision, not a bigger number: scope the two rules so they never fire on the same turn. A routine reply stays at one sentence; the summary read-back gets its own bound behind a WHEN. Both intentions survive; no single turn has to be two lengths at once.
§3The escalation that only tries
The most important rule in a phone bot is the one that gets a human on the line, and this one was written to fail softly. An upset caller does not want the agent to try to offer a person. The hedge turns the single instruction you most need honored into one the model is free to skip.
# Role You are a voice agent for a wireless carrier. # Constraints - WHEN the caller raises their voice THEN you MUST try to offer a human agent.
original.tg:5:52 info prompt/hedging Hedging - "try to" turns this instruction into a suggestion the model may skip. Delete the hedge, or commit to a modal (MUST / NEVER / SHOULD). ✓ 1 file - 0 error, 0 warning, 1 info
§4The rebuild
Same policy, rewritten for the channel and the compiler. The channel is declared once with $CONFIG modality voice. Voice describes tone only. Format is written for the ear. Authority is bounded. The escalation rule is scoped, un-hedged, and pinned with a $TEST so the next edit can't quietly weaken it.
<$CONFIG> $CONFIG modality voice </$CONFIG> # Voice @@ voice: personality is how Ivy sounds, never what Ivy may do Ivy IS calm, plain-spoken, and brief. # Format @@ spoken_money: a caller hears "nineteen dollars", never "$19" - MUST speak monetary amounts as words, not digits. @@ no_decoration: a screen reads emoji; a phone line cannot speak it - NEVER use emoji or markdown in a spoken reply. # Authority @@ fee_cap: a bounded waiver keeps refunds off the model's discretion - Ivy MAY waive a late fee up to $25. @@ above_cap: anything larger is a human decision - Above that, Ivy MUST escalate to a human agent. # Escalation @@ human_ask: a caller asking for a person gets one, every time - WHEN the caller asks for a human THEN Ivy MUST transfer to a live agent. $TEST upset_caller - input:: I am done with this, get me a person right now. - expect:: - transfers to a live agent - does not quote a specific late fee
Nothing here is voice-specific magic. It is the same discipline any agent prompt wants, applied to a channel that punishes sloppiness out loud. A chat window forgives a stray glyph and a rule that sometimes runs long. A phone line reads your mistakes to the customer in a pleasant voice, one call at a time.
This is the voice-channel companion to our first line-by-line teardown of a chat support prompt, where the failures were contradictions rather than decoration. The buried-rule problem - a safety instruction the model half-honors because of where it sits - is its own subject in the field guide to instruction placement. Want your prompt torn down (anonymously) in a future entry? Open an issue on GitHub with the tag teardown.
FAQCommon questions
- Why does my voice agent read out symbols, emoji, or markdown?
- Because they are in the prompt. A model mirrors the decoration it sees, and a text-to-speech engine then has to pronounce it, so a smiley or a star or a markdown bullet turns into noise on the call. A voice prompt should be plain words only. TypeGlish blocks a non-ASCII mark in the instruction plane with
structure/special-character, which catches the emoji and the star before they ever reach the caller. - How is a voice agent system prompt different from a chat agent prompt?
- The channel changes what a rule can even mean. There is no screen, so formatting rules become speech rules: numbers are spoken as words, there are no bullets or links, and there is no scrolling back to reread. Replies have to be short enough to hold in the ear but complete enough to confirm, which is exactly where length rules start to fight. Set the channel with
$CONFIG modality voiceand write the format rules for the ear, not the eye. - Why does my voice bot give different-length answers to the same question?
- Usually two length rules that cannot both hold. If one rule caps replies at one sentence and another asks the agent to read a full summary back in at least four, no reply satisfies both, so the model picks one per call and the length looks random. TypeGlish reads the numbers as inequalities and proves the conflict at compile time with
logic/numeric. Fix it by scoping the two rules so they never apply to the same turn. - What should a voice agent system prompt include?
- A voice section for tone, a format section written for speech (spoken numbers, no decoration), a bounded authority section that says what the agent may resolve and when it must hand off, and a scoped escalation rule with no hedging. Pin the escalation path with a
$TESTso a later edit cannot quietly delete it. Keep every rule measurable, and runnpx typeglish checkso the defects that hide in prose become compile errors.