Voice-to-text dictation tool for Linux (X11) using OpenAI Whisper.
Hold Ctrl+Space to record speech, release to transcribe and type into the focused window.
- Python 3.11+
- Linux with X11 (Wayland has limited support)
- PulseAudio/PipeWire
- Working microphone
- OpenAI API key
# System dependencies
sudo apt install xdotool ffmpeg python3-pip python3-venv
# Create virtual environment (recommended)
python3 -m venv ~/.local/share/linux-voice
source ~/.local/share/linux-voice/bin/activate
# Install Python packages
pip install pynput sounddevice numpy openai
# Download and install script
curl -o ~/.local/bin/linux-voice https://raw.githubusercontent.com/williamjameshandley/linux-voice/main/linux-voice.py
chmod +x ~/.local/bin/linux-voice# System dependencies
sudo dnf install xdotool ffmpeg python3-pip
# Create virtual environment (recommended)
python3 -m venv ~/.local/share/linux-voice
source ~/.local/share/linux-voice/bin/activate
# Install Python packages
pip install pynput sounddevice numpy openai
# Download and install script
curl -o ~/.local/bin/linux-voice https://raw.githubusercontent.com/williamjameshandley/linux-voice/main/linux-voice.py
chmod +x ~/.local/bin/linux-voice# System dependencies
sudo pacman -S xdotool ffmpeg python-numpy python-pynput python-sounddevice python-openai
# Download and install script
curl -o ~/.local/bin/linux-voice https://raw.githubusercontent.com/williamjameshandley/linux-voice/main/linux-voice.py
chmod +x ~/.local/bin/linux-voiceOr build the package:
git clone https://github.com/williamjameshandley/linux-voice
cd linux-voice
makepkg -si# Ensure system dependencies are installed first:
# - xdotool (for typing text)
# - ffmpeg (for audio compression, optional but recommended)
pip install pynput sounddevice numpy openai
# Download script
curl -o ~/.local/bin/linux-voice https://raw.githubusercontent.com/williamjameshandley/linux-voice/main/linux-voice.py
chmod +x ~/.local/bin/linux-voicebrew install ffmpeg uvgit clone https://github.com/williamjameshandley/linux-voice
cd linux-voice
uv sync --extra macos --extra groq # or without --extra groq if using OpenAIGet a free Groq API key at groq.com (or use an OpenAI key).
mkdir -p ~/.config/linux-voice
cat > ~/.config/linux-voice/config.toml << 'EOF'
[transcription]
backend = "groq"
api_key = "your-groq-api-key-here"
EOFFor OpenAI, omit the backend line and set your OpenAI key as api_key.
- Accessibility: System Settings > Privacy & Security > Accessibility — add
/bin/zsh(click+, press Cmd+Shift+G, type/bin/zsh) - Microphone: Will be prompted on first run
uv run python linux-voice.pyHold Cmd+Shift+Space, speak, release. Text should appear in the focused window. Press Ctrl+C to stop.
uv run python linux-voice.py --install-agentThis auto-generates the LaunchAgent plist with the correct paths and API key. Then start it:
launchctl bootstrap gui/$(id -u) ~/Library/LaunchAgents/com.linux-voice.agent.plistVoice dictation now works globally in any app via Cmd+Shift+Space and starts automatically on login.
# View logs
tail -f ~/Library/Logs/linux-voice.log
# Restart after code changes
launchctl kickstart -k gui/$(id -u)/com.linux-voice.agent
# Uninstall (stop + remove)
uv run python linux-voice.py --uninstall-agent| Hotkey | Action |
|---|---|
Cmd+Shift+Space |
Hold to record, release to transcribe |
Cmd+Shift+Ctrl+Space |
Record and auto-press Enter |
Cmd+Alt+Space |
Record correction instruction |
Add to your shell profile (~/.bashrc, ~/.zshrc, etc.):
export OPENAI_API_KEY="your-key-here"For the systemd service, create ~/.config/environment.d/openai.conf:
OPENAI_API_KEY=your-key-here
linux-voiceIf using a virtual environment:
~/.local/share/linux-voice/bin/python ~/.local/bin/linux-voiceCreate ~/.config/systemd/user/linux-voice.service:
[Unit]
Description=Linux Voice Dictation
[Service]
ExecStart=%h/.local/bin/linux-voice
Restart=on-failure
[Install]
WantedBy=default.targetIf using a virtual environment, update ExecStart:
ExecStart=%h/.local/share/linux-voice/bin/python %h/.local/bin/linux-voiceThen enable:
systemctl --user daemon-reload
systemctl --user enable --now linux-voice
# Check status
systemctl --user status linux-voice
# View logs
journalctl --user -u linux-voice -f- Hold mode (default): Hold Ctrl+Space while speaking, release to transcribe
- Toggle mode: Press Ctrl+Space to start recording, press again to stop
LINUX_VOICE_MODE=toggle linux-voiceUse Ctrl+Shift+Space (default) to record and automatically press Enter after typing. Useful for command-line input, chat applications, or any context where you want to submit immediately.
Configure an alternative (e.g., Alt+Space) in ~/.config/linux-voice/config.toml:
[hotkey_submit]
key = "space"
modifiers = ["alt"]
delay = 150 # ms delay before Enter (increase if unreliable)Use Ctrl+Alt+Space (default) to correct the previous transcription using an LLM. This is useful when Whisper misinterprets a word:
- Dictate normally with Ctrl+Space → "The function uses a cash mechanism"
- Hold Ctrl+Alt+Space and say "change cash to cache"
- The original text is cleared and replaced with "The function uses a cache mechanism"
The edit uses the backend's chat model (gpt-4o-mini for OpenAI, llama-3.3-70b-versatile for Groq). The LLM is aware of Unix/programming context and common voice recognition errors (cash→cache, bite→byte, get→git, etc.).
Configure in ~/.config/linux-voice/config.toml:
[hotkey_edit]
key = "space"
modifiers = ["ctrl", "alt"]
[transcription]
# llm_model = "gpt-4o-mini" # Override LLM model for correctionsIf the internet connection fails during transcription, the audio is saved and you'll see:
(no internet - say 'recover' to retry)
When internet is restored, hold Ctrl+Space and say "recover" to transcribe the saved audio. The recovery file is stored at /tmp/linux-voice-recovery.wav and deleted after successful recovery.
| Command | Action |
|---|---|
| "recover" | Transcribe saved audio from a failed attempt |
Create ~/.config/linux-voice/config.toml to customize:
[hotkey]
key = "space"
modifiers = ["ctrl"]
mode = "hold" # or "toggle"
[hotkey_submit]
key = "space"
modifiers = ["ctrl", "shift"] # Ctrl+Shift+Space by default
delay = 150 # ms delay before Enter key
[hotkey_edit]
key = "space"
modifiers = ["ctrl", "alt"] # Ctrl+Alt+Space by default
[audio]
sample_rate = 16000 # Whisper native rate (don't change unless needed)
silence_threshold = 150 # RMS threshold for silence detection
[transcription]
backend = "openai" # or "groq"
language = "en"
# model = "whisper-1" # or "whisper-large-v3-turbo" for groq
# llm_model = "gpt-4o-mini" # or "llama-3.3-70b-versatile" for groq (edit mode)
# prompt = "Domain-specific vocabulary. Technical terms, jargon, names."| Backend | Model | Cost | Latency |
|---|---|---|---|
openai |
whisper-1 | $0.006/min | ~1-2s |
groq |
whisper-large-v3-turbo | $0.04/hr | ~200ms |
For Groq, set GROQ_API_KEY instead of OPENAI_API_KEY.
The prompt helps Whisper with:
- British vs American spelling (colour, favour, organisation)
- Domain-specific vocabulary (your field's jargon)
- Consistent formatting and punctuation
Define regex replacements to convert spoken phrases into special characters or commands:
[replacements]
"^[Ss]lash " = "/" # "slash compact" → "/compact"
"^[Ff]orward [Ss]lash " = "/"
"^(/.*)\\.\\s*$" = "\\1" # strip period only from /commandsThis allows saying "slash compact" to type /compact for Claude Code commands.
Audio is sent to OpenAI: All recorded speech is transmitted to OpenAI's Whisper API for transcription. See OpenAI's data usage policies.
Text is typed into the focused window: Be careful not to dictate sensitive information while password fields or sensitive applications are focused.
OpenAI Whisper API costs $0.006 per minute of audio. A typical 10-second dictation costs ~$0.001.
Ubuntu/Debian:
sudo apt install linux-firmwareFedora:
sudo dnf install linux-firmwareArch Linux (modern AMD laptops - Ryzen 6000+, Strix Point):
sudo pacman -S sof-firmwareThen reboot.
Ctrl+Space (C-@) has a default behavior in vim insert mode (insert previously inserted text). Disable it by adding to your .vimrc:
" Disable Ctrl+Space insert mode behavior (for linux-voice)
inoremap <C-@> <Nop>xdotool has limited Wayland support. Consider using X11 or switching to ydotool.
On some systems, you may need to run as root or add your user to the input group:
sudo usermod -aG input $USERThen log out and back in.
- Accessibility permissions: Ensure your terminal app is listed in System Settings > Privacy & Security > Accessibility. Remove and re-add it if permissions were reset after a macOS update.
- Secure Input Mode: When a password field is focused or
sudois running in terminal, macOS enables Secure Input which blocks global hotkey monitoring. Switch to a different window/app. - Spotlight conflict: The default
Cmd+Spaceis taken by Spotlight. linux-voice defaults toCmd+Shift+Spaceon macOS to avoid this.
- Text is injected via clipboard paste (
Cmd+V). If the target app blocks paste, text injection will fail. - Some terminal apps (iTerm2) may prompt before pasting multi-line text.
MIT