A high-performance, private, on-device voice-to-text dictation application and programmable voice input broker built natively in Rust and Tauri with a Svelte frontend.
Zero Telemetry. Zero Cloud. 100% On-Device. VoxCtrl acts as an intelligent desktop voice gateway, routing your speech to any destinationβwhether typing directly into a focused window, invoking terminal agents, appending to journals, triggering shell commands, or feeding local AI assistants.
In an era of cloud processing, VoxCtrl is built from the ground up to guarantee absolute data sovereignty:
- VoxCtrl does not read your keyboard: Global shortcuts are registered with your desktop through the XDG
GlobalShortcutsportal. Your desktop owns the key grab and tells VoxCtrl exactly one thing β that its own shortcut fired. VoxCtrl cannot see what you type in your browser, your terminal, or your password manager, because it is never given the data. - No permissions to grant: No udev rule, no
inputgroup, no logout, no reboot. There is nothing to undo later, and installing VoxCtrl does not change your machine's security posture. (Earlier versions installed a udev rule granting read access to every input device. That has been removed β see why.) - No Cloud API Keys Required (100% On-Device by Default): VoxCtrl runs entirely offline on your local hardware using your choice of
whisper.cpp,Moonshine, orParakeet TDT. - Bring Your Own Voice Engine: Want to offload transcription to a homelab GPU server or custom backend? VoxCtrl supports connecting to any network speech-to-text service via the OpenAI-compatible
/v1/audio/transcriptionsAPI (Faster-Whisper, vLLM, Whisper standalone, or cloud APIs) with zero local compute overhead. - No Telemetry: Your ambient microphone data never leaves your machine. There are no hidden tracking scripts or analytical pings. The one request VoxCtrl makes on its own is the update check β a plain GET to GitHub's public release listing, carrying nothing about you, and off with one tick in Settings β General.
- Diagnostics only when you send them: Settings β Bug Report gathers a diagnostic bundle and sends it β but only when you press a button, and it shows you the entire report first. Everything you dictated, every API key, every file path, your username and your custom vocabulary are stripped before you ever see it, let alone before it is sent. See docs/bug_reports.md.
- Air-Gapped Ready: When using local inference backends, once application weights and models are downloaded, VoxCtrl requires zero internet access to function.
- Local Neural Voices: All text-to-speech feedback is generated offline by a local engine β Breeze-TTS-2, Piper, Pocket-TTS, Inflect-Micro-v2, or eSpeak-NG.
Full detail, including how to verify each claim yourself: docs/privacy.md.
The app tells you which of these is true, live. Settings β Hotkeys shows exactly how shortcuts are reaching VoxCtrl and which keys your desktop bound. If your desktop provides no shortcuts portal, VoxCtrl says so at launch and explains the trade-off β it will not grant itself keyboard access to work around it, because that access would apply to every program you run, not just this one.
On KDE Plasma specifically, an upstream bug leaves portal shortcuts registered but unticked in System Settings until you enable them yourself. VoxCtrl detects this and shows a one-click Open Shortcut Settings button β see KDE registers shortcuts disabled by default.
- High-Performance Offline Speech Recognition: Local on-device inference using native
whisper.cpp(viawhisper-rs), streaming ONNX withMoonshine, or ultra-fast non-autoregressive transcription via NVIDIAParakeet TDT. CUDA and Vulkan GPU acceleration available. - Bring Your Own Voice Engine (Remote Speech Engine): Connect VoxCtrl to any OpenAI-compatible
/v1/audio/transcriptionsnetwork endpoint (such as Faster-Whisper-Server, vLLM, LocalAI, Whisper standalone, or cloud STT APIs). Offload 100% of speech processing to your home server or external GPU instance with zero local RAM/VRAM load. Set up custom endpoints, Bearer auth, model selection with automatic server model discovery, and live connection testing directly in Settings β Engine or during initial onboarding. - First-Run Setup Wizard: A new machine is walked through setup in seven steps β choose from 4 transcription engine options (
whisper.cpp,Moonshine,Parakeet TDT, orRemote Speech Engine), bind a hotkey and register it with your desktop, choose an overlay, dictate a live test, and optionally add a voice β instead of being dropped into a settings window full of defaults nobody chose. Every choice is written to the config as it is made, so quitting halfway keeps what you picked. Reachable again afterwards withvoxctrl --setup, or Settings β General β "Open setup wizard". - Self-Updating: VoxCtrl checks GitHub for a newer release on launch, shows what changed, and β if you say yes β downloads the build matching your installation (Linux AppImage or Windows installer), verifies it against the checksum GitHub published, replaces itself and restarts. Nothing is replaced until a complete, verified file is on disk, so a failed update leaves the working version alone. The check is one unauthenticated request carrying no identifier, and Settings β General turns it off.
- Modern GUI & Tray System: A sleek Svelte-based user interface with dedicated, swappable, fully animated overlays (Ocean Wave, Voice Card, Waveform, and Pulse Ring), and a native desktop System Tray utility.
- Low-Latency Audio Loop: Streamlined recording and VAD (Voice Activity Detection) built using
cpalto minimize capture latency, with optional RNNoise background-noise suppression on the capture path. - Built-in Model Context Protocol (MCP) Server: Exposes voice dictation and speech synthesis as high-level JSON-RPC tools to AI clients (like Claude Desktop or Cursor) via local secure socketsβkeeping integrations fully local.
- Privacy-Preserving Global Hotkeys: Shortcuts are registered with your desktop through the XDG
GlobalShortcutsportal (KDE Plasma, GNOME 48+, Hyprland), so VoxCtrl receives its own shortcuts and never reads a keystroke. Bind hold-to-talk, toggle-to-talk, double-tap, or double-tap & hold gestures. Works identically on Wayland and X11, with no permission setup at all. - DBus Dictation Service: Exposes
ai.voxctrl.Dictationon the local Linux session bus, letting you script recording states securely without network exposure. - Neural Text-to-Speech (TTS): Built-in local voice feedback with a choice of engines β Breeze-TTS-2 (neural, voice design from natural language prompts; gated HF download under non-commercial license, optional CUDA/Metal GPU offload), Piper (neural, high quality), Pocket-TTS (neural, clones a voice from a reference clip), Inflect-Micro-v2 (neural, 38 MB ONNX), and eSpeak-NG (lightweight, always available) β with automatic local package installation and an in-app model downloader.
- Intelligent Post-Processing & LLM Rewriting: Real-time automatic filler-word cleanup (e.g. stripping "um", "uh", "hmm") to sanitize dictation, combined with optional post-processing through any OpenAI-compatible API server (a local Ollama or LM Studio instance, or a hosted provider) for real-time grammar correction, tone rewriting, or custom formatting. Point it at any URL and supply an API key when the server requires one.
The core of VoxCtrl is its Output Command Router. Rather than simply pasting text where your cursor is, VoxCtrl allows you to declare named output commands in targets.toml and bind them to different global keyboard gestures. This turns your voice into a programmable router.
Say a command by name. Start dictation and say "VoxCtrl", then the command's name, then what you want to send β "VoxCtrl notes, remember to call the plumber" routes remember to call the plumber to the command named notes. Everything after the name is the text, natural phrasing works ("VoxCtrl, add this to my notes: β¦"), and a dictation with no such phrase in it simply goes wherever your hotkey already points. See docs/routing.md for the full matching rules.
New in v0.1: You can now bind multiple commands to a single hotkey gesture! When activated, your text is broadcast concurrently to all bound commands. Configurations also hot-reload instantly in the background, without requiring an app restart.
Below are the 11 delivery types supported by VoxCtrl and what they are used for:
| Delivery Type | Mechanism | Perfect Use Case |
|---|---|---|
inject |
Keystroke simulation via native wtype (Wayland), xdotool (X11), or PowerShell (Windows). |
Standard voice dictation directly into any focused editor, web browser, or chat window. |
clipboard |
Fast clipboard population using the native arboard library. |
Quiet copying of notes, code snippets, or templates for manual pasting without modifying active focuses. |
exec |
Spawns a shell command substituting {TEXT} cleanly and safely (uses shell=False to prevent command injection). |
Integrating with CLI tools (e.g., pipe directly into llm {TEXT}, open a web search, or post to git commit -m "{TEXT}"). |
pipe |
Writes raw transcription bytes to a local named FIFO pipe. | Interfacing with custom CLI shell scripts, event listeners, or local terminal agents waiting for command buffers. |
socket |
Streams text directly over a TCP connection or local Unix Domain Socket. | Communicating with long-running daemons, remote servers, or external development container environments. |
file |
Appends transcriptions to a local file with customizable prefixes and optional UTC timestamps. | Automatic hands-free voice journaling, log keeping, standup note compilation, or task lists. |
dbus |
Emits a custom DBus signal containing the text on the session bus. | Triggering complex desktop notification actions, scripting custom desktop widget updates, or chaining custom system automation. |
http |
Sends a fast HTTP POST/GET request containing the transcription formatted inside a JSON template. | Streaming transcriptions directly to webhooks, database ingestion services, or remote HTTP endpoints. |
webhook |
Sends a signed, secure HTTP POST request with an HMAC-SHA256 signature generated using a shared secret. | Securely connecting dictation triggers to external APIs or home automation platforms (e.g., Home Assistant). |
speak |
Plays back the transcribed text aloud via the globally configured Text-to-Speech (TTS) engine. | Hearing the transcribed text spoken back to you directly, even without an active MCP server connection. |
chat |
Holds a running conversation with an OpenAI-compatible /v1/chat/completions server, sending prior turns as context and reading the reply back. |
Talking to a local LLM β Hermes, Ollama, llama.cpp β hands-free, with the answer spoken aloud, typed at your cursor, or copied to the clipboard. |
Tip
chat turns VoxCtrl into a voice front end for the same API Open WebUI uses. Enable your
server's OpenAI-compatible HTTP API, point chat_url at it, and speak. See
examples/targets-hermes-chat.toml and the
routing reference.
ββββββββββββββββββββββββββββββββ
β Desktop Shortcuts Portal β
β org.freedesktop.portal.* β
β GlobalShortcuts β
ββββββββββββββββ¬ββββββββββββββββ
β "your shortcut fired"
β (no keystroke data)
βΌ
ββββββββββββββββββββββββββββββββ
β Gesture Recognizer β
β (Hold / Toggle / Double) β
ββββββββββββββββ¬ββββββββββββββββ
β on_press(target_id)
βΌ
ββββββββββββββββββββββββββββββββ
β Recording Module (cpal) β
ββββββββββββββββ¬ββββββββββββββββ
β float32 raw audio chunks
βΌ
ββββββββββββββββββββββββββββββββ
β Speech Engine Backend β
β (whisper.cpp / Moonshine / β
β Parakeet TDT / Remote STT) β
ββββββββββββββββ¬ββββββββββββββββ
β (transcription, target_id)
βΌ
ββββββββββββββββββββββββββββββββ
β Output Command Router β
β (targets.toml) β
βββββββββ¬ββββββββ¬βββββββββ¬ββββββ
β β β
βΌ βΌ βΌ
ββββββββββββββββββββββββββββββββ
β Optional AI Post-processing β
β (Filler Removal / LLM API) β
βββββββββ¬ββββββββ¬βββββββββ¬ββββββ
β β β
βββββββββββββββ β βββββββββββββββ
βΌ βΌ βΌ
[inject / clipboard] [exec / pipe / file] [dbus / http / socket]
β β β
βΌ βΌ βΌ
Focused Editor Terminal / Scripting Integration Services
VoxCtrl provides a clean, native settings window and overlay environment:
-
General tab: Configure core system attributes, including the local MCP JSON-RPC server toggles and record timeouts.
-
Visual tab: A premium Cyber Obsidian interface that groups all aesthetic and presentation settings. It features an interactive Overlay Style Selector (supporting Voice Card, Waveform, Pulse Ring, Ocean Wave, Mono Bars, Neon Spectrum, Retro Terminal, Analog VU, or Disabled styles), toggles for displaying heads-up HUD overlays while speaking, Command Trigger Overlay toggles and duration sliders, and controls for sending system notifications on transcription. It also lets you configure if the Settings window should open automatically at launch or start minimized in the system tray.
-
Bug Report tab: Describe a problem, read the complete report VoxCtrl has assembled from it, and send it β filed for you with no GitHub account needed, opened as a prefilled GitHub issue, saved to a file, or emailed. What is collected and what never is are listed side by side above the form, and redaction works from an allowlist so a setting added later cannot leak by being forgotten. See docs/bug_reports.md.
VoxCtrl features a dynamic transparent overlay window β always-on-top and fully click-through β that renders floating real-time audio visualization above your desktop during dictation. Every style has its own identity, audio visualizer, active-target indicator, and animated load/unload transitions. The visual presentation is fully hot-swappable in the Visual Tab settings (which synchronizes across windows in real-time) and supports five unique visual options:
-
Ocean Wave (Default) π A glass tide pool at night with a glowing moon, rising bubbles, and three overlapping parallax wave layers (Deep Blue, Aqua Cyan, and Ice Teal).
- Voice Reactive Tide: Both the waterline and the wave amplitude swell dynamically in response to microphone sound levels, receding to a calm low tide when silent.
- Floating Buoy Target Tag: The active routing target label floats on a buoy that bobs on the wave surface.
- Fill & Drain Transitions: The water fills the pool when dictation starts and drains away when it ends.
-
Voice Card π³ A literal membership card: gold contact chip, embossed VOXCTRL branding, holographic sheen, and a 20Γ6 VU-meter LED dot matrix (greenβamberβred) lit bottom-up.
- Real VU Ballistics: Instant attack and slow decay, with a sensitivity curve tuned so even quiet speech lights the meter.
- Card Flip Transitions: The card deals in with a flip when dictation starts and flips back out when it ends, with an embossed
TARGETfield and a blinkingREC/INIT/PROCstamp.
-
Waveform π A green-phosphor oscilloscope ("OSC-01") with a graticule grid and a live scrolling line trace of your microphone signal, rendered with a phosphor glow. Includes a
TGT βΈtarget readout chip and switches to a blue sine sweep during AI post-processing. Powers on and off like a CRT, expanding from (and collapsing back into) a single scanline. -
Pulse Ring π A sonar/radar dial: a rotating sweep arm with a trailing wedge, expanding pulse rings that brighten with voice intensity, contact blips that flash as the sweep passes, and an audio-reactive core β paired with a pulsing "TARGET LOCK" plate showing the active routing target.
-
Disabled (None) β Turns off the transparent heads-up display entirely, relying purely on tray icon changes or system bus triggers for dictation feedback.
Whenever a voice command trigger is matched (e.g. "VoxCtrl notes Help me!"), VoxCtrl displays a temporary glassmorphism HUD overlay pill (β‘ NOTES βΈ Help me!) showing the target name and text payload summary. The display duration (default: 3s) and enable/disable toggles are configurable under Settings β Visual Tab.
- Foreground Focus Raising: If the settings page is already open but hidden behind other windows, clicking the β Settings button in the native system tray menu or double-clicking the system tray icon will trigger standard
show()andset_focus()commands to immediately bring the settings dashboard to the absolute foreground of the screen.
VoxCtrl features a native Model Context Protocol (MCP) server listening on a local Unix socket at /tmp/voxctrl-mcp.sock. This allows advanced LLM agents (such as Claude Desktop or Cursor) to interface directly with your voice and speak responses back to you.
transcribe_voice(timeout_seconds): Prompts the application to open your default recording device, capture speech, transcribe it using the Whisper engine, and return the raw text to the model. The argument is optional β omit it and VoxCtrl listens for the Record timeout configured in Settings β General.speak_text(text): Queues text to be spoken aloud locally on the user's host machine using the configured neural TTS engine.get_status(): Returns a JSON object with boolean states indicating whether the microphone is currently recording or the TTS engine is currently speaking.
VoxCtrl supports routing transcribed text directly to any local or networked MCP server via its Output Command Router using the mcp delivery type in targets.toml.
The client is fully standard-compliant (Option B, performing initialize -> notifications/initialized -> tools/call handshakes on socket connect) to guarantee maximum compatibility with strict third-party MCP servers.
You can declare generic MCP targets in your targets.toml or configure them through the GUI Settings window:
[[target]]
id = "self_speak"
label = "Synthesize Speech Loopback"
delivery = "mcp"
mcp_path = "/tmp/voxctrl-mcp.sock" # Optional custom socket or pipe path (defaults to standard socket/pipe)
mcp_tool = "speak_text" # The name of the MCP tool to call (defaults to 'speak_text')
[target.mcp_args]
text = "{TEXT}" # Custom arguments template (substitutes the transcription at {TEXT})VoxCtrl includes a Voice Command Router target (delivery = "command") that dynamically inspects dictated speech and reroutes text payload based on spoken target names.
- Trigger Phrase: Listens for
"VoxCtrl"(e.g."VoxCtrl","voxctrl","vox ctrl"). - Conversational Command Support: Accepts natural lead-in phrases (e.g. "VoxCtrl send this to my notes. I love you.", "VoxCtrl add this to my personal notes, help", or "VoxCtrl put this in Notes: hello").
- Target Resolution: Matches spoken target names against all configured target IDs and Labels, automatically prioritizing specific multi-word targets (e.g.
"Personal Notes"is matched before"Notes"). - Command UI Overlay: Displays a temporary purple/indigo HUD overlay (
β‘ TARGET βΈ Summary) showing the executed command target and text summary for a configurable duration (default: 3s). - Fallback: If no
"VoxCtrl"keyword is spoken, dictation types directly into your active window as normal.
VoxCtrl runs natively on Linux (optimized for CachyOS/Arch, Ubuntu/Debian, Fedora, and openSUSE). We support seamless standalone execution using a portable AppImage, which features a built-in installer to handle system integration.
chmod +x VoxCtrl-*-x86_64.AppImage
./VoxCtrl-*-x86_64.AppImageThat is the whole installation. Global shortcuts need no permissions, and
VoxCtrl registers its own .desktop entry and icon under ~/.local/share/ on
every Linux launch β no privileges, no install step.
Nothing has to be installed first β not even libfuse2: the AppImage's runtime
uses your system's FUSE 3, and extracts and runs itself when FUSE is
unavailable. It needs glibc 2.35 or newer (Ubuntu 22.04+, Linux Mint 21+,
Debian 12+, Fedora 36+, Arch); older distributions have to build from source.
The only thing that can need a package manager is the helper that types text
into other windows (wtype on Wayland, xdotool on X11). If it is missing, the
setup window says so and offers to install it, or shows you the command. You can
also do that step up front with ./VoxCtrl-*-x86_64.AppImage --install, which
installs those packages and nothing else.
Important
The installer does not touch keyboard permissions, and there is no step that does. Global shortcuts go through the XDG desktop portal, so nothing needs granting. The administrator prompt is for installing the packages above and nothing else.
Older VoxCtrl versions wrote /etc/udev/rules.d/99-voxctrl.rules, which let
every program running as your user read every keystroke on your system. The
installer now removes that rule if it finds it, and never creates it.
Why.
Note
VoxCtrl keeps watching: if shortcuts cannot reach it, it says so in the tray and in a notification rather than silently ignoring your keypress, and it starts working the moment the situation changes β without an app restart.
If you wish to compile the application and bundle a fresh, portable AppImage manually from source, run the dedicated compiler script:
chmod +x build_appimage.sh
./build_appimage.shThis compilation script:
- Restructures the workspace compiler toolchain, wrapping the local
appimagetoolto execute inside headless and FUSE-less build/sandbox environments using--appimage-extract-and-run. - Runs frontend compilation via Vite/Svelte and compiles the Rust Tauri backend.
- Automatically injects system GPU/CUDA library paths into the compiler environment for hardware-accelerated transcription (if compatible NVIDIA cards are present).
- Moves and exposes the final, standalone, portable AppImage directly to the root of the workspace as
VoxCtrl-x86_64.AppImage.
Once set up, you can execute the application in three ways:
- From Desktop Menu: Launch VoxCtrl directly from your desktop launcher or application drawer.
- Standalone Portable AppImage: Run the standalone AppImage executable in the root directory:
./VoxCtrl-x86_64.AppImage
- Helper Script Wrapper: Run the workspace helper script:
./voxctrl.sh
All configurations are stored locally inside ~/.config/voxctrl/.
Main application settings, including audio capture, UI styling, and the speech-to-text inference engine (whisper-cpp, moonshine, parakeet, or remote-openai):
{
"engine": {
"backend": "remote-openai",
"remote_openai": {
"endpoint": "http://192.168.1.50:8000/v1",
"api_key": null,
"model": "whisper-1",
"language": "auto",
"timeout_secs": 30
},
"whisper_cpp": { "model_size": "base", "device": "auto" },
"moonshine": { "model_size": "base", "language": "en" },
"parakeet": { "model_size": "tdt-0.6b-v3", "language": "auto" }
}
}Defines your Output Commands. The file and its [[target]] blocks keep their
original names on disk, so an existing config needs no changes:
format_version = "1.1"
[[target]]
id = "default"
label = "Focused Window"
delivery = "inject"
[[target]]
id = "notes"
label = "Meeting Journal"
delivery = "file"
file_path = "~/Documents/meeting_notes.md"
file_prefix = "- "
file_timestamp = true
file_timestamp_format = "%Y-%m-%dT%H:%M:%SZ"
[[target]]
id = "cmd_router"
label = "Voice Command Router"
delivery = "command" # Dynamically routes speech based on "VoxCtrl <target> <text>" keywordBinds hotkey gestures directly to target IDs (supports single or multiple sequential targets):
format_version = "1.1"
[[binding]]
id = "dictate_hold"
label = "Dictate into Focused Window (Hold)"
keys = ["KEY_LEFTMETA", "KEY_SPACE"]
gesture = "hold"
target_id = "default"
[[binding]]
id = "dictate_and_log"
label = "Type & Save Journal (Hold)"
keys = ["KEY_LEFTCTRL", "KEY_LEFTMETA", "KEY_SPACE"]
gesture = "hold"
target_id = "default" # Backward compatibility fallback (first target)
target_ids = ["default", "notes"] # Sequential delivery to both targets!
[[binding]]
id = "double_tap_dictation"
label = "Double-Tap & Hold to Dictate"
keys = ["KEY_LEFTMETA", "KEY_SPACE"]
gesture = "double_tap_hold"
tap_ms = 300 # Gap allowed between the two taps
hold_threshold_ms = 200 # Hold on the second tap before recording
target_ids = ["default"]Supported gestures are hold, toggle, double_tap and double_tap_hold.
See docs/hotkeys.md for how each behaves and how to tune the
double-tap timings.
VoxCtrl supports routing your speech to multiple Output Commands simultaneously using a single hotkey gesture!
When a multi-target binding is activated:
- Your speech is captured and transcribed once.
- The final text is delivered sequentially to each target specified in
target_ids. - The UI automatically ensures you cannot assign the same target more than once to prevent accidental duplicates.
Inside the Hotkey Binding Editor modal:
- Dynamic target selector fields let you add additional routing destinations using the
οΌ Add Targetbutton. - Already selected targets are automatically disabled in other dropdowns so you cannot select duplicates.
- Extra dropdown rows feature a clear
βbutton to remove them if added by accident.
To run the Svelte UI in standard hot-reloading development mode:
cargo tauri devnpm run build
npx tauri buildThis project is open-source and licensed under the MIT License.

