Two hotkeys. Two kinds of voice input. Local by default, cloud only when you choose it.
Quill is a free, open-source voice dictation app for Windows. macOS platform hooks and build scaffolding are included, but speech recognition is still wired to the packaged Windows runtime, so macOS is not yet functional end to end; see the macOS tester brief. Quill keeps two independently configurable global shortcuts active at the same time:
| Hotkey | Behavior |
|---|---|
| Dictation | Inserts the completed transcript when you stop, exactly as spoken. No cleanup. |
| Scribe | Holds a short trailing window, resolves spoken self-corrections, removes filler, applies punctuation, and types only the final wording. |
The hotkey is the mode switch. There is no settings menu to open while you are working.
Quill is an independent project. It is not affiliated with Wispr Flow, Willow Voice, WhimprFlow, Svara, or any other commercial dictation product.
Quill is currently an engineering preview:
- The trailing-buffer and final-insertion contracts are implemented and covered by standalone tests.
- The Tauri v2 shell, tray/updater/autostart configuration, settings UI, floating overlay, local-provider detection, hotkey polling, text injection, recovery checkpoints, bundled CPU whisper.cpp server, optional CUDA runtime, microphone capture, and Windows Dictation/Scribe session loop are in source.
- Dictionary entries support spoken-word biasing and literal word/snippet replacement. Accepted Scribe edits can produce an optional dictionary suggestion; Add and Dismiss are implemented, and dismissed pairs are capped and can be cleared from Dictionary settings.
- The desktop React bundle builds successfully.
- A native Windows production binary has been compiled and manually exercised with CUDA. The complete Notepad, VS Code, and Discord application matrix and macOS verification are still pending.
This status is intentionally explicit: do not treat v0.1.0 source as a
finished signed release yet.
Say:
Write down one two three five — no wait, four and five.
Dictation types:
Write down one two three five — no wait, four and five.
Scribe types:
Write down one two three four and five.
Dictation keeps rolling transcription warm while the shortcut is active, then inserts the complete verbatim transcript when the user releases or unlocks it. Scribe holds the same complete utterance, resolves corrections, and opens a review draft before any text reaches the cursor.
Scribe detects whether the captured target is email, chat, an AI prompt, notes, or general text and sends the raw transcript to your selected cleanup provider with the matching "polish, don't invent" instructions. Email may gain a greeting and sign-off; other registers do not. Every register forbids new facts, commitments, offers, or constraints, and the detected writing style can be changed in the review window to regenerate the draft.
Optional nearby-text context lets Scribe compose replies from the conversation around the caret or rewrite selected text. It is off by default, never reads password fields, and always keeps the review step before insertion. With Gemini selected, included editor text is sent to Gemini; local cleanup keeps it on the device. Quill learns aggregate per-app presentation preferences from accepted drafts, but never stores the drafts themselves as examples.
Cleanup output is never injected silently. Every Scribe activation opens a
review window with the raw transcript and the cleaned draft side by side;
text reaches the cursor only after you explicitly accept it (or edit it and
accept). Discard is always one click away. This human-in-the-loop step is
what closes the gap left by removing the earlier strict word-provenance
gate, which had blocked legitimate rewrites like hei → Hey. A
lightweight sanity guard also swaps the LLM output for a safe local draft when
the prompt would exceed its reserved context budget, the provider returns a
missing or malformed text field, generation stops at the output-token limit,
the model returns nothing or balloons past 3× the input word count, or the draft
introduces new promise, availability, proposal, or follow-up language that was
absent from the transcript.
- Windows 10/11 x64
- macOS 12+ is the intended target. Hotkeys, insertion, and build scaffolding are implemented, but the ASR runtime packaging is incomplete and the app has never been verified on Mac hardware. Do not treat macOS as supported yet; see docs/macos-testing.md.
- A microphone
- About 75 MB–1.6 GB for a whisper.cpp model
- Optional NVIDIA acceleration: about 700 MB to download and 1.25 GB installed
- Optional Scribe provider:
- Ollama
- LM Studio, Jan, or llama.cpp server exposing an OpenAI-compatible endpoint
Scribe does not choose a cleanup model automatically. After connecting Ollama, the user explicitly selects one of Quill's evaluated options:
| Scribe model | Download | Clear minimum | Trade-off |
|---|---|---|---|
| TurboSpeak 1.7B | ~1.1 GB | 8 GB system RAM, 2 GB free RAM, 1.1 GB disk | Fast on CPU; less reliable on complex corrections |
| Qwen 2.5 7B | ~4.7 GB | 16 GB system RAM, 8 GB free RAM, 4.7 GB disk | Stronger corrections and register-aware rewriting; slower on CPU |
A dedicated GPU is optional for both. Dictation never uses the cleanup model.
These are conservative minimums shown inside Quill's Voice settings. Actual whisper.cpp usage varies with backend and quantization; CPU mode requires no dedicated VRAM.
| Model | Download | Minimum GPU memory | CPU-only memory | Best fit |
|---|---|---|---|---|
tiny.en |
75 MB | 1 GB VRAM | 2 GB free RAM | Fastest; basic notes |
base.en |
142 MB | 1 GB VRAM | 2 GB free RAM | Balanced baseline |
small.en |
466 MB | 2 GB VRAM | 4 GB free RAM | Recommended for 4 GB GPUs |
medium.en |
1.5 GB | 5 GB VRAM | 8 GB free RAM | Higher accuracy; slower |
distil-large-v3 |
1.5 GB | 5 GB VRAM | 8 GB free RAM | Fast, high-accuracy English long-form transcription |
large-v3-turbo |
1.6 GB | 6 GB VRAM | 10 GB free RAM | Best quality/speed tradeoff |
Quill disables a model in the selector when its verified model file is not installed, preventing an unavailable choice from breaking speech-engine startup. English shows English-only models; Auto-detect and other languages show only compatible multilingual models.
- Node.js 20+
- pnpm 10+
- Rust stable (
rustup,cargo, and platform Tauri prerequisites) - CMake 3.20+
- Git
- SDL2 development files for
whisper-stream - Windows: Visual Studio Build Tools 2022 and WebView2
- macOS: Xcode Command Line Tools
See the current Tauri prerequisites for operating-system packages.
apps/
desktop/ React + Vite UI and Tauri v2 Rust core
src-tauri/
src/asr.rs whisper.cpp sidecar boundary
src/streaming.rs Timed-word representation shared by speech providers
src/cleanup.rs local LLM discovery, prompt, sanity guard
src/hotkeys/ poll-only Windows/macOS hotkey state
src/injection/ SendInput / CoreGraphics text insertion
prototypes/
scribe_buffer.py dependency-free trailing-buffer prototype
test_scribe_buffer.py canned correction and safety tests
scripts/
build-whisper.ps1 Windows whisper.cpp/CUDA build
build-whisper.sh macOS whisper.cpp/Metal build
| Layer | Choice | Why |
|---|---|---|
| Desktop shell | Tauri v2 + React + TypeScript | One UI and command surface; Windows is verified and macOS remains incomplete |
| Recognition | whisper.cpp | CPU runtime bundled on Windows; CUDA is an optional verified download; macOS Metal packaging is not yet wired into the app runtime |
| Text commit | Final clipboard paste | The target editor changes only after the user stops speaking |
| Speech recognition | Local whisper.cpp, Groq, or Gemini 3.5 Transcribe | Every provider inserts after release |
| Scribe cleanup | Ollama, OpenAI-compatible localhost, Gemini, or disabled | Every draft still passes the same guards and review window |
| Windows hotkeys | GetAsyncKeyState polling |
No system-wide keyboard hook |
| Windows insertion | Clipboard paste | Reliable Unicode insertion after transcription completes |
| macOS hotkeys | CGEventSourceKeyState polling |
Global state without an event tap keyboard hook |
| macOS insertion | CoreGraphics events + clipboard | Works through the standard Accessibility permission path |
| Updates | Tauri updater + GitHub Releases | User-confirmed updates from signed release artifacts |
Install JavaScript dependencies:
pnpm installRun the standalone cleanup contract:
python prototypes/test_scribe_buffer.py
python prototypes/scribe_buffer.pyRun the desktop UI in a browser:
pnpm dev:desktopBuild the desktop frontend:
pnpm buildThe helper scripts clone the upstream project into ignored third_party/ and
copy the resulting whisper-stream binary into Tauri's sidecar directory.
Windows (bundled CPU runtime plus a separately packaged optional CUDA runtime):
./scripts/build-whisper.ps1macOS with Metal:
./scripts/build-whisper.sh metalSpeech models are not bundled with the installer. On first launch Quill selects
and downloads the compatible medium model automatically, with progress shown
in the setup sheet and sidebar. Models can still be changed or removed from
Voice → Compare and download models. Quill stores them in the platform
application-data models/ folder and verifies each SHA-256 digest before use.
NVIDIA users can likewise download the optional CUDA runtime from Voice →
Compute backend. Quill verifies the archive before installation, and selecting
CUDA without the pack keeps transcription available on CPU with a visible status.
After installing the Tauri prerequisites and building the whisper sidecar:
pnpm tauri:buildTauri's Windows NSIS configuration uses currentUser, so the installer does
not require administrator rights. A macOS .app/.dmg target is configured,
but its ASR resource layout is incomplete and it has not been verified on Mac
hardware.
Quill needs:
- Microphone access to capture speech.
- Accessibility access to paste/type into the active application.
The signed application must include matching usage-description strings and entitlements. Unsigned local builds may need permissions removed and re-added after each bundle identity change.
Before creating a public release:
- Generate a Tauri updater signing key and replace
REPLACE_WITH_TAURI_UPDATER_PUBLIC_KEYintauri.conf.json. - Add the private updater key/password as GitHub Actions secrets.
- Add the Windows code-signing certificate configuration.
- Add Apple Developer ID, Team ID, certificate, and notarization credentials.
The release workflow is intentionally manual until those secrets are present. Updates are offered to the user; Quill never installs one silently during a recording session.
Quill contains no telemetry or analytics client. Local usage statistics, when implemented, will be stored only on the device. Network requests are limited to:
- localhost cleanup-provider discovery and inference;
- user-triggered model downloads;
- GitHub Releases update checks.
Read CONTRIBUTING.md before opening a pull request. Security issues should follow SECURITY.md.
GNU AGPL-3.0-or-later
Cloud processing is always opt-in. Groq transcription uses
whisper-large-v3; Gemini transcription uses gemini-3.5-transcribe in
Verbatim mode for Dictation and Smart mode for Scribe. Both upload the
completed recording only after the shortcut is released and do not type live.
Gemini Scribe cleanup uses gemini-3.1-flash-lite and receives transcript text
plus optional bounded editor context. API keys are stored in Windows Credential
Manager or macOS Keychain rather than in Quill's settings file. Adding a key
never changes the active provider.