Local, on-device dictation for macOS. Press ⌥+Space, talk, and watch your words stream live into whatever text field has focus. Press ⌥+Space again to stop. All transcription happens on-device via FluidAudio and NVIDIA's Parakeet models running on CoreML — no audio ever leaves your Mac.
Grumble also records meetings: it detects when Zoom, Teams, or a browser meeting is using your microphone, records both sides of the call, and produces a speaker-tagged transcript with an optional local-LLM title and summary. See Meetings.
Requires macOS 14.4+. Install with Homebrew:
brew install --cask fcjr/fcjr/grumbleOr download Grumble.dmg from the latest release and drag Grumble to Applications.
Or with Nix flakes:
nix profile install github:fcjr/grumbleOr in a nix-darwin or home-manager flake config, add the input and package:
{
inputs.grumble.url = "github:fcjr/grumble";
# then, in a nix-darwin module (links the app into /Applications/Nix Apps):
{ pkgs, inputs, ... }: {
environment.systemPackages = [
inputs.grumble.packages.${pkgs.system}.default
];
}
# or in a home-manager module:
{ pkgs, inputs, ... }: {
home.packages = [ inputs.grumble.packages.${pkgs.system}.default ];
}
}Nix installs are updated through Nix, not Sparkle: Grumble detects that it's
running from the Nix store and disables the in-app updater (the store is
read-only), so update by bumping the flake input (nix flake update grumble).
- A menu bar app (no Dock icon) registers a global ⌥+Space hotkey (customizable via menu bar icon → Change Hotkey…).
- While listening, microphone audio is fed to FluidAudio's streaming ASR engine (Parakeet Unified 0.6B by default — a true streaming variant of the Parakeet TDT 0.6B model with live partial token updates).
- Partial transcripts are typed into the focused text field as you speak. When the model revises earlier words, only the changed suffix is backspaced and retyped.
Grumble can record meetings and turn them into speaker-tagged transcripts, entirely on-device:
- Detection — when a meeting app (Zoom, Teams, Webex, Slack, Discord, FaceTime) starts using the microphone, recording starts automatically. Browsers (Google Meet lives there) ask first via a notification. Policies are per-app and configurable from the Meetings window; recording can also be started manually from the menu bar.
- Capture — two tracks: your microphone (with Apple's echo canceller, so
speaker playback doesn't bleed in) and system audio via a CoreAudio process
tap (macOS 14.4+, needs the one-time System Audio Recording permission).
Audio lands in
~/Library/Application Support/Grumble/Meetings/. - Transcription — after the meeting, each track is transcribed with the offline Parakeet TDT model. The mic track is you; the system track is diarized with NVIDIA's streaming Sortformer so each remote speaker gets their own label. Everything is merged into one timeline in a local SQLite database (GRDB, append-only migrations).
- Titles, summaries, and names — optionally, a local Qwen3-4B model (opt-in ~2.3 GB download on first use, via MLX) writes a title and summary and names speakers from context clues. Auto-applied names are marked and always editable; your edits are never overwritten.
- Browsing — menu bar → Meetings… lists every meeting with full-text search, per-speaker transcript with click-to-play audio, markdown export, audio retention settings, and delete.
Nothing about a meeting ever leaves your Mac: capture, diarization, transcription, and summarization all run locally.
Requires macOS 14.4+, Xcode, xcodegen,
and just (brew install xcodegen just).
just run # generate project, build, and launch
just open # generate project and open in Xcode
just clean # remove generated project and build artifacts- Model download — on first launch the selected model (~600 MB for the 0.6B Parakeet Unified) is downloaded from HuggingFace and cached. The menu bar icon shows a download indicator while this happens.
- Microphone — you'll be prompted the first time you start dictation.
- Accessibility — required so Grumble can type into other apps. macOS will prompt; enable Grumble under System Settings → Privacy & Security → Accessibility.
- System audio — needed for meetings, so the far side of a call can be captured. The first recording triggers the prompt; enable Grumble under System Settings → Privacy & Security → Screen & System Audio Recording. Recording can't start without it.
- Summarization model — optional, and only downloaded (~2.3 GB) when you turn on meeting summaries from the Meetings window.
Push a tag like v0.2.0 and CI does the rest: builds and signs the app
(version taken from the tag), notarizes the DMG, uploads the DMG and the
Sparkle update zip to a GitHub release, publishes the Homebrew cask to
fcjr/homebrew-fcjr, regenerates the
signed appcast at grumble.computer/desktop/darwin/appcast.xml, commits it
together with the flake's nix/version.json pin, and redeploys the site.
The same tag also releases to the Mac App Store, end to end: CI builds the
GrumbleAppStore target (sandboxed, no Sparkle — the store owns updates),
uploads it, creates the store version, attaches the build once Apple
finishes processing it, sets What's New from the tag annotation (falling
back to a stock message), and submits for review; the version releases
automatically after approval. Signing is cloud-managed: the export re-signs
the archive with an Apple Distribution certificate created on demand
through the App Store Connect API key, which therefore needs Admin access
(App Manager alone cannot use cloud-managed certificates). To run the same
flow locally: APP_STORE_CONNECT_KEY_FILE=/path/to/AuthKey.p8 APP_STORE_CONNECT_KEY_ID=… APP_STORE_CONNECT_ISSUER_ID=… just appstore appstore-submit.
Repository secrets used: MACOS_CERTIFICATE_P12 (base64 Developer ID .p12),
MACOS_CERTIFICATE_PASSWORD, APP_STORE_CONNECT_API_KEY (.p8 contents),
APP_STORE_CONNECT_KEY_ID, APP_STORE_CONNECT_ISSUER_ID,
SPARKLE_PRIVATE_KEY, CLOUDFLARE_API_TOKEN, CLOUDFLARE_ACCOUNT_ID,
RELEASER_APP_ID and RELEASER_APP_PRIVATE_KEY (GitHub App with write
access to the tap).
Switch models from the menu bar icon → Model:
| Model | Latency | Notes |
|---|---|---|
| Parakeet Unified 320 ms | lowest | re-encodes often, highest CPU |
| Parakeet Unified 640 ms | low | same accuracy as 320 ms, cheaper |
| Parakeet Unified 1120 ms | medium | default — best accuracy/latency balance |
| Parakeet Unified 2080 ms | high | highest throughput |
| Parakeet EOU 120M 160 ms | lowest | tiny model, fastest |
All of FluidAudio's true-streaming variants are currently English-only. The multilingual Parakeet TDT v3 model only supports offline/sliding-window transcription, so it can't stream partial tokens live.
Apache 2.0 — see LICENSE. © 2026 Left Shift Logical, LLC.