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 has two top-level fields plus a nested sub-object per backend.

Key Default Description
backend "auto" "auto" | "whisper-cpp" | "moonshine" — auto selects based on GPU availability
inference_mode "Balanced" "Balanced" | "Aggressive" — Balanced is recommended
whisper_cpp.model_size "large-v3" tiny, tiny.en, base, base.en, small, small.en, medium, medium.en, large-v2, large-v3, large-v3-turbo
whisper_cpp.device "auto" auto | cpu | cuda | vulkan
whisper_cpp.threads 0 CPU thread count; 0 = half of logical cores
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

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
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.