REFERENCE / ARCHITECTURE

Architecture

What's inside the app, and how the parts talk to each other.

High-level design

VoxCtrl is a Tauri 2 application: a compiled Rust backend that spawns a WebView window running a Svelte 5 SPA (styled with Tailwind CSS 4, bundled with Vite 5). The two halves communicate over Tauri's IPC bridge — invoke commands from the frontend, event emitters from the backend.

The backend also spawns a native overlay helper process (voxctrl-overlay, built with Slint) that renders the always-on-top, click-through recording HUD. The backend streams newline-delimited JSON (status / position / shutdown) to the helper's stdin; the helper runs its own 16ms animation loop, drives spring-based load/unload animations, and builds the per-style visualizer geometry (oscilloscope trace, radar sweep, ocean waves, VU LED matrix) on every tick.

Crate workspace

The backend is a Cargo workspace of focused, single-responsibility crates:

Data flow

A hotkey press is picked up by voxctrl-hotkeys and sent over a gesture_tx channel to the lib.rs coordinator, which starts the audio recorder and determines the target from the binding. Audio chunks accumulate in a buffer until hotkey release or VAD-detected silence, at which point the buffer is handed to InferenceEngine.process() in voxctrl-inference, which runs (in order): noise gate (VAD), Whisper transcription, filler removal, spoken punctuation, auto-format lists, snippet expansion, custom vocabulary fuzzy correction, code mode, a silence hallucination filter, and — optionally, per binding — an LLM rewrite via the OpenAI-compatible API.

The resulting text is sent to OutputTargetRouter.route() in voxctrl-routing, which dispatches by delivery type: injectvoxctrl-inject, clipboard → arboard, filetokio::fs, http/webhook → reqwest, execstd::process, socketUnixStream, dbusvoxctrl-dbus, mcp → the MCP response queue, and pipe → a named FIFO. A Tauri event then notifies the frontend (status tick, history update).

Concurrency model

VoxCtrl uses Tokio for async I/O plus dedicated OS threads for latency-sensitive work:

Shared state is an Arc<AppState>, using AtomicBool/AtomicU32 for hot-path flags and Mutex for heavier data (targets, history, TTS handle). Channels (crossbeam/tokio) carry typed messages between stages: audio_tx/audio_rx (Vec<f32> chunks), inference_tx/inference_rx (InferenceRequest), text_tx/text_rx (InferenceOutput), audio_level_tx/level_rx (f32 RMS), and gesture_tx/gesture_rx (GestureEvent), plus a hotkey_reloader channel that pushes updated bindings to the listener thread for hot-reload.

Frontend architecture

The Svelte frontend is a single-page app with three logical "pages" rendered as separate Tauri windows:

State management: src/stores/config.ts holds a reactive AppConfig with a 400ms-debounced auto-save via the save_config IPC command, and listens for config-changed events. src/stores/status.ts tracks live state from status-tick events plus derived stores (recording, speaking, wordCount, activeTargetLabel).

File locations

Path Contents
~/.config/voxctrl/config.json Main application config
~/.config/voxctrl/targets.toml Output target definitions
~/.config/voxctrl/bindings.toml Hotkey binding definitions
~/.local/share/voxctrl/models/ Downloaded Whisper GGUF models
~/.local/share/voxctrl/piper-voices/ Downloaded Piper voice packs
/tmp/voxctrl-mcp.sock MCP Unix domain socket (Linux)
\\.\pipe\voxctrl-mcp MCP named pipe (Windows)