Dictate with MacWhisper
Press a key, speak, press again. The words land at your cursor.
Local dictation for Visual Studio Code on macOS, transcribed by the
MacWhisper app you already
own. Project page: bitman.ch/en/dictate-with-macwhisper.
By default the extension makes no network requests: it records with ffmpeg and
hands the audio to MacWhisper's command-line tool mw, which uses whatever
engine you selected in the app. With a local engine (Parakeet, WhisperKit,
Apple on-device speech) nothing leaves your Mac; if you selected a cloud
engine in MacWhisper, MacWhisper sends the audio there, as it does for any
transcription. The optional clean-up pass (off by default) sends the
transcript text, never the audio, to the Ollama server you configure; with
Ollama on your Mac it stays local, with a remote server the text leaves your
Mac.
- One shortcut:
ctrl+alt+space (⌃⌥Space) toggles recording.
- Inserts through the editor API: replaces the selection, works with
multiple cursors. The clipboard is used only as a fallback when no editor
can take the text, and a warning tells you.
- Works in Remote-SSH, WSL and dev-container windows (the extension runs on
your Mac, the text goes into the remote editor).
- No API keys, no telemetry, no model downloads. A few hundred lines of
TypeScript, shipped unminified in the extension package so you can read
what runs.
Requirements
- macOS with MacWhisper
from macwhisper.com (the Mac App Store build has no
mw tool).
- The
mw command-line tool: in MacWhisper open Settings → Advanced →
Command-Line Tool → Install. The extension also finds the copy inside
MacWhisper.app if you skip this step.
- ffmpeg for microphone capture:
brew install ffmpeg.
macOS asks once to let Visual Studio Code use the microphone. If you
declined, enable it under System Settings → Privacy & Security →
Microphone; until then the extension reports "No audio was captured".
- The shortcut must reach VS Code. If you use several keyboard layouts,
macOS binds ⌃⌥Space to "Select previous input source" and swallows it:
turn that off under System Settings → Keyboard → Keyboard Shortcuts →
Input Sources, or rebind the command in VS Code (Keyboard Shortcuts →
"Dictate with MacWhisper: Toggle").
Usage
| Action |
How |
| Start recording |
ctrl+alt+space, or click $(mic) Dictate in the status bar |
| Stop and insert |
press the shortcut again |
| Cancel without inserting |
command palette → Dictate with MacWhisper: Cancel |
While recording the status bar shows Recording…; while MacWhisper works
it shows Transcribing…. A tap shorter than 0.3 s inserts nothing and the
status bar says so for two seconds. A recording stops by itself after one
hour, so a crashed window cannot leave the microphone open; the status bar
and the macOS microphone indicator show that a recording is running. On an M-series Mac with Parakeet v3, ten seconds
of speech come back in about a second.
If no text editor is active when the transcript arrives, or the editor is
read-only, the text is copied to the system clipboard and a warning says so
(clipboard managers and Apple's Universal Clipboard see it there). Text is
never dropped silently. Each recording lives in a private temporary
folder that is deleted when the dictation ends, whatever the outcome.
Optional clean-up: punctuation by a local model
Dictation comes out as one unpunctuated run. If you have Ollama
on your Mac, the extension can send the transcript to a small local model that is
asked to add punctuation and capitalization and nothing else:
brew install ollama && brew services start ollama
ollama pull gemma3:4b
Then set macwhisperDictate.cleanup.endpoint to http://127.0.0.1:11434. On an
M4 Pro the pass took one to three seconds with a warm model. The answer is
accepted only if it contains exactly the dictated words in the same order
(case and punctuation aside) and no invisible, control or direction-changing
characters; if the model changed, dropped, added or reordered a word, did not
finish, answered with more than 1 MB, or did not answer within 20 seconds,
the raw transcript is used and a warning says so. This check catches changed words, not a meaning
changed by punctuation alone. The transcript goes only to that endpoint, over
plain HTTP unless you give an https:// URL. Models with a thinking mode
(qwen3) are slow here; gemma3:4b has none.
Settings
| Setting |
Default |
Meaning |
macwhisperDictate.language |
"" |
ISO 639-1 code (pl, en, de…), auto or multilingual. Empty or malformed uses MacWhisper's current language. |
macwhisperDictate.model |
"" |
engine:model-id from mw models list. Empty uses the model selected in MacWhisper. User setting only: a workspace, folder or remote machine cannot change it. |
macwhisperDictate.mwPath |
"" |
Path to mw. Empty auto-detects. |
macwhisperDictate.ffmpegPath |
ffmpeg |
Path to ffmpeg. The default looks in /opt/homebrew/bin, /usr/local/bin, then PATH. |
macwhisperDictate.audioDevice |
default |
avfoundation device name or index (ffmpeg -f avfoundation -list_devices true -i ""). User setting only. |
macwhisperDictate.cleanup.endpoint |
"" |
Ollama base URL for the punctuation pass; empty = off. A remote URL sends the transcript off your Mac. User setting only. |
macwhisperDictate.cleanup.model |
gemma3:4b |
Ollama model for the pass. User setting only. |
macwhisperDictate.cleanup.prompt |
"" |
Custom system prompt; empty = built-in (punctuation only). The word-for-word check still applies. User setting only. |
Why not just MacWhisper's own dictation hotkey?
Use it, it is great. MacWhisper's hotkey types into any app by simulating
keystrokes. This extension exists for the cases where that is the wrong
tool inside an editor: replacing a selection, multi-cursor, Vim mode and
remote windows. It is also a toggle rather than hold-to-talk, which some
people prefer for longer notes.
Questions and problems
Write to kontakt@bitman.ch or use the Q&A tab on the Marketplace listing. The
project page with FAQ: https://bitman.ch/en/dictate-with-macwhisper/#support
Development
npm install
npm test # core tests (uses the real mw and a Polish WAV fixture) + extension-host test
npm run package # builds the .vsix
Core logic lives in src/core/ and has no dependency on the vscode
module, so it is tested with plain node --test.
Not affiliated
MacWhisper is a product and trademark of Good Snooze. This extension is an
independent, MIT-licensed companion and is not endorsed by them.
License
MIT