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-daemon can reset macOS privacy (TCC) grants for that binary. After a rebuild, re-assign permissions in System Settings.

Quick start

  1. Bootstrap dependencies (downloads Whisper weights; checks permissions and Ollama):

    voxd doctor
  2. Pull the recommended cleanup model (small, fast for dictation cleanup):

    ollama pull lfm2.5-thinking
  3. Start Ollama (in a separate terminal or tmux pane):

    ollama serve
  4. Install and start the background daemon (per-user launchd agent):

    voxd install
    voxd start
  5. Verify readiness:

    voxd status
    voxd doctor
  6. 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:

  1. Record : While the Activation Chord is held, audio is captured from the configured Audio Input (up to max_turn_duration_secs).
  2. STT : On release, in-process Whisper (ggml-large-v3-turbo) produces a Raw Transcript.
  3. Post-process : Unless cleanup mode is raw, voxd calls local Ollama to turn the raw transcript into Cleaned Text (punctuation, casing, light polish).
  4. 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, daemon stop/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.