Voice input for AI coding agents on Linux. Speak into your microphone and your words get transcribed locally (via Whisper) and sent as prompts to your agent of choice.
All processing happens on your machine — no audio data leaves your computer.
Works standalone with tmux/Zellij, or as part of the LINCE multi-agent dashboard for voice-controlled orchestration of multiple agents.
You speak → Microphone → Whisper (local, GPU) → Text → tmux/Zellij → Claude Code
VoxCode runs in a terminal multiplexer pane (tmux or Zellij) next to Claude Code. You speak, VoxCode transcribes your words into a text buffer. When you say "comando: invia" (or press Enter), the text is sent to Claude Code as if you typed it.
Before installing VoxCode, make sure you have:
- Linux (tested on Fedora 43, should work on Ubuntu/Debian)
- A working microphone (built-in laptop mic is fine)
- NVIDIA GPU with proprietary drivers (recommended) or CPU-only (much slower)
- Claude Code installed and working
# Check NVIDIA GPU and drivers (skip if using CPU-only)
nvidia-smi
# You should see your GPU model and driver version
# Check microphone (should list at least one input device)
arecord -l
# Or: pactl list sources short
# Check Claude Code is installed
claude --version# Claude Code requires Node.js 18+
# Install Node.js first if needed:
# Fedora: sudo dnf install nodejs
# Ubuntu: sudo apt install nodejs npm
npm install -g @anthropic-ai/claude-codeFedora / RHEL / Rocky:
sudo dnf install tmux pipewire pipewire-pulseaudio portaudio-devel # or: zellij instead of tmuxUbuntu / Debian:
sudo apt install tmux libportaudio2 pipewire pipewire-pulse # or: zellij instead of tmuxcurl -LsSf https://astral.sh/uv/install.sh | shClose and reopen your terminal after installing uv, or run source ~/.bashrc.
git clone <repo-url>
cd voxcode
uv syncuv sync downloads Python (if needed) and all dependencies. This takes about a minute.
Run this before anything else to make sure audio capture and transcription work:
uv run python test_interactive.py --devicesYou should see a list of audio devices with your microphone marked as default input. Look for your microphone in the list and note the device number (the number at the beginning of each line, e.g., > 13).
If your microphone is NOT the default device (common with external USB microphones), you need to specify the device number. For example, if your USB mic is device 13:
uv run python test_interactive.py --audio-device 13If the default device is correct, just run it without --audio-device.
Now test actual transcription — speak into your microphone when you see "Speak now!":
uv run python test_interactive.py
# Or with a specific device:
uv run python test_interactive.py --audio-device 13What you should see:
╭──────────────────────────────────────╮
│ VoxCode Interactive Audio Test │
╰──────────────────────────────────────╯
Model: large-v3 on cuda (float16)
Language: auto
Mode: VAD (continuous) — speak naturally, pauses trigger transcription
Loading Whisper model... ← first run downloads ~3 GB, takes a few minutes
Model loaded.
Capture: 48000Hz → 16kHz resampled
Speak now! Say 'comando: invia' to test voice commands.
Press Ctrl+C to stop.
● listening ███░░░░░░░░░░░░░░░░░░░░░░ 0.0012 ← silence, low level
● REC ██████████████░░░░░░░░░░░░ 0.0847 ← you're speaking!
[1] Hello, this is a test (en, 0.8s) ← transcribed text
If this works, your audio pipeline is ready. Press Ctrl+C to stop.
Troubleshooting the test:
- If audio level stays near 0.0000 even when speaking: you're using the wrong audio device. Run
--devicesand try a different device number with--audio-device N - If the model is too slow or you don't have a GPU:
uv run python test_interactive.py --model small --device cpu --compute-type int8 - If you prefer press-to-talk instead of continuous listening:
uv run python test_interactive.py --ptt
A single command sets up everything — a multiplexer session with Claude Code and VoxCode side by side:
uv run voxcode --launch # auto-detects tmux or Zellij
uv run voxcode --launch --backend tmux # force tmux
uv run voxcode --launch --backend zellij # force ZellijThis creates a session called voxcode with two panes:
┌──────────────────────┬──────────────────────┐
│ │ │
│ Claude Code │ VoxCode │
│ waiting for │ ● LISTENING │
│ your input... │ │
│ │ │
└──────────────────────┴──────────────────────┘
You can also launch a different command in the first pane:
uv run voxcode --launch "claude --model opus"
uv run voxcode --launch vimThe default command is claude, configurable in config.toml:
[multiplexer]
launch_command = "claude"If the session already exists, --launch reattaches to it.
By default, VoxCode injects text without pressing Enter — you review it in the Claude Code pane and press Enter when ready. To send automatically:
[multiplexer]
send_enter = trueIf you prefer to set up the tmux panes yourself:
1. Open a terminal and start tmux:
tmuxYour terminal is now inside tmux (you'll see a green bar at the bottom).
2. Start Claude Code:
claudeClaude Code starts in this pane. You should see its prompt waiting for input.
3. Create a second pane for VoxCode:
Press Ctrl+B, then % (percent sign). This splits your terminal into two panes side by side.
Your cursor is now in the right pane.
4. Start VoxCode in the new pane:
cd ~/path/to/voxcode
uv run voxcodeReplace ~/path/to/voxcode with wherever you cloned the project (e.g., cd ~/voxcode).
VoxCode auto-detects the Claude Code pane. You should see:
╭────────────── VoxCode ──────────────╮
│ Mode: VAD ● LISTENING │
│ Level: ███░░░░░░░░░░░░░░░░░░░░░░ │
│ Pane: 0:0.0 │
│ Keys: [Enter] send [c] clear │
│ [q] quit │
╰─────────────────────────────────────╯
5. Speak and send your first voice command:
Say something, for example: "explain what the ls command does"
You'll see the status change to ● RECORDING while you speak, then ● TRANSCRIBING, and then your text appears in the Buffer line:
│ Buffer: explain what the ls command does │
Now send it to Claude Code in one of two ways:
- Voice: Say "comando: invia"
- Keyboard: Press Enter
The text disappears from the buffer and appears in the Claude Code pane as if you typed it. Claude Code processes it and responds.
│ Sent: explain what the ls command does │
│ Buffer: │
That's it! You're now controlling Claude Code with your voice.
speak speak more "comando: invia" Claude Code
"explain" → "the ls" → (or press Enter) → receives the
"what..." "command does" full prompt
│ │ │
▼ ▼ ▼
Buffer: Buffer: explain Buffer is sent,
"explain what the ls cleared, ready
what..." command does" for next prompt
Key points:
- Text accumulates in the buffer as you speak. Multiple speech segments are joined together.
- Nothing is sent until you explicitly say "comando: invia" or press Enter.
- Say "comando: cancella" (or press
c) to clear the buffer and start over. - Say "comando: pausa" to temporarily stop listening (say "comando: riprendi" to resume).
| Key | Action |
|---|---|
Enter |
Send buffer to Claude Code |
c |
Clear buffer |
q |
Quit VoxCode |
Ctrl+C |
Quit VoxCode |
Space |
Toggle recording (PTT mode only) |
Voice commands must start with the prefix "comando:" so VoxCode can tell them apart from regular speech.
| Say this | What happens |
|---|---|
| "comando: invia" or "comando: send" | Send buffer to Claude Code |
| "comando: cancella" or "comando: cancel" | Clear the buffer |
| "comando: pausa" or "comando: pause" | Pause listening |
| "comando: riprendi" or "comando: resume" | Resume listening |
Both Italian and English command words work regardless of what language you're speaking.
If you've never used tmux before, here's everything you need:
| What you want to do | What to press |
|---|---|
| Start tmux | Type tmux and press Enter |
| Split into two panes (side by side) | Ctrl+B then % |
| Split into two panes (top/bottom) | Ctrl+B then " |
| Move to the other pane | Ctrl+B then arrow key (← or →) |
| Close a pane | Type exit or press Ctrl+D |
| Detach from tmux (it keeps running) | Ctrl+B then d |
| Reattach to a running tmux session | Type tmux attach |
Important: In tmux, Ctrl+B is the "prefix key". You press it, release it, then press the next key. Don't hold them all at once.
VAD mode (default) — VoxCode listens continuously. When you speak, it starts recording. When you stop speaking for ~1.5 seconds, it transcribes. This is the "hands-free" mode.
uv run voxcode # VAD modePTT mode (push-to-talk) — Press Space to start recording, Space again to stop. Useful in noisy environments where VAD might trigger on background noise.
uv run voxcode --mode ptt # PTT modeVoxCode works with sensible defaults. You only need a config file if you want to change something.
cp config.example.toml config.toml
# Edit config.toml with your preferred text editorVoxCode looks for config in this order:
./config.toml(current directory)~/.config/voxcode/config.toml- Built-in defaults
Send automatically without confirmation:
[general]
auto_send = true # sends text to Claude Code as soon as you stop speakingUse a smaller/faster model:
[whisper]
model = "small" # much faster, less accurateCPU-only (no NVIDIA GPU):
[whisper]
device = "cpu"
compute_type = "int8" # consider using "float32" for higher precision (slower)
model = "small" # large models are too slow on CPUAdjust speech detection sensitivity:
[vad]
threshold = 0.01 # lower = more sensitive (picks up quieter speech)
threshold = 0.03 # higher = less sensitive (ignores background noise)Use a specific microphone (if the default input device isn't your mic):
[audio]
device = 13 # find yours with: uv run voxcode --list-devicesSet tmux pane manually (if auto-detect doesn't find Claude Code):
[tmux]
auto_detect = false
target_pane = "0:0.0" # find yours with: tmux list-panes -aDisable voice commands (if "comando:" triggers too often by accident):
[commands]
enabled = false| Model | VRAM needed | Speed | Accuracy | Recommended for |
|---|---|---|---|---|
tiny |
~1 GB | Instant | Low | Quick testing only |
base |
~1 GB | Very fast | Fair | Low-end hardware |
small |
~2 GB | Fast | Good | CPU-only or limited VRAM |
medium |
~5 GB | Medium | Very good | Balanced choice |
large-v3 |
~10 GB | ~1-2s | Best | Default, best accuracy |
Override config settings without editing the file:
uv run voxcode --launch # Launch tmux/Zellij with Claude Code + VoxCode
uv run voxcode --launch "vim" # Launch with a custom command + VoxCode
uv run voxcode --backend zellij # Force Zellij backend
uv run voxcode --backend tmux # Force tmux backend
uv run voxcode --mode ptt # Push-to-talk
uv run voxcode --model small # Smaller model
uv run voxcode --device cpu # CPU-only
uv run voxcode --language it # Force Italian
uv run voxcode --audio-device 13 # Use specific microphone (see --list-devices)
uv run voxcode --config myconfig.toml # Custom config file
uv run voxcode --list-devices # Show audio devicesVoxCode looks for a multiplexer pane running a process with "claude" in the name.
Fix 1: Make sure Claude Code is actually running in a multiplexer pane (not in a separate terminal outside tmux/Zellij).
Fix 2 (tmux): Check what tmux sees:
tmux list-panes -a -F "#{session_name}:#{window_index}.#{pane_index} #{pane_current_command}"Fix 2 (Zellij): Check what Zellij sees:
zellij list-sessionsFix 3: Set the pane manually in config.toml:
For tmux:
[tmux]
auto_detect = false
target_pane = "0:0.0" # replace with your pane from the command aboveFor Zellij:
[zellij]
auto_detect = false
target_pane = "next" # "next" or "previous" relative to VoxCode pane# Check devices
uv run python test_interactive.py --devices
# Make sure PipeWire/PulseAudio is running
pactl info | head -5
# Test recording with system tools
arecord -d 3 -f cd test.wav && aplay test.wav# Verify GPU is being used
nvidia-smi
# Look for a python process using VRAM
# Switch to a smaller model
uv run voxcode --model small
# Or try int8 quantization (less VRAM, similar quality to float16)
# In config.toml: compute_type = "int8"The first run downloads the Whisper model from HuggingFace (~3 GB for large-v3). Subsequent runs load it from cache (~5-10 seconds).
If the download fails:
# Models are cached here:
ls ~/.cache/huggingface/hub/models--Systran--faster-whisper-*
# Delete and retry if corrupted
rm -rf ~/.cache/huggingface/hub/models--Systran--faster-whisper-*Increase the VAD threshold in config.toml:
[vad]
threshold = 0.03 # default is 0.015, higher = less sensitiveOr switch to PTT mode to avoid false triggers:
uv run voxcode --mode pttvoxcode/
├── pyproject.toml # Project config and dependencies
├── config.example.toml # Example configuration
├── test_interactive.py # Interactive audio test (no tmux needed)
├── README.md # This file
├── ROADMAP.md # Future features and extension plans
└── src/voxcode/
├── __init__.py # Package marker
├── __main__.py # Allows `python -m voxcode`
├── cli.py # Main app loop and orchestration
├── config.py # TOML config loading
├── audio.py # Microphone capture with resampling
├── vad.py # Voice activity detection
├── transcriber.py # Whisper transcription wrapper
├── commands.py # Voice command parser
├── multiplexer.py # Multiplexer abstraction and auto-detection
├── tmux_bridge.py # tmux backend
├── zellij_bridge.py # Zellij backend
└── ui.py # Terminal UI (rich)