Repository
voxd
A fully local, headless AI dictation daemon for macOS written in rust. Triggers via an activation chord to instantly process and auto-paste text system-wide.
- Component
- Role
- Whisper ( ggml-large-v3-turbo )
- Whisper
- Ollama
- Ollama
- Cleanup model ( lfm2.5-thinking recommended)
- Cleanup model
Specs
- ComponentRole
- Whisper ( ggml-large-v3-turbo )Whisper
- OllamaOllama
- Cleanup model ( lfm2.5-thinking recommended)Cleanup model
- CommandWhat it does
- voxd doctorDownload/verify Whisper assets; check mic, Accessibility, Input Monitoring, Ollama reachability, and cleanup model presence
- voxd installWrite ~/Library/LaunchAgents/com.voxd.daemon.plist and bootstrap the per-user launchd job
- voxd startLoad/restart the daemon via launchd ( kickstart )
- voxd stopUnload the launchd job (plist remains; use start to run again)
- voxd uninstallStop the job and remove the plist
- voxd statusHuman-readable runtime health (add --json for machine-readable)
- voxd activation show / set <chord>View or set Activation Chord (default: fn+ctrl )
- voxd audio listList microphone devices ( --json optional)
- voxd audio use defaultUse system default input
- voxd audio use <device-id>Pin a device from audio list
- voxd cleanup show / set <mode>View or set Cleanup Mode ( raw , light , polish )
- voxd fallback show / set <policy>View or set Fallback Policy when cleanup fails
- voxd recovery-policy show / set <policy>View or set Recovery Policy when insertion target is lost
- voxd recovery listList recovery record metadata
- voxd recovery show <id>Print preserved text for one recovery record
- OptionDefault
- activation_chordfn+ctrl
- audio_inputsystem-default
- max_turn_duration_secs60
- cleanup_modelight
- fallback_policyraw
- cleanup_timeout_secs2.0
- recovery_policystore-and-clipboard
- VariableDefault
- VOXD_OLLAMA_CLEANUP_MODELlfm2.5-thinking
- VOXD_OLLAMA_BASE_URLhttp://127.0.0.1:11434
- VOXD_DATA_DIR~/Library/Application Support/voxd
- VOXD_HOME_DIR$HOME
- VOXD_WHISPER_MODEL_URLupstream ggml-large-v3-turbo URL
- VOXD_WHISPER_MODEL_SHA256baked default hash
- VOXD_WHISPER_MODEL_FILEggml-large-v3-turbo.bin
- PermissionUsed for
- MicrophoneMicrophone
- AccessibilityAccessibility
- Input MonitoringInput Monitoring
README
voxd
Why pay for Wispr Flow?
Fully local voice dictation for Apple Silicon macOS. Hold a global Activation Chord (default fn+ctrl), speak, release to commit; voxd transcribes with Whisper, optionally cleans the text with a local Ollama model, and inserts into the focused app.
Requirements
- macOS on Apple Silicon
- Rust (to build from source)
- Ollama for post-processing (optional for
cleanup_mode = "raw") - Microphone, Accessibility, and Input Monitoring permissions for
voxd-daemon(see Permissions)
Install to PATH
Recommended - install both voxd and voxd-daemon from GitHub (they land in ~/.cargo/bin; the CLI resolves the daemon as a sibling of voxd):
cargo install --git https://github.com/Shaurya-Sethi/voxd
Or from a local clone:
git clone https://github.com/Shaurya-Sethi/voxd
cd voxd
cargo install --path .
Note: Rebuilding and replacing
voxd-daemoncan reset macOS privacy (TCC) grants for that binary. After a rebuild, re-assign permissions in System Settings.
Quick start
-
Bootstrap dependencies (downloads Whisper weights; checks permissions and Ollama):
voxd doctor -
Pull the recommended cleanup model (small, fast for dictation cleanup):
ollama pull lfm2.5-thinking -
Start Ollama (in a separate terminal or tmux pane):
ollama serve -
Install and start the background daemon (per-user launchd agent):
voxd install voxd start -
Verify readiness:
voxd status voxd doctor -
Focus a text field, hold your Activation Chord, speak, release to commit the dictation turn.
How it works
flowchart LR
A[Hold Activation Chord] --> B[Record audio]
B --> C[Release chord]
C --> D[Whisper STT]
D --> E[Ollama cleanup]
E --> F[Insert into target]
At a high level, each Dictation Turn is:
- Record : While the Activation Chord is held, audio is captured from the configured Audio Input (up to
max_turn_duration_secs). - STT : On release, in-process Whisper (
ggml-large-v3-turbo) produces a Raw Transcript. - Post-process : Unless cleanup mode is
raw, voxd calls local Ollama to turn the raw transcript into Cleaned Text (punctuation, casing, light polish). - Insert : voxd inserts into the verified Insertion Target via Accessibility APIs, with a clipboard-preserving paste fallback when direct insert fails but the target is still verified.
If the Insertion Target cannot be verified at insert time (for example you switched apps or focus moved), voxd does not type into the wrong place. With the default Recovery Policy, text is saved to the recovery store and copied to the clipboard so you can paste manually. Apps where insertion is typically reliable include TextEdit, Notes, and Google Chrome; some apps block or obscure the focused element — use clipboard paste when voxd notifies you the target was lost.
Dependencies
| Component | Role | How you get it |
|---|---|---|
Whisper (ggml-large-v3-turbo) |
On-device speech-to-text | voxd doctor downloads and verifies weights under ~/Library/Application Support/voxd/models/ |
| Ollama | Local LLM HTTP server for cleanup | Install from ollama.com; run ollama serve |
Cleanup model (lfm2.5-thinking recommended) |
Turns raw transcript into cleaned text | ollama pull lfm2.5-thinking (or another model of your choice via a VOXD_OLLAMA_CLEANUP_MODEL environment variable) |
Dictation still works if Ollama is down when Fallback Policy is raw (insert the raw transcript). Other fallback modes are described in the configuration table.
Commands
| Command | What it does |
|---|---|
voxd doctor |
Download/verify Whisper assets; check mic, Accessibility, Input Monitoring, Ollama reachability, and cleanup model presence |
voxd install |
Write ~/Library/LaunchAgents/com.voxd.daemon.plist and bootstrap the per-user launchd job |
voxd start |
Load/restart the daemon via launchd (kickstart) |
voxd stop |
Unload the launchd job (plist remains; use start to run again) |
voxd uninstall |
Stop the job and remove the plist |
voxd status |
Human-readable runtime health (add --json for machine-readable) |
voxd activation show / set <chord> |
View or set Activation Chord (default: fn+ctrl) |
voxd audio list |
List microphone devices (--json optional) |
voxd audio use default |
Use system default input |
voxd audio use <device-id> |
Pin a device from audio list |
voxd cleanup show / set <mode> |
View or set Cleanup Mode (raw, light, polish) |
voxd fallback show / set <policy> |
View or set Fallback Policy when cleanup fails |
voxd recovery-policy show / set <policy> |
View or set Recovery Policy when insertion target is lost |
voxd recovery list |
List recovery record metadata |
voxd recovery show <id> |
Print preserved text for one recovery record |
Config file (created/updated by set commands and manual edits):
~/Library/Application Support/voxd/config.toml
Daemon logs:
~/Library/Application Support/voxd/logs/
Configuration
Settings live in config.toml unless noted. CLI set commands persist the same keys.
| Option | Default | Description |
|---|---|---|
activation_chord |
fn+ctrl |
Global shortcut: hold to record, release to commit (voxd activation set) |
audio_input |
system-default |
Microphone device id from voxd audio list, or system default (voxd audio use) |
max_turn_duration_secs |
60 |
Maximum capture length per dictation turn (config file only) |
cleanup_mode |
light |
raw — no Ollama; light — light cleanup; polish — stronger polish (voxd cleanup set) |
fallback_policy |
raw |
If cleanup fails: raw insert transcript; drop insert nothing; recover preserve via recovery store (voxd fallback set) |
cleanup_timeout_secs |
2.0 |
HTTP timeout for Ollama cleanup (config file only) |
recovery_policy |
store-and-clipboard |
If insertion target is lost: store, clipboard, store-and-clipboard, or drop (voxd recovery-policy set) |
Environment variables (advanced)
Set these before voxd install if you want them embedded in the launchd plist, or export them in the shell used for manual voxd-daemon runs.
| Variable | Default | Purpose |
|---|---|---|
VOXD_OLLAMA_CLEANUP_MODEL |
lfm2.5-thinking |
Ollama model tag for cleanup. Recommended: lfm2.5-thinking — very small and effective for this task; any pulled Ollama model works if prompts suit your use |
VOXD_OLLAMA_BASE_URL |
http://127.0.0.1:11434 |
Ollama HTTP base URL |
VOXD_DATA_DIR |
~/Library/Application Support/voxd |
Override data directory (config, models, socket, logs) |
VOXD_HOME_DIR |
$HOME |
Override home used for LaunchAgents path |
VOXD_WHISPER_MODEL_URL |
upstream ggml-large-v3-turbo URL |
Custom Whisper download URL |
VOXD_WHISPER_MODEL_SHA256 |
baked default hash | Required when using a custom Whisper URL |
VOXD_WHISPER_MODEL_FILE |
ggml-large-v3-turbo.bin |
Whisper weights filename under models/ |
Example — use a different cleanup model:
export VOXD_OLLAMA_CLEANUP_MODEL=my-model:tag
ollama pull my-model:tag
voxd install # re-install if the daemon was already installed without this env
voxd start
Permissions
macOS grants privacy access per executable. Dictation runs in voxd-daemon, not the voxd CLI. After installing, run the daemon once (via voxd start) and grant access when prompted, or open System Settings → Privacy & Security:
| Permission | Used for |
|---|---|
| Microphone | Capturing audio for dictation (Cannot be granted via settings) |
| Accessibility | Reading the focused UI element and inserting text |
| Input Monitoring | Listening for the global Activation Chord |
Enable voxd-daemon in each list. Confirm with:
voxd doctor
voxd status
Stop, restart, and Ollama
Daemon (launchd):
voxd stop # unload job; plist stays installed
voxd start # load/restart daemon
voxd uninstall # remove plist and stop managing the service
Ollama:
# stop: Ctrl+C in the terminal running `ollama serve`, or kill the process
ollama serve # start again
After changing config.toml or environment variables referenced by the plist, voxd stop then voxd start (or voxd install + voxd start when env vars changed).
Tip: tmux layout
Keep long-running services visible in one place:
tmux new -s voxd
# Split horizontally (two panes):
# prefix (ctrl+b) then %
- Pane 1:
voxd status,voxd doctor, config commands, daemonstop/start - Pane 2:
ollama serve
Save with prefix + ctrl+s and detach with prefix + d. Attach later with tmux a.
AI Disclosure
A significant part of this codebase was written with Cursor. The only issues that were fully implemented by me were #2, #3, #4, and #11. The rest were largely addressed using Nightshift (a tool I made) powered by composer-2.5. I wanted to stay as far as possible from plumbing and macos specifics as these don't interest me (and I also needed a real repo to test nightshift on lol).
License
MIT — see LICENSE.