Press a hotkey, speak, and paste the transcription at your cursor. ok-voice
is a toggle-driven voice-to-text application for Linux on X11 using a
configurable OpenAI-compatible Whisper endpoint.
- Toggle mode: first press starts recording, second press stops
- Batch transcription: uploads one completed WAV through the standard
/v1/audio/transcriptionsAPI; no Realtime API or WebSocket - Automatic language detection: no language configuration required
- Unicode output: transfers UTF-8 through the X11 clipboard
- Babashka
parecordfrom PulseAudio utilitiesxdotoolxclipnotify-sendfrom libnotifyxbindkeysor another external hotkey manager- An X11 desktop session
- An OpenAI-compatible transcription endpoint and Bearer credential
On Debian/Ubuntu:
sudo apt install pulseaudio-utils xdotool xclip libnotify-bin xbindkeysCreate the configuration directory and copy the example:
mkdir -p ~/.config/ok-voice
cp resources/config.example.yaml ~/.config/ok-voice/config.yaml
chmod 600 ~/.config/ok-voice/config.yamlEdit ~/.config/ok-voice/config.yaml:
api-url: "https://whisper-turbo.twohundredok.com/v1/audio/transcriptions"
api-key: "your-api-key-here"
model: "large-v3-turbo"
allow-insecure-http: falseapi-url must be the complete transcription endpoint, including
/v1/audio/transcriptions. The request uses the OpenAI multipart fields
file, model, and response_format=json, with Bearer authentication.
The following environment variables are used when the corresponding config value is absent:
| Config | Environment | Default |
|---|---|---|
api-url |
OPENAI_API_URL |
https://api.openai.com/v1/audio/transcriptions |
api-key |
OPENAI_API_KEY |
none |
model |
OPENAI_MODEL |
whisper-1 |
Remote plain-HTTP endpoints are rejected because they expose the credential
and recorded audio. HTTPS is recommended. Localhost HTTP is allowed; another
HTTP endpoint requires allow-insecure-http: true.
Never commit the real user configuration or an API key. The tracked
resources/config.example.yaml contains placeholders only.
Add a binding to ~/.xbindkeysrc:
"cd ~/src/200ok/ok-voice/ && bb -m ok-voice.core"
F9
Change the checkout path and key as needed, then reload xbindkeys:
xbindkeys --poll-rcRun the application once to start recording:
bb -m ok-voice.coreRun the same command again to stop and transcribe. The Babashka task is also
available as bb ok-voice. Notifications indicate recording, transcription,
completion, and error states.
- The first invocation records 16 kHz mono audio from the default PulseAudio input into a temporary WAV file.
- The second invocation writes a runtime stop request.
- The recording process uploads the WAV to the configured
OpenAI-compatible endpoint and reads the JSON
textresponse. - The original X11 window is activated and receives the transcript through the UTF-8 clipboard.
- Temporary WAV and runtime state files are removed.
The transcript is transferred through the X11 clipboard rather than typed as
synthetic character keypresses. X11 keyboard events cannot represent arbitrary
Unicode reliably; direct xdotool type input can corrupt characters such as
German umlauts.
ok-voice restores the previous textual clipboard after pasting. It uses
Shift+Insert for normal X11 applications and Ctrl+Shift+V for Kitty,
selected from the target window's X11 class. xdotool remains responsible
only for restoring window focus and sending the paste shortcut.
clj-kondo --lint src --fail-level warning
git diff --checkThis project is 100% vibe coded with
GSD. The full planning artifacts
are in the .planning/ folder.
AGPL-3.0 - see LICENSE for details.