Voice-to-prompt for developers. Hold a button, speak, release — structured prompts on your clipboard in under a second.
Project description
Invoke
Voice-to-prompt for developers.
Hold a button, speak, release. Your words hit the clipboard (or auto-paste at your cursor) in under a second. GPU-accelerated local transcription via Whisper — no cloud round-trip for speech-to-text.
Optionally run your transcription through an AI reformatter to clean it up into structured prompts for Claude Code, Cursor, Windsurf, Copilot, or raw text.
Install
# CLI only (headless, any platform)
pip install getinvoke
# With GUI (system tray + overlay)
pip install getinvoke[gui]
# Or use pipx for isolated install
pipx install getinvoke
Note: The CLI command is
dictate, notinvoke, to avoid conflict with the pyinvoke task runner.
Quick Start
# Check your setup (GPU, mic, settings)
dictate health
# Run the setup wizard
dictate setup
# Start dictating (headless mode)
dictate run
# Start with GUI (requires [gui] extras)
dictate run # auto-detects GUI availability
Default workflow: Hold Mouse5 (forward side button) → speak → release → text on clipboard.
How It Works
YOU SPEAK into your mic
│
▼
┌─────────────────────────────┐
│ WHISPER (runs locally) │
│ Model: distil-large-v3 │
│ GPU (CUDA) or CPU │
│ No internet. No API key. │
│ │
│ Output: raw transcription │
│ "uh so like fix the um │
│ auth middleware thing" │
└──────────────┬──────────────┘
│
▼
┌─────────────────────────────┐
│ AI REFORMATTER (optional) │
│ │
│ Takes raw speech and │
│ reshapes it based on the │
│ selected MODE: │
│ │
│ Claude Code → conversational│
│ Cursor → @file references │
│ Commit → git commit msg │
│ Raw → just clean up speech │
│ none → SKIP (no AI call) │
│ │
│ Backend options: │
│ • openrouter (cloud API) │
│ • claude-cli (local CC) │
│ • ollama (fully local) │
│ • none (skip AI entirely) │
└──────────────┬──────────────┘
│
▼
┌─────────────────────────────┐
│ CLIPBOARD + AUTO-PASTE │
│ "Fix the auth middleware │
│ to validate JWT tokens │
│ before checking roles" │
└─────────────────────────────┘
Platform Support
| Platform | CLI | GUI (tray + overlay) | Installer | GPU |
|---|---|---|---|---|
| Windows | pip install getinvoke |
pip install getinvoke[gui] |
Download .exe | CUDA (NVIDIA) |
| macOS | pip install getinvoke |
pip install "getinvoke[gui]" |
Download .dmg | MLX (Apple Silicon) |
| Linux | pip install getinvoke |
pip install getinvoke[gui] |
pip install getinvoke[gui,wayland] |
CUDA (NVIDIA) |
Comparison
| Feature | Invoke | whisper.cpp CLI | nerd-dictation | macOS Dictation |
|---|---|---|---|---|
| Local Whisper | Yes | Yes | Yes | No |
| AI reformatting | 5 backends | No | No | No |
| Code-aware modes | 8 modes | No | No | No |
| Project context | Auto-detected | No | No | No |
| GPU acceleration | CUDA + MLX | CUDA/Metal | No | — |
| Privacy mode | Yes (fully offline) | Yes | Yes | No |
| Cross-platform | Win/Linux/Mac | Win/Linux/Mac | Linux | Mac only |
| pip installable | Yes | No | No | — |
Requirements
- Python 3.11+
- NVIDIA GPU (CUDA) or Apple Silicon (MLX) recommended — works on CPU but slower
- Windows, Linux, or macOS
CLI Commands
| Command | Description |
|---|---|
dictate run |
Start Invoke (auto-detects GUI vs headless) |
dictate run --headless |
Force headless mode |
dictate run --no-beep |
Start without audio feedback |
dictate health |
Check GPU, model, mic, API keys, config |
dictate devices |
List audio input devices |
dictate modes |
List available target modes |
dictate history |
View dictation history |
dictate setup |
Run setup wizard |
dictate setup --cli |
Force CLI wizard (no GUI) |
dictate config |
View all configuration |
dictate config mode cursor |
Set a config value |
dictate license status |
Check license status |
dictate license activate <key> |
Activate a license |
dictate install |
Create Windows Startup shortcut |
dictate transcribe <file> |
One-shot WAV transcription |
dictate logs |
View log file |
Configuration
Key Settings
| Setting | Default | Options |
|---|---|---|
reformatter_backend |
none |
openrouter, claude-cli, ollama, none |
mode |
claude-code |
claude-code, cursor, windsurf, copilot, raw, commit, pr |
whisper_model |
distil-large-v3 |
Any faster-whisper model |
whisper_device |
auto |
auto, cuda, cpu |
hotkey |
mouse5 |
mouse5, mouse4, ctrl+shift+d, or any key combo |
auto_paste |
false |
true = insta-dump at cursor |
audio_device |
system default | Device index from dictate devices |
beep_enabled |
true |
true / false |
sound_preset |
default |
default, subtle, arcade, minimal, icq, aim, dial-up |
language |
en |
en, auto, or any Whisper language code |
Set values quickly from the terminal:
dictate config mode cursor
dictate config reformatter_backend claude-cli
dictate config auto_paste true
AI Reformatter Backends
| Backend | Where it runs | What you need | Cost |
|---|---|---|---|
openrouter |
Cloud (OpenRouter API) | OPENROUTER_API_KEY |
~$0.001/dictation |
claude-cli |
Local (your Claude Code) | Claude Code installed | Part of your CC plan |
ollama |
Local (your machine) | Ollama running on localhost:11434 | Free, no internet |
none |
Skipped entirely | Nothing | Free — raw Whisper output only |
Target Modes
| Mode | What the AI does with your speech |
|---|---|
claude-code |
Formats as a conversational prompt for Claude Code |
cursor |
Adds @file references, structured for Cursor's chat |
windsurf |
Cascade-style prompt for Windsurf |
copilot |
GitHub Copilot Chat format |
raw |
Cleans up filler/grammar only — no prompt structure |
commit |
Turns your description into a git commit message |
pr |
Turns your description into a PR title + body |
Custom Hotkeys
The settings GUI has a Record... button to capture any key combo. Or set it from the CLI:
dictate config hotkey "ctrl+shift+r"
dictate config hotkey mouse5
Supports modifier combos (ctrl+shift+d, alt+f2), mouse buttons (mouse4, mouse5), and single keys.
Ollama Setup
# Install Ollama (https://ollama.com)
ollama pull llama3.2
# Configure Invoke to use it
dictate config reformatter_backend ollama
dictate config ollama_model llama3.2
# Default URL: http://localhost:11434
Custom Vocabulary
Boost Whisper recognition for domain-specific terms:
dictate config custom_vocab "KeyGrip,OpenRouter,pyproject,FastAPI,pynput"
History
dictate history # Recent entries
dictate history -n 20 # Last 20
dictate history -s "fix" # Search
History retention defaults to 30 days. Change with dictate config history_retention_days 90.
Audio Feedback
- Short high tick — recording started (hotkey pressed)
- Rising chirp — done, text is on clipboard / pasted
- Disable with
dictate run --no-beepordictate config beep_enabled false
Sound Presets
Choose from 7 sound themes:
| Preset | Vibe |
|---|---|
default |
Original Invoke sounds |
subtle |
Softer, lower tones |
arcade |
Retro game-style chirps |
minimal |
Single short ticks |
icq |
Classic ICQ vibes |
aim |
AIM buddy list chirps |
dial-up |
Modem handshake tones |
dictate config sound_preset icq
Preview all sounds in Settings > General > Sound theme > Preview.
Linux Notes
- Audio stream stays open to avoid ALSA/PipeWire latency on every hotkey press
- If using
pip installon modern Debian/Ubuntu, usepipx install getinvokeinstead (PEP 668)
X11
Auto-paste requires xdotool:
sudo apt install xdotool # Debian/Ubuntu
sudo dnf install xdotool # Fedora
Wayland
Wayland requires a few extra steps for full functionality. Run dictate health at any point to check your setup.
Mouse hotkeys (mouse4/mouse5)
pynput can't capture global mouse events on Wayland. Invoke uses evdev instead, reading directly from /dev/input:
# 1. Install the wayland extra
pip install getinvoke[wayland]
# 2. Add yourself to the input group, then reboot
sudo usermod -a -G input $USER
sudo reboot
Keyboard hotkeys (e.g. ctrl+shift+d) work on Wayland without any extra steps.
Clipboard
On Wayland, wl-clipboard is required so text lands on the native Wayland clipboard (not the X11 one):
sudo dnf install wl-clipboard # Fedora
sudo apt install wl-clipboard # Debian/Ubuntu
Auto-paste
Auto-paste works for XWayland apps (Electron apps like Signal, VS Code, Chrome) via xdotool. Install it as above.
For native Wayland apps on KDE or Sway, also install wtype:
sudo dnf install wtype
GNOME limitation: GNOME's compositor doesn't support the virtual keyboard protocol, so auto-paste only works into XWayland apps on GNOME. For terminals (Claude Code, etc.), auto-paste is not possible on Wayland — text is on your clipboard, paste manually with Ctrl+Shift+V.
| App type | Auto-paste works? |
|---|---|
| Electron apps (Signal, VS Code, Chrome) | Yes — via xdotool (XWayland) |
| Native Wayland apps on KDE/Sway | Yes — via wtype |
| Native Wayland apps on GNOME | No — paste manually with Ctrl+V |
| Terminal emulators | No — paste manually with Ctrl+Shift+V |
System Tray (GUI mode)
When installed with pip install getinvoke[gui], Invoke runs in the system tray with:
- State indicator (idle / recording / processing / error)
- Current AI backend + model displayed
- Mode switcher (right-click menu)
- License management
- Settings editor
- Open logs
- Quit
Use dictate-gui to launch without a console window.
Building the Windows Installer
See the installer README for details on building the .exe installer with PyInstaller + Inno Setup.
Development
pip install -e ".[dev,gui]"
ruff check src/ tests/
ruff format src/ tests/
pytest
Architecture
src/getinvoke/
engine.py # Core pipeline engine (FrontendProtocol + InvokeEngine)
app.py # GUI frontend wrapper (GuiFrontend + InvokeApp)
terminal.py # Rich terminal frontend (TerminalFrontend)
cli.py # Click CLI commands
setup_cli.py # Terminal-based setup wizard
clipboard.py # Copy + auto-paste via pynput
config.py # Settings from config.json / env vars / .env
context.py # Project context loader (18 file types + git)
feedback.py # Audio cues (beeps/chirps)
history.py # SQLite dictation history
hotkey.py # Global hotkey listener (mouse/keyboard)
license.py # Lemon Squeezy license validation (7-day trial)
license_gui.py # License activation dialog (tkinter, GUI only)
modes/ # 7 target mode system prompts
overlay.py # Recording/processing overlay (tkinter, GUI only)
recorder.py # Push-to-talk audio capture (sounddevice)
reformatter.py # LLM reformatting (OpenRouter/Claude CLI/Ollama/none)
settings_gui.py # Settings editor (tkinter, GUI only)
transcriber.py # Whisper model loading + transcription
tray.py # System tray icon + menu (pystray, GUI only)
updater.py # Auto-updater (GitHub releases + pip-aware)
window.py # Active window/file detection
wizard.py # First-run setup wizard (tkinter, GUI only)
installer/
invoke.spec # PyInstaller build config
invoke.iss # Inno Setup installer script
build.ps1 # Local build script
License
MIT — see THIRD-PARTY-LICENSES.txt for bundled dependency licenses.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file getinvoke-0.10.4.tar.gz.
File metadata
- Download URL: getinvoke-0.10.4.tar.gz
- Upload date:
- Size: 129.0 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
0b836e08605a08d0144dc5254631a532503cb1974f5d2314296c63362ade5bc6
|
|
| MD5 |
b44bff38ff3cea0432fc43b7cb44c0c3
|
|
| BLAKE2b-256 |
262a13e2b80e7aa9ec23ff828a215704100b9ba129eb0783d01f2904b18c4984
|
Provenance
The following attestation bundles were made for getinvoke-0.10.4.tar.gz:
Publisher:
publish-pypi.yml on zmroth/invoke
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
getinvoke-0.10.4.tar.gz -
Subject digest:
0b836e08605a08d0144dc5254631a532503cb1974f5d2314296c63362ade5bc6 - Sigstore transparency entry: 1851686986
- Sigstore integration time:
-
Permalink:
zmroth/invoke@19cd9d9649a933a3c8c5214dbb48ac42b651fee3 -
Branch / Tag:
refs/tags/v0.10.4 - Owner: https://github.com/zmroth
-
Access:
private
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish-pypi.yml@19cd9d9649a933a3c8c5214dbb48ac42b651fee3 -
Trigger Event:
push
-
Statement type:
File details
Details for the file getinvoke-0.10.4-py3-none-any.whl.
File metadata
- Download URL: getinvoke-0.10.4-py3-none-any.whl
- Upload date:
- Size: 124.7 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
87dce0977f35de6b4e4c9ce373821f592a9f6346787ebe1a6c24ce76eeada530
|
|
| MD5 |
bc1d2cb9efd922e3630f95285dbaa3b5
|
|
| BLAKE2b-256 |
dc471579f871bb70287d6ef0186c79cc9898d254f4cacc1051b069e4e371a2ec
|
Provenance
The following attestation bundles were made for getinvoke-0.10.4-py3-none-any.whl:
Publisher:
publish-pypi.yml on zmroth/invoke
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
getinvoke-0.10.4-py3-none-any.whl -
Subject digest:
87dce0977f35de6b4e4c9ce373821f592a9f6346787ebe1a6c24ce76eeada530 - Sigstore transparency entry: 1851687057
- Sigstore integration time:
-
Permalink:
zmroth/invoke@19cd9d9649a933a3c8c5214dbb48ac42b651fee3 -
Branch / Tag:
refs/tags/v0.10.4 - Owner: https://github.com/zmroth
-
Access:
private
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish-pypi.yml@19cd9d9649a933a3c8c5214dbb48ac42b651fee3 -
Trigger Event:
push
-
Statement type: