Voice Relay
Voice relay lets you dictate into a Claude Code session instead of typing. It captures audio from your microphone, transcribes it locally using a Whisper model, and injects the resulting text into the attended pane of any workspace. All audio processing happens on your machine, so nothing leaves the local network except the transcribed text.
Voice relay works with every workspace type: local Zellij sessions, Podman containers, Compose environments, SSH remotes, and Kubernetes deployments. The same command, the same TUI, regardless of where the session runs.
Prerequisites
You need two things before voice relay can run: the whisper.cpp server binary and a Whisper model file.
Install whisper.cpp via Homebrew:
brew install whisper-cpp
This provides whisper-server, which cc-deck starts and manages automatically.
You do not need to run it yourself.
Then run the setup command to download a model and verify dependencies:
cc-deck ws voice --setup
Setup checks for whisper-server in your PATH, downloads the default model (base.en, about 141 MB), and reports whether everything is ready.
If you want a different model, pass --model during setup: cc-deck ws voice --setup --model small.en.
See Whisper Models for a comparison of available models.
|
Quick Start
The fastest path from zero to voice dictation takes three commands.
Create a workspace (if you do not already have one):
cc-deck ws new my-project --type local
In one terminal, attach to the workspace and start a Claude Code session:
cc-deck ws attach my-project
In a second terminal, start voice relay:
cc-deck ws voice my-project
The voice TUI opens with an audio level meter and a scrollable transcript. Start speaking and your words appear in the Claude Code input of the attended pane.
To submit the prompt, say "send" as a standalone word.
cc-deck recognizes this as a command word and sends a newline instead of the literal text.
To cycle to the next session needing attention, say "next" as a standalone word.
This triggers the same tiered attend logic as Alt+a.
Both command words can be configured in ~/.config/cc-deck/config.yaml.
Press q to quit the voice TUI and shut down the whisper server.
Voice Activity Detection
Voice relay uses VAD (voice activity detection) mode. The microphone listens continuously, and cc-deck detects when you start and stop speaking based on audio energy levels. Each utterance is automatically segmented, transcribed, and delivered.
The threshold setting controls how much ambient noise is tolerated before speech is detected.
Lower values make detection more sensitive (quieter speech is captured), while higher values require louder input.
Use the + and - keys in the TUI to adjust the threshold in real time.
Silence of 2.5 seconds ends an utterance and triggers transcription (configurable with --silence or defaults.voice.silence).
Utterances are capped at 30 seconds, which is the maximum window Whisper can process in a single pass.
Sidebar Integration
When voice relay is running, a ♫ indicator appears in the sidebar header.
-
Bright green ♫: Voice relay is connected and listening.
-
Dim ♫: Voice relay is connected but muted.
-
No ♫: Voice relay is not connected.
Mute Toggle
You can mute and unmute voice relay from multiple locations:
From the sidebar (any pane):
-
Alt+m: Toggle mute (configurable viavoice_keyin plugin config). -
min navigation mode: Toggle mute while navigating sessions. -
Click the ♫ indicator: Toggle mute with the mouse.
From the voice TUI:
-
m: Toggle mute.
Mute state synchronizes bidirectionally between the sidebar and voice TUI. When you mute from the sidebar, the TUI reflects the change within about one second. When you mute from the TUI, the sidebar updates immediately.
Whisper Models
cc-deck supports five Whisper models for dictation and recording.
The .en models are English-optimized; medium and large-v3-turbo also handle other languages.
| Model | Size | Speed | Accuracy | Notes |
|---|---|---|---|---|
|
74 MB |
Fastest |
Low |
Good for testing. Not recommended for real dictation. |
|
141 MB |
Fast |
Decent |
The default. Reasonable accuracy for clear speech in a quiet room. |
|
465 MB |
Moderate |
Good |
Best tradeoff on Apple Silicon. Noticeably better with technical terms. |
|
1.5 GB |
Slower |
High |
Multilingual support. Accurate, but higher latency per utterance. |
|
1.6 GB |
Like |
Highest |
Multilingual support. The most accurate model; a pruned large model that transcribes about as fast as |
Speech Filter
Whisper models sometimes turn non-speech audio into words. Keyboard clicks, breathing, or room noise can come out as "Thank you.", "Okay.", or "Bye.", and the relay would deliver those phantom words to the attended session. The large models are more prone to this than the small ones.
To prevent it, the relay runs a speech filter before transcription.
It uses the Silero voice activity model (ggml-silero-v6.2.0.bin, under 1 MB), which cc-deck ws voice --setup installs together with the Whisper model.
Audio without speech is skipped instead of transcribed, so it costs almost no time and produces no text.
The filter applies to dictation, to recordings, and to separating speakers by voice.
The filter is on by default.
If it is not installed yet, the voice TUI shows a reminder at startup.
To turn it off, set defaults.voice.speech_filter: false in ~/.config/cc-deck/config.yaml.
On an Apple Silicon Mac, small.en is the recommended upgrade from the default.
It runs comfortably in real time and handles code-related vocabulary (function names, library names, technical jargon) much better than base.en.
|
To switch models:
cc-deck ws voice --setup --model small.en
cc-deck ws voice my-project --model small.en
Models are cached at ~/.cache/cc-deck/models/ and only downloaded once.
The Voice TUI
When voice relay starts, it opens a terminal interface that shows the current state of the audio pipeline.
What You See
The header displays the target workspace name, the active audio device, the current mode (VAD or MUTED), and a real-time audio level meter. The level meter uses a braille-block visualization with a threshold indicator, so you can see at a glance whether your voice is loud enough to trigger detection.
The main area shows a scrollable transcript history. Each entry includes a timestamp, delivery status icon, and the transcribed text:
-
+(green): Text was delivered to the attended pane. -
!(red): Delivery failed. -
~(grey): Transcription is in progress.
The footer shows available keyboard shortcuts.
Keyboard Controls
| Key | Action |
|---|---|
|
Quit voice relay and stop the whisper server. |
|
Toggle mute/unmute. |
|
Increase or decrease VAD sensitivity by 2% per press. |
|
Open the audio device picker. |
|
Start recording, pause, or resume transcript recording. |
|
Stop transcript recording and close the file. |
|
Open the reading view (only while recording or paused). |
|
Choose how the next recording separates speakers: by pause or by voice (only when idle). |
|
Scroll through transcript history. |
Transcript Recording
Voice relay can record everything you say to a plain text file. Each transcribed utterance is written as a single line, with no timestamps or metadata.
To start recording, press r.
A filename prompt appears at the bottom of the TUI with a default name based on the current timestamp (for example, transcript-2026-05-04T15-04-05.txt).
Type a custom name or press Enter to accept the default.
Press Escape to cancel without starting a recording.
While recording, a red REC indicator appears in the header next to the mode display.
Every transcription is appended to the file as it arrives.
To pause recording, press r again.
The indicator changes to a yellow pause symbol.
Transcriptions continue to appear in the TUI history but are not written to the file.
Press r once more to resume recording.
To stop recording and close the file, press R (Shift+R).
The indicator disappears and the file is finalized.
Quitting the TUI with q also closes the file properly.
Relative filenames are stored in ~/.local/share/cc-deck/transcripts/.
Absolute paths are used as-is.
Recording While Muted
When the relay is muted and a recording is active, voice relay continues to transcribe speech and write it to the transcript file. The transcribed text is not sent to the attended pane. This lets you capture notes or commentary that you do not want delivered to the active session.
When no recording is active and the relay is muted, audio is discarded without transcription, preserving the existing mute behavior.
Reading View and Speaker Separation
While recording a transcript, press v to open the reading view.
The view shows the ongoing conversation as blocks, one block for each contribution in the call.
Each block shows the time the contribution started, followed by the spoken text.
The gutter bar alternates between two colors, so adjacent contributions are easy to tell apart.
The view follows new speech as it arrives.
Navigating the Reading View
Scroll with ↑/↓ or j/k (one line) and PgUp/PgDn (one page).
When you scroll up, auto-follow pauses and the footer shows how many new blocks have arrived below.
Press G or End to jump back to the bottom and resume following.
Press esc or v again to close the reading view and return to the normal TUI.
The header line keeps the audio level meter and the threshold (T:) visible.
Press + or - to adjust the threshold while you read, for example when quiet speakers are missing from the transcript.
During a pause in the conversation, the level bar should drop below the threshold marker; otherwise silence is never detected and passages only end at the maximum chunk length.
Separating Speakers
The relay decides in one of two ways where one speaker stops and the next one starts.
The header shows the current choice after Speakers:.
- By pause (the default)
-
A new block starts after a silence longer than the configured pause break, or where Whisper marks a speaker change with a leading dash. This mode works with every Whisper model and every language and needs no setup. A quick exchange without a pause stays in one block.
- By voice
-
A speech model listens for a change of voice and starts a new block at each change, even without a pause. This mode uses the tinydiarize model through
whisper-cliand recognizes English only. The recording is transcribed with that model instead of your configured one, while dictation keeps using your configured model.
Press s in the idle TUI to switch between the two modes.
The choice applies to the next recording, and the status line briefly confirms it.
While a recording runs, s has no effect, so choose the mode before you press r.
Installing the Voice Model
Separating speakers by voice needs the tinydiarize model (small.en-tdrz, 488 MB).
When you press s and the model is missing, the TUI asks whether to download it and shows the progress in the footer.
Dictation and recording keep working during the download, and quitting the relay with q cancels it.
To install the model ahead of time, use the setup command:
cc-deck ws voice --setup --model small.en-tdrz
Tuning Recording Sensitivity
Recording passages arrive faster than dictation utterances because the recording VAD uses a shorter silence window (1 second by default, compared to 2.5 seconds for dictation). This means the reading view updates more frequently during recording.
For quiet remote voices or noisy environments, adjust the recording-specific VAD parameters in the config file:
defaults:
voice:
recording:
threshold: 20
silence: 0.8
max_chunk: 10.0
pause_break: 1.5
Lower threshold values capture softer speech.
Shorter silence values produce faster updates but may split mid-sentence pauses into separate passages.
The pause_break value (2 seconds by default) sets how many seconds of real silence between two passages start a new block.
The relay measures this silence from the last loud audio of one passage to the first loud audio of the next, so the --pre-roll setting does not affect it.
See Configuration Reference for the full list of recording parameters and their ranges.
Speaker Breaks in the Transcript File
The transcript file separates contributions with a single blank line. Each segment is written on its own line, and a blank line appears before each segment that starts a new contribution. The first line of a recording never has a blank line in front of it. Both modes write the file the same way.
Troubleshooting Speaker Separation
- whisper-cli not found
-
Separating speakers by voice requires
whisper-cli, which is part of thewhisper-cpppackage. Install it withbrew install whisper-cpp. Without it, pressingsshows an error and the relay keeps separating speakers by pause. - Voice model download failed
-
Network errors during the download appear in the TUI footer. Press
sagain to retry, or install the model withcc-deck ws voice --setup --model small.en-tdrz. - Pause-based fallback during a recording
-
If the voice model fails on a passage or needs longer than 30 seconds for it, the relay transcribes that passage with your configured model and separates speakers by pause for it. The footer shows the reason, and the recording continues. Run the relay with
--verboseto see the details in~/.local/state/cc-deck/voice.log. - No new block while one person talks
-
The voice model reacts to a change of speaker, not to pauses. A long monologue therefore stays in one block, except where a silence exceeds the pause break.
Configuration
Config File
The VAD threshold can be set in ~/.config/cc-deck/config.yaml so you do not have to pass --threshold every time:
defaults:
voice:
threshold: 45
The threshold uses a logarithmic scale from 0 to 100. A value around 30 to 50 works well for most quiet indoor environments.
CLI Flags
All voice settings can be overridden per invocation:
| Flag | Default | Description |
|---|---|---|
|
|
Whisper model name. |
|
|
Port for the local whisper-server. |
|
(from config) |
VAD sensitivity (0-100, logarithmic). Overrides the config file value. |
|
|
Write detailed diagnostic logs to |
Command Words
Voice relay recognizes two default command words:
| Word | Action | Description |
|---|---|---|
|
|
Submits the current prompt (sends a newline to the attended pane) |
|
|
Cycles to the next session needing attention (same as |
A command word only fires when the entire utterance, after stripping filler words, equals the trigger word. Saying "the next step is to refactor" is treated as normal dictation because "next" is not standalone.
You can configure additional trigger words or define new actions in the config file:
defaults:
voice:
commands:
submit:
- send
- done
- enter
attend:
- next
- switch
Each key under commands is an action name, and the list contains trigger words for that action.
When you configure an action, your word list replaces the default words for that action.
Actions you do not configure keep their defaults.
Filler words (um, uh, hmm) are stripped before matching, so "um, send" still triggers the command.
Troubleshooting
- whisper-server not found
-
Install whisper.cpp:
brew install whisper-cpp. Then runcc-deck ws voice --setupto verify the installation. - Timed out waiting for whisper-server
-
The server takes a few seconds to load the model into memory. Larger models (especially
mediumat 1.5 GB andlarge-v3-turboat 1.6 GB) need more time. If this persists, check whether another process is using port 8234 and try a different port with--port. - Phantom words such as "Thank you." appear without anyone speaking
-
Run
cc-deck ws voice --setupto install the speech filter, and check thatdefaults.voice.speech_filteris not set tofalse. With--verbose, the log showsspeech filter: onat startup when the filter is active. - Transcription misses quiet speech
-
Lower the VAD threshold with the
-key in the TUI, or set a lower value in the config file. A threshold of 20 to 30 captures softer speech at the cost of picking up more background noise. - Filler words appear in output
-
cc-deck strips common fillers (um, uh, hmm, ah, er) automatically. If you see them, the issue may be that the filler was part of a longer phrase rather than standalone.
- Text does not appear in Claude Code
-
Verify that the workspace has an active Zellij session and that a pane is attended. Check the transcript history in the TUI for delivery errors (the
!indicator).
Next Steps
-
The Sidebar for understanding session states and the attended pane
-
Smart Attend for how cc-deck picks which pane receives voice input
-
Configuration for custom keybindings and layout variants
-
CLI Reference for the complete
ws voiceflag reference