NovaVoice
Local, offline voice dictation for Linux, macOS, and Windows. Hold a key, speak, release — the transcribed text appears in whatever app is focused. No cloud, no GPU.

Hold the dictation key (>0.5s) → speak → release → text appears
Powered by faster-whisper (CPU/int8). Works in browsers, terminals, IDEs, chat apps — anywhere the OS lets keystrokes reach the focused window.
Supported platforms
| OS | Hotkey default | Install | Status |
|---|
| Linux | Space | apt / snap / PPA / pipx / .deb / installer | Stable |
| macOS | Right Option | .dmg (Homebrew Cask coming) | Developer preview (unsigned) |
| Windows | Right Ctrl | .exe installer (winget coming) | Developer preview (unsigned) |
> Why Right Ctrl on Windows, not Right Alt? On many international layouts Right Alt acts as AltGr — used to type @, €, {}, [], \, ~, etc. Hijacking it would break normal typing. Right Ctrl is rarely used for typing, so it's the safer default. Every platform's hotkey is configurable in config.toml.
Quick install
One-line install on every major OS:
# macOS — via Homebrew tap
brew tap novafabric/novavoice && brew install --cask novavoice
# Windows — via winget (pending PR review at microsoft/winget-pkgs#371427)
winget install NovaFabric.NovaVoice
# Linux — via the apt repo
bash <(curl -fsSL https://raw.githubusercontent.com/novafabric/novavoice/main/install.sh)
# Cross-platform fallback — pip
pipx install novavoice
After install:
| OS | What's left |
|---|
| macOS | Right-click → Open the first time (unsigned dev preview); grant Accessibility + Microphone when prompted; hold Right Option to dictate. |
| Windows | If SmartScreen warns, click More info → Run anyway (unsigned dev preview); hold Right Ctrl to dictate. |
| Linux | sudo usermod -aG input "$USER" then re-login; systemctl --user enable --now novavoice.service; hold Space to dictate. |
Full per-OS guides: docs/macos-install.md, docs/windows-install.md. Status of every distribution channel lives in docs/distribution-status.md.
Other channels
If a one-liner above doesn't fit your environment, pick from the platform sections below.
macOS — alternatives
# Direct .dmg download (no Homebrew needed)
# https://github.com/novafabric/novavoice/releases/latest
# Open the .dmg, drag NovaVoice.app into /Applications, right-click → Open the first time.
Windows — alternatives
# Direct .exe download
# https://github.com/novafabric/novavoice/releases/latest
# Click "More info → Run anyway" if SmartScreen warns.
Linux — alternatives
# APT repo (Debian/Ubuntu)
curl -fsSL https://novafabric.github.io/novavoice/apt/KEY.gpg \
| sudo gpg --dearmor --yes -o /usr/share/keyrings/novavoice.gpg
echo "deb [signed-by=/usr/share/keyrings/novavoice.gpg] https://novafabric.github.io/novavoice/apt ./" \
| sudo tee /etc/apt/sources.list.d/novavoice.list
sudo apt update && sudo apt install novavoice
# Launchpad PPA (Ubuntu)
sudo add-apt-repository ppa:novafabric/novavoice
sudo apt update && sudo apt install novavoice
# Snap (works on most distros after `snapd` is installed)
sudo snap install novavoice --classic
# AUR (Arch / Manjaro / EndeavourOS)
yay -S novavoice # any AUR helper
# .deb download
# https://github.com/novafabric/novavoice/releases/latest
sudo apt install ./novavoice_*.deb
# pipx (any Linux)
sudo apt install libportaudio2 xdotool xclip pipx
pipx install novavoice
Usage
NovaVoice runs silently in the background. The same CLI works on every platform.
| Command | What it does |
|---|
| Hold the hotkey, speak, release | Transcribe and inject text into focused app |
novavoice status | Daemon state, model, hotkey, backend, uptime |
novavoice start / stop | Manage the daemon |
novavoice doctor | Per-platform prerequisite check |
novavoice inject "hello" | Type text without recording (debug) |
novavoice remote | Forward voice typing to a remote SSH host |
novavoice remote --stop | Disconnect active remote session |
novavoice enroll | Calibration wizard for VAD / silence settings |
On macOS and Windows the NovaVoice tray icon changes color to reflect state (idle / recording / transcribing / remote / error).
Voice commands (v0.3.0)
Speak natural commands while [commands] enabled = true (default). The grammar classifier routes recognised intents to key sequences instead of typed text:
| Say | Action |
|---|
| "undo" / "undo 3 times" | Ctrl+Z (×N) |
| "save file" | Ctrl+S |
| "delete 2 words" | Ctrl+Backspace ×2 |
| "delete 3 lines" | Delete 3 lines |
| "go to line 42" | Ctrl+G → "42" → Enter |
| "comment selection" | Ctrl+/ |
| "copy" / "paste" | Ctrl+C / Ctrl+V |
| "scratch that" / "delete that" | Remove text back to last sentence |
Everything else is typed verbatim.
Configuration
config.toml lives in the platform's standard config dir:
| OS | Path |
|---|
| Linux | ~/.config/novavoice/config.toml |
| macOS | ~/Library/Application Support/novavoice/config.toml |
| Windows | %APPDATA%\novavoice\config.toml |
[stt]
model = "tiny.en" # tiny.en (fast) | base.en (more accurate, slower)
[hotkey]
# "auto" → Space (Linux) / right_option (macOS) / right_ctrl (Windows).
key = "auto"
hold_threshold_ms = 500
[audio]
sample_rate = 16000
max_record_seconds = 90
[tray]
enabled = "auto" # default true on macOS/Windows, false on Linux v0
[general]
log_level = "INFO"
# --- v0.3.0 additions (all optional — defaults shown) ---
[commands]
enabled = true # voice command grammar (undo, save, go to line N, …)
profile = "auto" # "auto" | "vscode" | "vim" | "default"
[filters.disfluency]
enabled = true # remove filler words, repeated phrases, "scratch that"
[accessibility]
vad_threshold = 0.01 # silence threshold — run `novavoice enroll` to calibrate
min_silence_ms = 500 # minimum silence to end a recording
pre_speech_padding_ms = 200 # prepend ring-buffer audio to catch voice onset
[streaming]
enabled = true # emit stable partial transcripts while you speak
partial_interval_ms = 300
[remote]
default_host = "" # SSH host for `novavoice remote`
ssh_port = 22
agent_port = 9875
key_file = "" # path to SSH private key (optional)
How it works
┌──────────────┐ ┌──────────────┐ ┌──────────────────┐
│ Hotkey hook │──▶│ Audio (16kHz │──▶│ faster-whisper │
│ (per-OS API) │ │ PortAudio) │ │ (CPU / int8) │
└──────────────┘ └──────────────┘ └────────┬─────────┘
│
┌────────────▼────────────┐
│ disfluency filter │ ← v0.3.0
│ grammar classifier │ ← v0.3.0
└────────────┬────────────┘
│
┌────────────▼────────────┐
│ Text injector │
│ (local or SSH remote) │ ← v0.3.0
└─────────────────────────┘
│
└─────────── daemon process ────────────────────────────
▲
JSON-RPC over Unix socket / named pipe
│
┌─────────┴─────────┐
│ CLI / tray │
└───────────────────┘
Every platform-specific surface (keyboard hook, text injection, autostart, IPC, paths, permissions, tray) lives behind a single Protocol-based abstraction in src/novavoice/platform/. Adding a fifth platform is a matter of writing one more sub-package.
Remote voice forwarding (v0.3.0)
Local machine Remote machine
───────────────────────────────────── ──────────────────────
microphone → daemon → transcript ──SSH──▶ novavoice-agent → injector
tunnel (types into remote app)
Start: novavoice remote user@remote-host
Stop: novavoice remote --stop
Only the transcript text travels over SSH — audio never leaves the local machine.
Build from source
git clone https://github.com/novafabric/novavoice
cd novavoice
uv sync
uv run pytest tests/ -v
Platform-specific installers:
# macOS — produces dist/NovaVoice-.dmg
./scripts/build-macos.sh
# Windows — produces dist/NovaVoice--windows-x64.exe
./scripts/build-windows.ps1
# Linux .deb
./scripts/build-deb.sh
CI builds the unsigned .dmg and .exe on every PR that touches the relevant code paths.
Troubleshooting
novavoice doctor — first stop. Tells you what's missing on the current OS.
- macOS: see
docs/macos-install.md for Gatekeeper / Accessibility / Microphone.
- Windows: see
docs/windows-install.md for SmartScreen / antivirus / privacy.
- Linux: confirm you're in the
input group; check journalctl --user -u novavoice.service -f.
License
Apache 2.0 — see LICENSE.