Open source, local-first voice dictation for Apple Silicon Macs.
Hold Fn, talk, release, and the transcribed text lands in whatever text field is focused. Transcription runs entirely on your Mac with on-device models. No audio is uploaded, no transcripts leave your machine, no account is required.
OpenWords is fully open source under the MIT license. Every binary, script, and config file that runs on your machine lives in this repository, so the privacy claims are auditable rather than marketing. No cloud, no telemetry, no subscription, no paywalled features.
- Truly open source. MIT licensed, with the full source for the listener, the SwiftUI desktop app, the install scripts, and the DMG packaging pipeline in this repo. You can read, audit, fork, and modify every line.
- Local-first, not local-as-a-feature. Transcription uses on-device models (Parakeet via Core ML, Apple Speech, or WhisperKit). Audio never touches a server. This is the architecture, not a toggle.
- Runs on base Apple Silicon, not only maxed-out machines. Battery-conscious presets include a 110M Parakeet model and Apple Speech, so an 8GB M1 MacBook Air is a first-class target, not an afterthought. Heavy Whisper presets are blocked below 24GB RAM to prevent accidental memory spikes.
- A dictated workflow, not an always-listening bubble. Hold
Fnto record, release to transcribe and paste. There is no floating "always on" UI watching your mic. - One tool, multiple backends. Parakeet TDT v3 (default), Parakeet v2, Parakeet 110M, Apple Speech, and WhisperKit large / turbo fallbacks, all switchable from the CLI or the desktop app.
- Smart formatting built in. Filler removal (
um,uh,erm) and spoken punctuation (comma,full stop,new paragraph) run locally before paste. - Free, in every sense. No accounts, no paid tiers, no feature gating. If you want a hosted or proprietary dictation product, those exist already. OpenWords is for people who want the opposite.
- You hold
Fn. OpenWords records from the microphone into a local WAV file. - You release
Fn. OpenWords transcribes locally with the selected model preset. - OpenWords applies smart formatting and pastes the final text into the active text field.
The default preset is parakeet-v3, chosen for a strong quality, speed, and battery balance on base Apple Silicon Macs.
For most users, download OpenWords-<version>-arm64.dmg from the releases page, open it, and drag OpenWords.app into Applications. Launch it, pick a model, and click Start Listener.
From source:
./scripts/install.sh
openwords startThen hold Fn and talk.
- Local batch transcription on macOS.
- Hold-to-dictate
Fnhotkey. - Compact recording/transcribing overlay.
- Automatic paste into the active text field.
- Battery-conscious model presets.
- CLI commands for start, stop, update, status, and model switching.
- Configurable backend, model, and language.
- Apple Silicon Mac.
- macOS 14 or newer.
- Xcode Command Line Tools.
- Swift Package Manager.
screen, included with macOS.
Install Xcode Command Line Tools if needed:
xcode-select --installFor normal users, download OpenWords-<version>-arm64.dmg from a release, open it, and drag OpenWords.app to Applications.
Launch OpenWords, choose a model, and click Start Listener. The app manages configuration and listener start/stop without requiring the CLI.
The desktop app includes:
- First-run setup wizard for permissions and launch-at-login.
- Model and language selection.
- System, light, and dark appearance modes.
- Local usage stats.
- Update checks against GitHub Releases.
The first launch may ask for macOS permissions:
- Microphone
- Accessibility
- Input Monitoring, if macOS asks for it
If the app is unsigned, macOS may require right-clicking OpenWords.app and choosing Open the first time. Public release builds should be signed and notarized before broad distribution.
From a cloned checkout:
./scripts/install.shThe installer builds OpenWords, creates ~/.config/openwords/openwords.env, and installs command wrappers into ~/.local/bin.
Add ~/.local/bin to your PATH if it is not already there:
export PATH="$HOME/.local/bin:$PATH"Then start the background listener:
openwords startCheck setup:
openwords doctorYou can also run directly from the checkout:
./scripts/openwords.sh startmacOS must allow the terminal app that launches OpenWords in:
- System Settings > Privacy & Security > Microphone
- System Settings > Privacy & Security > Accessibility
- System Settings > Privacy & Security > Input Monitoring, if macOS asks for it
Accessibility is required so OpenWords can paste the final transcript into the active app.
You can check the current permission state with:
swift run openwords --diagnose permissionsIf dictation records but does not paste, Accessibility or Input Monitoring is usually the missing permission.
Hold Fn to dictate. Release Fn to transcribe and paste.
Useful commands:
openwords start
openwords stop
openwords restart
openwords status
openwords update
openwords versionDirect checkout equivalent:
./scripts/openwords.sh statusOpenWords applies a small local cleanup step before pasting:
- Removes common fillers:
um,uh,erm,er,ah,hmm. - Converts spoken punctuation:
full stop,period,comma,question mark,exclamation mark,exclamation point,colon,semicolon. - Converts
new lineandnew paragraph. - If sentence punctuation is immediately followed by a filler, both are removed. Example:
hello full stop um actually continuebecomesHello actually continue.
This is intentionally conservative and runs fully locally.
List supported batch presets:
openwords models listShow the current preset:
openwords models currentShow a local recommendation based on chip, RAM, and battery state:
openwords recommendSwitch presets:
openwords models use parakeet-v3
openwords restartOr apply the local recommendation:
openwords models use recommended
openwords restartOpenWords can also auto-use the lighter parakeet-110m preset when a listener starts on battery below the configured threshold. This is enabled by default at 20%.
OpenWords does not hot-swap models in the middle of an active dictation. Changing models can trigger model load/download work and change latency, so the battery saver decision is made when the listener starts or restarts.
Available presets:
| Preset | Backend | Power | Notes |
|---|---|---|---|
parakeet-v3 |
FluidAudio/Core ML | Balanced | Works on 8GB+ RAM. On 8GB, parakeet-110m is still recommended for extra headroom. |
parakeet-v2 |
FluidAudio/Core ML | Balanced | Works on 8GB+ RAM. English-only recall option. |
parakeet-110m |
FluidAudio/Core ML | Saver | Available on all Apple Silicon Macs. |
apple-speech |
Apple Speech | Saver | Available on all Apple Silicon Macs, macOS 26+ for the current path. |
whisper-large-v3 |
WhisperKit CLI | High | Requires 24GB+ RAM. High-accuracy fallback. |
whisper-large-v3-turbo |
WhisperKit CLI | High | Requires 24GB+ RAM. Faster Whisper fallback. |
OpenWords stays batch-only: it records first, then transcribes after Fn is released.
OpenWords blocks model presets that are too heavy for the detected installed RAM. This avoids accidental high-memory model loads on base machines.
8GB Macs can use Parakeet. OpenWords recommends parakeet-110m on 8GB machines to reduce memory pressure and battery use, but it still allows parakeet-v3 and parakeet-v2. Heavy Whisper presets are blocked below 24GB RAM.
For base Apple Silicon Macs, start with parakeet-v3. It uses Core ML and avoids the heavier Whisper path by default.
Use parakeet-110m when battery life, memory pressure, or thermals matter more than maximum accuracy.
Use Whisper presets only when you specifically want to compare quality or need Whisper behavior. They can use more energy and memory.
openwords recommend reads only privacy-safe local details: chip name, installed RAM, and battery/AC state. It ignores serial numbers and hardware identifiers.
Battery saver is controlled by:
OPENWORDS_BATTERY_AUTO_SAVER=1
OPENWORDS_BATTERY_SAVER_THRESHOLD=20Set OPENWORDS_BATTERY_AUTO_SAVER=0 or turn off the desktop app toggle to keep your selected model even at low battery.
Language support depends on the selected backend:
parakeet-v3: best OpenWords default. Supports multiple Latin-script language filters in FluidAudio, including English, Spanish, French, German, Italian, Portuguese, Dutch, Polish, Czech, Romanian, and Russian-related filters. English variants such asen-INare treated as English.parakeet-v2: English-only.parakeet-110m: lighter Parakeet preset; best treated as English-first until benchmarked per language.apple-speech: depends on Apple Speech support and installed language assets on the user’s macOS version.- Whisper presets: broad multilingual support, but heavier on battery and memory.
The desktop app exposes common language choices. The config file can still be edited manually for advanced language codes.
OpenWords currently uses batch transcription: it records one WAV file, transcribes it after Fn is released, then pastes.
FluidAudio also includes sliding-window ASR managers with roughly 15-second default windows and overlap handling for longer/realtime-style audio. That is the right path if OpenWords needs multi-minute dictation with lower memory spikes. For now, short-to-medium passages are the intended use; long-form dictation chunking is on the roadmap.
Edit:
~/.config/openwords/openwords.env
Default configuration:
OPENWORDS_BACKEND=parakeet
OPENWORDS_MODEL_PRESET=parakeet-v3
OPENWORDS_PARAKEET_VERSION=v3
OPENWORDS_LANGUAGE=en
OPENWORDS_POWER_MODE=balanced
OPENWORDS_BATTERY_AUTO_SAVER=1
OPENWORDS_BATTERY_SAVER_THRESHOLD=20Parakeet treats language values starting with en as English, so en, en-US, and en-IN all use English decoding.
WhisperKit mode requires whisperkit-cli at /opt/homebrew/bin/whisperkit-cli, or set:
OPENWORDS_TRANSCRIBER=/path/to/whisperkit-cliBy default, logs are stored under:
~/Library/Application Support/OpenWords/logs
Normal logs do not include transcript text. Audio debug recordings and raw transcript debug files are opt-in:
OPENWORDS_SAVE_DEBUG_AUDIO=1
OPENWORDS_LOG_TRANSCRIPTS=1Those debug files may contain dictated text or audio. They are ignored by git and should not be shared publicly without review.
Run tests:
swift run openwords-testsBuild:
swift build --product openwordsBuild a DMG:
./scripts/package-dmg.shThe packaging script is part of the open-source repo. It builds OpenWords.app, embeds the listener binary, and creates dist/OpenWords-0.1.0-arm64.dmg with macOS hdiutil.
For a public release, sign and notarize the app/DMG with Apple Developer credentials before uploading it to GitHub Releases.
The repository includes .github/workflows/release.yml.
To publish a release:
git tag v0.1.0
git push origin v0.1.0GitHub Actions builds the DMG and uploads it to the GitHub release for the tag.
The desktop app checks https://github.com/siddvoh/openwords/releases on launch and from the app menu. When a release has a .dmg asset, the app can download it to Downloads and open it for installation.
Production silent/in-place self-updating should use Sparkle once the app is signed and notarized.
Check the app version:
swift run openwords --diagnose versionMIT. See LICENSE.
OpenWords is open source and will stay that way. The entire codebase, desktop app, install scripts, and packaging pipeline are MIT licensed and live in this repository. Contributions are welcome, see CONTRIBUTING.md. For security-sensitive reports, see SECURITY.md.