REFERENCE / CONFIGURATION

Configuration

All settings live under ~/.config/voxctrl/. The Settings UI is a thin layer over these files — they're the source of truth. All three config files are hot-reloaded on save.

Files

File Format Purpose
config.json JSON Application settings — engine, audio, UI, features, OpenAI, TTS, MCP, AT-SPI2
targets.toml TOML Output target definitions
bindings.toml TOML Hotkey binding definitions

Data directory

Models and TTS voices are stored under ~/.local/share/voxctrl/:

Migration

VoxCtrl auto-migrates older config formats on load — unrecognized fields are silently ignored, and missing fields fall back to their defaults. This keeps things compatible across upgrades and downgrades. One known migration: features.show_notification moved to ui.show_notification in an early release; the migrated config is immediately re-saved to disk to clean up the old key.

engine

The engine config supports four distinct speech-recognition backends, each with its own nested sub-object. There is also an on-device dictation cleanup pass, s1_mini, that runs independently of which backend is selected.

Key Default Description
backend "whisper-cpp" "whisper-cpp" | "moonshine" | "parakeet" | "remote-openai" — which speech-recognition backend to use
whisper_cpp.model_size "tiny" tiny, tiny.en, base, base.en, small, small.en, medium, medium.en, large-v2, large-v3, large-v3-turbo. tiny/tiny.en auto-download silently on first launch; other sizes require an explicit download in Settings → Engine.
whisper_cpp.device "auto" auto | cpu | cuda | vulkan
whisper_cpp.threads 0 CPU thread count; 0 = one per physical core
whisper_cpp.model_dir "" Custom model directory; empty = ~/.local/share/voxctrl/models/
moonshine.model_size "base" "base" | "tiny" (only used when backend = "moonshine")
moonshine.language "en" BCP-47 language code (output label only)
parakeet.model_size "tdt-0.6b-v3" Parakeet model size, INT8 ONNX (only used when backend = "parakeet"); "tdt-0.6b-v3-redux" is the smaller 1.58-bit variant (~420 MB)
parakeet.language "auto" Target language code
remote_openai.endpoint "http://localhost:8000/v1" URL of the OpenAI-compatible speech-to-text service (used when backend = "remote-openai" — "Bring Your Own Voice Engine")
remote_openai.api_key null Optional Bearer token authentication
remote_openai.model "whisper-1" Remote model name, e.g. whisper-1, large-v3
remote_openai.language "" Language code for transcription, or blank for automatic detection
remote_openai.timeout_secs 30 Request timeout in seconds (min 5, max 300)
s1_mini.enabled false Enable on-device dictation cleanup via Superwhisper's fine-tuned S1-mini (Qwen3-0.6B) model — normalizes hesitations and self-corrections after transcription, independent of the STT backend
s1_mini.styling "semi-formal" "semi-formal" | "formal" | "casual", etc. — text styling passed to S1-mini

A config still holding a retired backend = "auto" value loads as "whisper-cpp". Moonshine is a default compile-time feature; a build made with --no-default-features omits it, and selecting "moonshine" then transparently falls back to whisper-cpp.

audio

Key Default Description
vad_threshold 0.5 Voice Activity Detection sensitivity (0.0–1.0); higher = more sensitive
min_silence_duration_ms 500 Milliseconds of silence before stopping a recording session
input_device_index null CPAL device index; null = auto-detect
evdev_device null Linux evdev keyboard device path for hotkeys, e.g. "/dev/input/event4"
noise_suppression false Enable basic noise suppression pre-processing
gain 1.0 Microphone amplification multiplier
dynamic_stream true Open mic on-demand (true) vs. always-on (false)

ui

Key Default Description
show_overlay true Whether the overlay window is currently visible
overlay_style "blue_wave" blue_wave | voice_card | waveform | pulse | mono_bars | spectrum | terminal | vinyl | none
overlay_position "center" top | center | bottom
overlay_monitor "primary" "primary" or a specific monitor name
auto_show_settings true Auto-show Settings window on startup
show_notification false Desktop toast notification after text delivery
history_enabled false Enable transcription history tracking

features

Key Default Description
paste_instead_of_typing true Deliver dictation as one paste (clipboard backed up and restored) instead of typing it; falls back to typing. Ignored on Linux Mint, where text is always typed
paste_shortcut "auto" auto, ctrl+v, ctrl+shift+v or shift+insert
early_command_detection true Detect a spoken command while you are still speaking, so its overlay appears and the TTS model starts loading before you release the hotkey
remove_fillers true Strip filler words (uh, um, hmm, er, ah, etc.)
spoken_punctuation true Convert spoken punctuation words to symbols (e.g. "period" → ".")
auto_format_lists true Detect "first/second/third" patterns and reformat as a numbered list
quiet_mode false Suppress overlay notifications during transcription
custom_vocabulary [] Custom words corrected post-transcription via fuzzy Levenshtein matching
snippets {} Short code → expansion text map

openai

LLM post-processing through any OpenAI-compatible API server — local or hosted. Exposed in the GUI under Settings → OpenAI API. Each request sends a system prompt (how to transform the text) and a user prompt containing {text}, replaced with the dictated speech. Configs written before this section was renamed used the key ollama; that key is still accepted via a serde alias.

Key Default Description
enabled false Enable LLM post-processing
endpoint "http://localhost:11434" OpenAI-compatible API base URL; /v1 suffix added automatically when missing
api_key null Sent as a Bearer token; required by most remote providers
model "llama3.2:1b" Model name
mode "clean" clean | formal | casual | bullet | concise | custom
system_prompt "Fix grammar and punctuation only…" System message describing the transformation; empty = none
user_prompt "{text}" User message template; must contain {text}
timeout_secs 8 HTTP request timeout in seconds

tts

Key Default Description
enabled false Enable TTS subsystem
engine "piper" piper | pocket_tts | espeak
voice "en-us-lessac-medium" Active Piper voice name
voice_dir "" Piper voice directory; empty = ~/.local/share/voxctrl/piper-voices/
stop_key [KEY_ESCAPE] Keys that cancel current TTS playback
response_overlay true Show overlay indicator while TTS is speaking
speed 1.0 Speech speed multiplier (0.5–2.0); not used by Pocket-TTS
gpu false Enable GPU acceleration (CUDA) for Piper
pocket_tts.voice "alba" Bundled voice ID (alba, anna, vera, charles, michael) or custom clip stem
pocket_tts.prewarm false Pre-warm model on startup so first speech is instantaneous
pocket_tts.hf_token null HuggingFace token to download the gated kyutai/pocket-tts weights
pocket_tts.voice_dir "" Directory scanned for custom .wav voice clips; empty = default directory

Pocket-TTS is a voice-cloning neural TTS engine — each voice is a short reference audio clip that conditions synthesis, rather than a fixed precomputed embedding.

mcp

Key Default Description
server_enabled false Start the MCP socket server on launch
record_timeout 15.0 Max seconds for transcribe_voice to wait for speech
visual_feedback true Show overlay indicator while MCP server is listening to microphone

atspi

Key Default Description
injection true Use AT-SPI2 for text insertion when available
context_prompt true Read focused widget text to use as Whisper context prompt
auto_code_mode true Detect code editors/terminals and enable code-mode processing automatically

targets.toml

Each output destination is a [[target]] block, identified by id and routed to by hotkey bindings. Common fields: label, delivery, append_newline (default true), strip_newlines (default false, inject only), send_on_release (default true), initial_prompt (Whisper context override), and a per-target [target.processing] block that can override any global feature flag (remove_fillers, spoken_punctuation, auto_format_lists, apply_snippets, code_mode, quiet_mode, atspi_context, noise_suppression).

Delivery types: inject, clipboard, file (with file_path/file_prefix/file_timestamp/file_mode), http (http_url, http_method), webhook (webhook_url, webhook_secret), exec (command), socket (socket_unix or socket_host/socket_port), pipe (pipe_path), and speak. Any target can also set a response_pipe FIFO path for TTS output.

bindings.toml

Each hotkey is a [[binding]] block with id, label, keys (evdev key names), gesture, and target_ids (ordered list of target IDs to route to).

Field Default Description
gesture — hold | toggle | double_tap | double_tap_hold | chord
subkey — Trigger key for the chord gesture, pressed after base keys are held
hold_threshold_ms 200 Min hold duration in ms for hold / double-tap-hold gestures
tap_ms 250 Double-tap inter-press window in ms
disabled false Disable without deleting
openai_enabled null Enable/disable LLM post-processing for this hotkey (null = inherit global)
openai_mode null LLM mode override for this hotkey (clean/formal/casual/bullet/concise/custom)
openai_model null Model override for this hotkey (null = inherit global)
openai_prompt null User prompt template override for this hotkey; must contain {text} (null = inherit global)
openai_system_prompt null System prompt override for this hotkey (null = inherit global)

The per-hotkey field names were renamed from ollama_* to openai_*; the legacy names are still accepted via serde aliases.