{"slug": "show-hn-multilingual-minimal-local-mcp-only-alternative-to-granola", "title": "Show HN : Multilingual Minimal Local (MCP only) alternative to Granola", "summary": "A developer publishing as IndianTinker released Quills, a downstream fork of Andrew Jones's macOS menu-bar recorder Quill that adds shared multilingual Parakeet v3 model support, a `quills models --download` pre-install command, `quills doctor` model diagnostics, pause/resume on Control–Option–Command–P, and a loopback-only read-only MCP server for meeting status, metadata, transcript search and transcript reads usable from Codex, Claude Code and OpenCode. Recording and transcription run on-device after a one-time model download, and the MCP server exposes no recording, editing or deletion tools and makes no outbound network requests. The fork ships as a single Swift binary with no app bundle, built via `swift build -c release` and installed to /usr/local/bin/quills.", "body_md": "A local macOS meeting recorder and multilingual transcriber, built on\n[Quill](https://github.com/digimata/quill) by Andrew Jones. Quills extends the\noriginal project with shared multilingual Parakeet v3 models, model setup and\ndiagnostics, and a local read-only MCP server for working with meeting transcripts\nfrom tools such as Codex, Claude Code, and OpenCode.\n\nThe menu-bar controls record your mic and system audio as separate tracks. When you stop, Quills transcribes both on-device and writes a speaker-tagged transcript. Recording and transcription stay on your Mac. Connected MCP clients may send transcripts to their own services or hosted models.\n\nQuills works on its own; VoiceInk and other transcription apps are optional.\nOn first transcription, it downloads its speech model if needed (an internet\nconnection is required for that download). After setup, transcription runs\noffline. You can also download the model in advance with `quills models --download`.\n\nQuills keeps the original Quill architecture: a single Swift binary, a feather menu-bar icon, and no app bundle.\n\nQuills is a downstream fork of [Quill](https://github.com/digimata/quill),\nwhich provides the original macOS menu-bar recorder, two-track audio capture,\nlocal transcription pipeline, and LaunchAgent support. The changes made in\nthis fork are documented below so the upstream work and downstream\ncontributions remain clearly separated.\n\nThe following additions were made in this fork:\n\n- **Shared Parakeet v3 model support** — reuse FluidAudio's shared`parakeet-tdt-0.6b-v3` cache, including models already installed by VoiceInk,\ninstead of maintaining a second private copy.\n- **Model download command** — added`quills models --download` to install the\nmultilingual Parakeet v3 model before an important meeting.\n- **Custom model locations** — added`transcription.model_dir` support so a\ncompatible model can be selected directly or through a symlink.\n- **Improved model diagnostics** —`quills doctor` checks the selected model\nlocation, and the menu bar reports model-loading and transcription progress.\n- **Documentation and installation updates** — documented shared-model reuse,\nfirst-use setup, custom model paths, and background launch-at-login usage.\n\n- **Local read-only MCP server** — added a loopback-only, multi-client MCP\nendpoint for meeting status, metadata, transcript search, and transcript\nreads. It has no recording, editing, or deletion tools and does not make\noutbound network requests.\n- **Menu-bar MCP lifecycle controls** — added MCP status plus Start, Stop, and\nRestart actions to the feather menu. Quills stops the MCP child before a\nnormal application exit, and launch-at-login starts both without an open\nterminal.\n\n- **Pause and resume** — pause both tracks from the menu or with\nControl–Option–Command–P. Paused sections become silence to preserve transcript\ntiming, and the feather dot turns orange until recording resumes.\n- **Accidental recording cutoff** — discard sessions with less than 10 seconds\nof unpaused capture before transcription or the completion hook runs.\n- **Copy MCP details** — copy the current endpoint, port, connection instructions,\ntools, resources, and suggested queries directly from the menu into an AI agent.\n\nThese changes are maintained here as downstream contributions on top of the upstream project. See the repository history for the individual commits and implementation details.\n\n```\ngit clone https://github.com/IndianTinker/quills.git\ncd quills\nswift build -c release\ncodesign --force --sign \"<your codesigning identity>\" --identifier com.indiantinker.quills .build/release/quills\nsudo install -m 755 .build/release/quills /usr/local/bin/quills\nquills models --download           # optional: prepare the model before first use\nquills install --launch-at-login   # optional: start in the menu bar on login\n```\n\nSee [Code signing (why it matters)](#code-signing-why-it-matters) — without this\nstep, Quills asks for microphone and System Audio Recording permission on every\nrecording.\n\nQuills uses the `quills` command and `/usr/local/bin/quills` install path.\nFor compatibility with existing Quill installations, it retains\n`~/.config/quill/config.json`, `~/Library/Application Support/Quill/status.json`,\nand existing `.quill-*` session markers. The signing identifier and LaunchAgent\nlabel are now `com.indiantinker.quills`. Migrating from Quill requires granting\nmicrophone and system-audio permissions again; subsequent updates should use\nthe same signing identity and identifier to preserve those permissions.\nThe MCP status JSON retains its `quill` field;\nlegacy `quill://` resource links remain readable alongside `quills://` links.\nNew LaunchAgent logs are `/tmp/quills.out.log` and `/tmp/quills.err.log`.\nThe upstream MIT copyright and license are preserved in [LICENSE](https://github.com/IndianTinker/quills/blob/master/LICENSE).\n\nThe menu's **Storage** submenu saves one of three audio retention settings:\n**Delete audio after transcription**, **Keep last audio** (both tracks of the\nnewest fully transcribed session), or **Do not delete anything** (the default).\nCleanup runs when the selection changes, after transcription, and at startup. Transcripts, metadata, and logs\nare kept. Pending, failed, partially transcribed, and pre-update recordings keep\ntheir audio, even when transcripts exist: an older session without the completion\nmarker is never made eligible just because it has a transcript. Changing the\nsetting applies immediately to eligible recordings; deleted audio\ncannot be restored by selecting a different option. The setting is stored as\n`audio_retention` in `~/.config/quill/config.json`, with values\n`delete_after_transcription`, `keep_last`, or `keep_all`.\n\nAfter pulling new Quills changes, build and sign first. Wait until recording and transcription finish before stopping the old LaunchAgent, installing the new binary, and registering the LaunchAgent again:\n\n```\nswift build -c release\ncodesign --force --sign \"<your codesigning identity>\" --identifier com.indiantinker.quills .build/release/quills\ncodesign --verify --strict .build/release/quills\nlaunchctl bootout gui/$(id -u) ~/Library/LaunchAgents/com.indiantinker.quills.plist 2>/dev/null || true\nsudo install -m 755 .build/release/quills /usr/local/bin/quills\nquills install --launch-at-login\n```\n\nWhen migrating an existing Quill installation, run\n`/usr/local/bin/quill install --uninstall` after building and signing, before\nstarting Quills. This removes the old `com.digimata.quill` LaunchAgent so both\napps do not start at login and compete for the MCP port. Keep the old binary\nuntil the new installation is verified.\n\nThe signed binary is not optional. `swift build` produces an ad-hoc, linker-signed\nexecutable with no stable code identity, and macOS privacy (TCC) binds permission\ngrants — microphone, System Audio Recording — to the binary's identity. An ad-hoc\nbinary has no usable identity, so macOS prompts for permissions on every single\nrecording and never remembers the grant.\n\nSign with a real codesigning identity once and the prompts stop: the first recording asks, every later recording is remembered. Rebuilds keep the grants as long as the same identity signs the new binary. List available identities with:\n\n```\nsecurity find-identity -v -p codesigning\n```\n\nAny Apple Development identity works; a self-signed code-signing certificate created in Keychain Access works too.\n\nThe last command starts Quills and its MCP server in the menu bar. The Terminal window can then be closed; the LaunchAgent keeps Quills running at login. The feather menu shows MCP status and provides Start, Stop, and Restart controls. Quills stops its MCP child before a normal exit. If the menu-bar parent is terminated unexpectedly, the child detects that its parent disappeared and closes its loopback server as well.\n\n**Requires:** macOS 15+ (Core Audio process taps for system audio — no\nvirtual device, no kernel extension). Apple Silicon recommended for\ntranscription speed.\n\n1. **Run it** (`quills` in a terminal, or the LaunchAgent).\n2. **Click the feather in the menu bar → Start recording.** First use prompts\nfor microphone and System Audio Recording permissions. While recording, the\nwhite feather shows a red dot at its bottom-right, the menu shows a\nrunning elapsed counter, and macOS shows the purple\nrecording indicator.\n3. **Pause private sections** with**Pause recording** in the menu or**Control–Option–Command–P (⌃⌥⌘P)** from any app. Use the same control to\nresume in the same session. The feather dot turns orange and the menu shows**paused** . Both tracks save silence during pauses, so private speech is\nexcluded while elapsed time and transcript timestamps stay aligned. Audio\ndevices remain connected, so macOS's recording indicator stays on. Pause\nhas no effect when no session is open; you can also stop a paused session.\n4. **Click → Stop recording** when the meeting ends. Transcription starts\nautomatically. The status bar shows model loading and transcription\nprogress; a notification fires when the transcript is ready.\n\nSessions with **less than 10 seconds of unpaused recording** are discarded\nwhen stopped: their audio folder is removed, no model is loaded or transcription\nqueued for them, and `on_stop` does not run. Exactly 10 seconds is kept. Paused\ntime does not count toward this minimum. Existing recordings are unaffected.\n\nOption-click the feather to start or stop recording. A single click or right-click opens the menu immediately.\n\nPress **Control–Option–Command–R (⌃⌥⌘R)** from any app to start or stop a\nrecording. This provides access even if macOS hides Quills in a crowded menu\nbar. The feather stays one fixed icon wide; status details live in its menu\nand tooltip. If another app has claimed the shortcut, Quills logs a warning\nand its menu control remains available. The shortcut needs no Accessibility\npermission.\n\nEach session lands in `~/Recordings/<yyyy.MM.dd-HHmm>/`:\n\n| File | Contents | \n|---|---|\n| `mic.caf` | your side (default input device, AAC) | \n| `system.caf` | everything the Mac played — the other side of the call (AAC) | \n| `meta.json` | start/end timestamps, duration, per-track start offsets | \n| `transcript.json` | canonical transcript — engine provenance + timed, speaker-tagged segments | \n| `transcript.md` | the same transcript rendered for reading | \n| `transcribe.log` | transcription progress/errors for this session | \n\nTwo tracks on purpose: speech models do better on clean single-source audio,\nand mic-vs-system is free two-party diarization — `me` vs `them` with no\nspeaker-identification model. CAF on purpose: unlike m4a, it needs no\nfinalization pass — if the process dies mid-meeting, everything already\nwritten is still readable.\n\nBuilt in, on-device, automatic. The engine is **Parakeet TDT 0.6B v3**\n(multilingual: 25 European languages plus Japanese) via\n[FluidAudio](https://github.com/FluidInference/FluidAudio)'s Core ML port.\nIt uses FluidAudio's shared user-level cache at\n`~/Library/Application Support/FluidAudio/Models/parakeet-tdt-0.6b-v3`. If\nanother app such as VoiceInk has already installed a compatible v3 bundle,\nQuills reuses those files. If the model is absent,\n`quills models --download` (or the first transcription while online)\ndownloads v3 into that same shared cache. Quills never keeps a second private\nmodel copy.\n\nThe **Models** submenu lists supported models, their language/size guidance,\nand whether they are installed. Click an installed model to select it; click\nan absent model to download and validate it before selecting it. Downloads run\nin the background, and failed downloads leave the previous selection in place.\nModels are stored in FluidAudio's shared cache, each in its own directory.\n\n| Model | Guidance | \n|---|---|\n| Parakeet TDT 0.6B v3 (default) | Fast, multilingual; recommended starting point | \n| Parakeet TDT 0.6B v2 | Fast, English only; 600M parameters | \n| Parakeet TDT-CTC 110M | English only; smaller, faster loading, less memory | \n\nSpeed and accuracy depend on hardware, language, and audio quality. These labels are selection guidance, not a measured accuracy ranking for meeting recordings. Whisper and other model families require additional engines and are not yet supported by Quills.\n\nUse **Browse for existing model…** to choose a model type and an existing\nFluidAudio-compatible Core ML folder. Quills checks that it loads, then saves\nthe path and reuses the files in place, including folders shared with another\napp or accessed through a symlink. Choose the matching type; a folder contains\nmultiple compiled `.mlmodelc` bundles and a vocabulary JSON file, rather than\none universal model file. An incomplete custom folder reports an error and is\nnever populated by automatic downloads. **Show selected model in Finder** opens\nits location.\n\nA model change takes effect at the next transcription session. A session already being transcribed keeps the same model for both tracks; queued sessions use the new selection. Transcript JSON records the model used. Files on disk are shared; loaded model instances in memory belong to each app separately.\n\nBefore a meeting, run this once to make model setup explicit:\n\n```\nquills models --download\nquills doctor\n```\n\nEach track is transcribed separately, shifted by its start offset so both\nshare one clock, and merged by timestamp. Before writing, Quills filters long,\nnearly identical microphone spans that overlap the same system speech, keeping\nthe system version as `them`. This reduces speaker playback appearing twice.\nReplies under five words, distinct speech, and later repetitions are preserved.\nIt is conservative and may leave echoes with substantially different recognition.\nThe feather pulses continuously during both model loading and transcription\n(recording still takes priority with a white feather and red dot). The dropdown also shows the selected model.\n\nShared model files do not mean shared live inference: Quills loads its own Core ML model instance and releases it when the queue drains. Reusing a model already loaded inside VoiceInk would require VoiceInk to expose an inference service that Quills can call.\n\nJobs run in a serial queue — you can\nstart a new recording while the last one transcribes. Unfinished jobs resume\non next launch (the filesystem is the queue: a session with `meta.json` but no\n`transcript.json` is pending). Failures append to the session's\n`transcribe.log` and never block later jobs.\n\nThe engine sits behind a small protocol; a Whisper engine (WhisperKit large-v3-turbo) is planned as the fallback / re-transcription option.\n\nOptional, at `~/.config/quill/config.json`:\n\n```\n{\n  \"recordings_dir\": \"~/Recordings\",\n  \"transcription\": {\n    \"enabled\": true,\n    \"engine\": \"parakeet\",\n    \"model\": \"parakeet-tdt-0.6b-v3\",\n    \"model_dir\": \"~/Models/parakeet-tdt-0.6b-v3\"\n  },\n  \"on_stop\": \"my-hook\"\n}\n```\n\n- `recordings_dir` — where sessions land. Resolution order:`--out` flag >\nconfig >`~/Recordings` .\n- `transcription.enabled` — set`false` to just record.\n- `transcription.model` —`parakeet-tdt-0.6b-v3` (default),`parakeet-tdt-0.6b-v2` , or`parakeet-tdt-ctc-110m` . The Models menu saves this.\n- `transcription.model_dir` — optional path to a**FluidAudio-compatible\nCore ML bundle matching the selected model type** . It can be a folder used by another local\ntranscription app, or a symlink to that folder. When absent, Quills uses the\nstandard FluidAudio shared cache.`quills models --download` and`quills doctor` use this selected path. Custom paths must already contain\na complete model. Selecting a built-in model in the menu clears the custom path.\n- `mic_voice_processing` — Apple's echo cancellation on the mic (default off).\nSet`true` when recording meetings through the speakers, so playback doesn't\nbleed into the mic track and get transcribed twice as \"me\". The trade: while\nthe voice unit is live, macOS ducks other playback slightly (`.min` ducking\nis configured, but it can't be zeroed). On headphones there's no echo to\ncancel, so raw capture is the better default.\n- `on_stop` — shell command spawned with the session directory as its\nargument,**after the transcript is written** (or right after recording if\ntranscription is disabled). Wire it to whatever comes next: summarization,\nfiling, indexing.\n\n```\nquills                        # run the menu-bar daemon (^C to quit)\nquills run --out <dir>        # custom recordings root (default ~/Recordings)\nquills doctor                 # check permissions, recordings folder, models\nquills models                 # list supported models and cache locations\nquills models --download      # pre-download/reuse the selected model\nquills models --download --model parakeet-tdt-ctc-110m # download without changing selection\nquills mcp --out <dir>        # run the local read-only MCP server directly\nquills install --launch-at-login\nquills install --uninstall\n```\n\nQuills includes a local, read-only [MCP](https://modelcontextprotocol.io/)\nserver for consuming meeting data from MCP clients. When Quills is running in\nthe menu bar, it starts the server automatically at:\n\n```\nhttp://127.0.0.1:47777/mcp\n```\n\nThe server binds only to loopback, reads only from the configured recordings folder and Quills’ local runtime-status file, and has no outbound network client. It exposes status, meeting metadata, transcript search, and complete transcript reads. It does not expose recording, editing, deletion, or any other write operation. The endpoint uses independent MCP sessions, so Claude Code, Codex, OpenCode, and other clients can connect concurrently to the same running Quills instance.\n\nThe `get_status` tool and `quills://status` resource include both Quills runtime\nstate and MCP connection details: state, loopback host, port, full endpoint,\ntransport, and read-only mode.\n\nUse the feather menu-bar icon to see whether MCP is running and to **Start**,\n**Stop**, or **Restart** it. Choosing **Quit Quills** stops the MCP child\nprocess before Quills exits. With `quills install --launch-at-login`, the menu\nbar app (and its MCP server) starts without leaving a terminal open.\n\nChoose **Copy MCP details** in the feather menu to copy a guide you can paste\ninto your AI agent. It includes the current endpoint and port, server state,\ntransport, connection steps, tools with example arguments, resources, and a\nquick workflow for finding transcripts. It works even when MCP is stopped,\nso you can copy its configuration before starting it. The MCP client must run\non the same Mac to reach the loopback endpoint.\n\nThe port can be changed in `~/.config/quill/config.json`:\n\n```\n{\n  \"mcp_port\": 47777\n}\n```\n\nThis server being local does not make a cloud MCP client local: a client that sends transcript content to a hosted model can still transmit that content. For end-to-end local processing, use a local MCP client and local model.\n\n- **Swift** — single SPM executable target\n- **Core Audio process tap** (`AudioHardwareCreateProcessTap` , macOS 14.2+) —\nsystem audio capture via a private aggregate device\n- **AVAudioEngine** — mic capture\n- **AVAudioFile** — streaming AAC encode into CAF\n- **FluidAudio / Parakeet** — on-device Core ML transcription\n- **NSStatusItem** — the whole UI\n\n- A global tap records *everything* the Mac plays — notification dings,\nmusic, all of it. Don't play Spotify during meetings (or ask for a\nper-process picker if it bothers you).\n- If recordings come out silent, check System Settings → Privacy & Security → Screen & System Audio Recording.\n- The first v3 download is about 600 MB. Run `quills models --download` on a\nreliable connection before recording an important meeting.\n- A model from another app must be the FluidAudio Core ML bundle for the selected Parakeet type;\nWhisper, GGUF, or other model formats cannot be loaded by Quills. To avoid\nduplication, point `transcription.model_dir` directly at it or use a\nsymlink, for example:`ln -s \"/path/to/model\" ~/Models/parakeet-v3` .\n- The binary embeds its Info.plist (`__TEXT,__info_plist` ) so TCC can\nattribute permissions to quills itself when running as a LaunchAgent.", "url": "https://wpnews.pro/news/show-hn-multilingual-minimal-local-mcp-only-alternative-to-granola", "canonical_source": "https://github.com/IndianTinker/quills", "published_at": "2026-11-15 11:23:20+00:00", "updated_at": "2026-11-15 11:54:21.392286+00:00", "lang": "en", "topics": ["ai-tools", "agent-protocols", "ai-products", "artificial-intelligence"], "entities": ["Quills", "Quill", "Andrew Jones", "IndianTinker", "Parakeet v3", "FluidAudio", "VoiceInk", "Codex"], "also_reported_by": [], "alternates": {"html": "https://wpnews.pro/news/show-hn-multilingual-minimal-local-mcp-only-alternative-to-granola", "markdown": "https://wpnews.pro/news/show-hn-multilingual-minimal-local-mcp-only-alternative-to-granola.md", "text": "https://wpnews.pro/news/show-hn-multilingual-minimal-local-mcp-only-alternative-to-granola.txt", "jsonld": "https://wpnews.pro/news/show-hn-multilingual-minimal-local-mcp-only-alternative-to-granola.jsonld"}}