Voice coding means speaking the instructions you'd normally type to an AI coding agent: the bug report, the refactor plan, the constraints. The agent then writes the code. Claude Code has this built in with /voice. Cursor, Copilot, and most terminals don't, so developers bolt on a dictation layer. Which one you need depends on where you work and how many proper nouns you say.
Here's the short version. Claude Code's /voice is a good default if you live in the Claude Code CLI or its VS Code extension. An API-based dictation layer earns its keep when you move between tools, need your own dictionary, or want the output shaped differently for the terminal than for a commit message.
This post covers both: what the built-in does, what breaks when generic speech-to-text meets a terminal, and how to build the version that holds up.
Why prompts are the ideal dictation workload
A prompt to a coding agent is long, structured, and disposable. You write 200 words describing what you want, the agent does something with it, and nobody reads that paragraph again. Compare it to the code itself: short, dense, precise, and permanent.
Dictation wins where text is verbose and thrown away. That's the whole reason this niche appeared. The highest-value thing to speak in a developer's day isn't code. It's the paragraph of intent that sits above the code.
There's a second-order effect too. Because you're talking rather than typing, you say more. Constraints you'd have skipped ("don't touch the migration files," "the flaky test in the auth suite is known, ignore it") make it into the prompt, and the agent's first attempt lands closer.
Our research team frames the shift as moving from speech as dictation to speech as executable command input. The text isn't the deliverable. The action is.
Claude Code's built-in /voice vs. an API you control
Claude Code ships voice dictation as a slash command. Run /voice, hold Space (or tap to toggle), and your speech is transcribed live into the prompt. It's tuned for coding vocabulary. It recognizes terms like regex, OAuth, and localhost, and adds your project name and git branch as recognition hints automatically. It supports 20 dictation languages, and transcription doesn't count against your Claude usage.
That's a lot of value for zero setup. Here's where the two approaches differ.
| Claude Code /voice (built in) | API-based dictation layer (e.g. AssemblyAI Dictation API) | |
|---|---|---|
| Where it works | Claude Code CLI and its VS Code extension | Any app with a text field: Cursor, Copilot CLI, terminals, commit messages, Slack |
| Sign-in required | A Claude.ai account; not available when Claude Code uses an API key, Bedrock, or other third-party providers | Your own API key |
| Remote and cloud sessions | Not available over SSH, in cloud sessions, or in VS Code Remote | Capture runs locally and the text goes wherever your cursor is |
| Vocabulary | Coding terms built in; project name and branch added automatically | Your own list: up to 100 keyterms plus a context prompt per request |
| Languages | 20, chosen with the language setting | 19, with mid-sentence code-switching |
| Output shaping | Verbatim transcript into the prompt | Cleanup by default; an instruction per request reshapes it (terse imperative, commit message, PR description) |
| Cost | Included; doesn't consume Claude messages | $0.62/hr of audio, all in |
Neither column is "better". They answer different questions. If you're one developer in Claude Code all day, start with /voice. If you're building a developer tool, or your team works across three editors, read on.
What breaks when you point generic speech-to-text at a terminal
Whichever route you take, these are the four failures to design around. Every one of them shows up in the first ten minutes with a generic transcription model.
Identifiers become English
bolt.module.paportal comes back as "bolt module pa portal." axios becomes "axe eos." A general transcription model is doing exactly what it was built to do: writing down the most probable sequence of English words. Package names, version strings, issue IDs, and internal service names are, statistically, not English words.
It's an entity accuracy problem rather than a word accuracy problem, and it's the one that makes people quit. Aggregate accuracy looks fine while every proper noun in the prompt is wrong. Automatic hints help with the project you have open. They don't know your company's twelve internal service names.
Syntax becomes prose
"if colon newline indent a equals 42" dictated verbatim is not working code. Speech has no indentation, no brackets, and no way to signal that you've moved from describing something to specifying it. That's why voice coding works for prompts and struggles for code.
Filler survives
Coding agents follow instructions literally. That's the point of them. It's also why a raw transcript is a hazard: a false start becomes an instruction.
Say "let's use Postgres, no, wait, use SQLite" into a verbatim transcriber and the agent receives both. Add the ums, the restarts, and the half-sentence you abandoned, and you've handed a literal-minded system a document that contradicts itself.
No context
The same words mean different things depending on where they land. "Fix the failing test in the user service" is a command in a terminal, a description of finished work in a commit message, and a request to a teammate in Slack. An endpoint that sees only the audio can't pick between them.
Dictate a messy sentence full of package names and read the verbatim transcript before anything tidies it.
Why build on an API instead of the built-in
Five situations push teams past a built-in dictation command:
- You work in more than one agent. Cursor, Copilot CLI, Claude Code, and the terminal all accept typed text. A system-wide hotkey that types into whatever has focus works in all of them.
- Your vocabulary is bigger than your repo name. Internal services, customer names, and ticket prefixes need an explicit list. With an API, you pass that list on every request and extend it per project.
- Different destinations need different output. A terminal wants a terse imperative. A commit message wants a subject line and a body. One API call with a per-destination instruction handles both.
- Your auth setup rules out the built-in. Teams running Claude Code on an API key, Bedrock, or another cloud provider don't get /voice.
- You're shipping voice in your own developer tool. If you're building the IDE, CLI, or agent, you need a dictation API, not someone else's slash command.
Here's what that looks like with the Dictation API. One request returns the verbatim transcript and the shaped output side by side:
import assemblyai as aai
aai.settings.api_key = "YOUR_API_KEY"
config = aai.DictationConfig(
stt_prompt="A software engineer dictating a task for a coding agent. "
"Expect package names, file paths, and issue IDs.",
keyterms_prompt=["bolt.module.paportal", "axios", "PaymentsService", "JIRA-4821"],
llm_instruction="Rewrite as a terse imperative instruction for a coding agent. "
"Resolve self-corrections. Keep identifiers exactly as spelled.",
)
result = aai.DictationTranscriber().transcribe_live("clip.wav", config)
print(result.text) # verbatim, for a "show original" toggle
print(result.llm_response) # what gets typed into the terminalThe text field is always the words as spoken. llm_response is the shaped version, or None if the rewrite failed, in which case you fall back to the transcript. Cleanup runs by default even without an instruction. The Python SDK wraps it; from any other language it's a single multipart POST.
Prefer to own the cleanup prompt yourself? Call the Sync API for the transcript and run your own rewrite through LLM Gateway. It's two hops instead of one, and you control every rule.
What it takes to build the version that works
Each failure above has a fix, and they sit at different layers. Getting the order right matters more than any single parameter. The full feature set a shipping dictation feature carries runs wider than these four.
Get the identifiers right before cleanup
This comes first because nothing downstream can repair it. A word that was never heard can't be recovered by post-processing.
Two controls do the work, and they do different jobs. A context prompt describes the setting and what the model should expect to hear. Keyterms carry the specific terms you know will appear: library names, service names, internal acronyms. If you're building dictation into a developer tool, you know that list at build time and can extend it per project. The keyterm prompting docs cover the limits.
One tradeoff that isn't obvious: an explicit language selection is ignored when a custom prompt is set. For an English-speaking team that costs nothing. If your users dictate in other languages, state the language in the prompt itself, and make that choice deliberately rather than discover it in a bug report.
Underneath it all, the model matters more than the parameters. Sync and Dictation run on Universal-3.5 Pro, our pre-recorded flagship, not a smaller variant tuned for latency. That's the difference between a package name landing and a package name becoming two English words.
Shape the output for where it lands
Cleanup handles filler and false starts. An instruction handles everything past that, per request, so the same hotkey behaves differently depending on where the text is going.
Keep the verbatim transcript alongside the rewrite, so your product never has to guess which one it's holding. A "show original" toggle then becomes a display decision rather than a second API call.
The boundary is worth stating plainly. The rewrite polishes; it does not correct. Hand it "axe eos" and you get "Axe EOS," confidently capitalized and still wrong. That fix belongs upstream, in the prompt and the keyterms. Our look inside dictation cleanup explains why.
Feed it context
This is the highest-impact and least obvious part of the build, and almost nobody does it.
Send what's around the cursor. Send the selection. Send what app or field the user is dictating into. Our own dictation experiments got materially better once surrounding text became part of the request. The model didn't get smarter. "The failing test" just stopped being ambiguous once the request carried the file the user was looking at.
Make the hotkey feel instant
Dictation is a UI-blocking interaction. The user has stopped talking and is looking at the cursor.
Three things carry most of the weight. Push-to-talk, so the user sets the clip boundaries rather than a silence detector; the push-to-talk dictation tutorial covers capture and encoding. Connection pre-warming on key-down, so the TLS handshake runs while the user is still speaking. And fewer sequential inference calls, because a transcript hop and a rewrite hop compound. That's the main latency argument for a single Dictation API call: 134 ms p50 for transcription, with cleanup in the same round trip.
One reliability argument shows up on laptops: a single request survives a network change. Close the lid, walk to a meeting, reopen on cellular, and hold the hotkey. A WebSocket held open across that handoff is dead. A POST goes out over whatever interface exists now.
Steer recognition with a prompt and keyterms, and see identifiers land before any rewrite runs.
Try it without writing code: Blurt
Blurt is a free, open-source (MIT) Mac dictation app built on the Dictation API. Hold a key, talk, and finished text lands in whatever app has focus, including Claude Code, Cursor, or your terminal. You bring your own AssemblyAI API key and pay for the audio you transcribe, about $0.62 per hour.
It's a reference build, not a product pitch. Read the source to see how capture, pre-warming, and instructions fit together, then lift what you need. If you're choosing between desktop dictation apps for yourself, our MacWhisper vs Superwhisper vs Blurt comparison covers the tradeoffs. General-purpose apps like Wispr Flow and Superwhisper take the same system-wide hotkey approach.
Where this goes
The version of this that gets interesting isn't dictation into an agent. It's dictation as command input, where "run the tests and fix whatever breaks" is a spoken instruction the agent executes, not a string it writes down.
That's a much shorter utterance doing much more work, and it puts the whole burden on the layer between the microphone and the agent. Get the identifiers wrong and the agent edits the wrong file. Leave the false start in and it does two contradictory things. Drop the context and it asks which test you meant.
Built-in voice commands will keep getting better at the first two. The third, context about your codebase, your team's names, and where the text is going, is the part you'll own either way. If you're building voice into an agent of your own, the same principles apply; see how we approached building a voice agent with a coding agent.
Finished, identifier-accurate text in one call, ready to type into any agent.
Frequently asked questions
Does Claude Code accept voice input?
Yes. Claude Code has a built-in /voice command that transcribes your speech live into the prompt, using hold-to-record or tap-to-record. It requires a Claude.ai account sign-in and a local microphone. It isn't available when Claude Code runs on an API key or third-party provider, or in SSH and cloud sessions.
How do you enable voice mode in Claude Code?
Run /voice in a Claude Code session, then hold Space while you speak. Run /voice tap to toggle recording with a single tap instead. Set your dictation language with the language setting in /config. Dictation defaults to English.
Is Claude Code /voice accurate enough for package and identifier names?
It handles common coding terms and adds your project name and git branch as hints automatically. It doesn't let you supply your own dictionary of internal service names, customer names, or ticket prefixes. Teams that need that use a dictation API with explicit keyterms.
Why is voice input not working in VS Code, on Mac, or under WSL?
Most failures are permissions or audio routing, not the model. On macOS, grant microphone access to your terminal app and restart it. Under WSL, use WSLg and install SoX with its PulseAudio backend (sox libsox-fmt-pulse). In VS Code, voice doesn't work in Remote sessions, because the microphone is on your local machine.
What's the best speech-to-text setup for dictating prompts to an AI coding agent?
Use push-to-talk capture, a transcription prompt plus keyterms for your package and service names, an instruction that shapes output for its destination, and surrounding editor text as context. If you only use Claude Code, start with /voice. Across multiple tools, a system-wide hotkey calling a dictation API covers all of them.
How do I stop dictated prompts from mangling package and identifier names?
Bias the transcription itself, before any cleanup runs. Pass a prompt describing the setting and your known identifiers as keyterms. Post-processing can't recover a term that was never heard, so adding library names to a rewrite instruction does nothing for this.