Inspiration

Voice dictation is one of the fastest ways to turn an idea into text, but many dictation products require a subscription or send speech and transcripts to a cloud service. I wanted a tool I could trust with everyday Korean, English, and mixed-language work: press a shortcut, speak naturally, and get polished text in the app I am already using, even when the network is unavailable.

That became Parrot, a private, local-first macOS dictation app built around one focused interaction: hold shortcut -> record -> local speech recognition -> local cleanup -> paste

What it does

Parrot runs as a native macOS menu-bar app. The user holds a configurable global shortcut, speaks, and releases it. Parrot transcribes the recording locally with WhisperKit, optionally cleans the text with an embedded Qwen3 model running through MLX Swift LM, validates the result, and pastes it into the active application.

It supports Korean, English, and automatic language selection, with Raw, Rule Only, and Local Clean output modes. If local cleanup fails or times out, Parrot safely falls back without silently sending content to a remote service. Audio and transcript content are not persisted by default, and the original clipboard is restored after paste.

How we built it

Parrot is a native SwiftUI and AppKit application for Apple Silicon. Its core is an explicit dictation-session state machine that coordinates microphone capture, WhisperKit transcription, deterministic or MLX-based cleanup, validation, and text insertion. ASR and cleanup inference are serialized to stay within the memory envelope of a 16 GB Mac.

The app downloads models only with explicit user approval, pins the cleanup model to a specific revision, verifies installed files with SHA-256 manifests, and never uses the network as an automatic runtime fallback. A signed, stable app bundle gives macOS a consistent identity for microphone, Accessibility, and Input Monitoring permissions.

I used Codex throughout the Build Week development workflow to turn the product idea into phased acceptance gates, implement and test the native Swift architecture, audit privacy boundaries, diagnose macOS signing and TCC behavior, and fix concurrency bugs in rapid hold-to-talk input. Codex also helped build content-free benchmark tooling so latency and failure modes could be measured without committing private audio or transcripts.

Challenges we ran into

The hardest problems were at the boundaries between an ML prototype and a dependable macOS utility. A raw Swift executable and a packaged app can receive different macOS privacy permissions, so I had to establish a stable signed-bundle lifecycle before treating manual tests as valid. Fast shortcut presses also exposed races between permission checks, microphone startup, key release, and stale asynchronous callbacks. The session now reserves its generation synchronously and rejects cancelled, stale, or too-short recordings before transcription or paste.

Local LLM cleanup introduced a different safety problem: a fluent response is not necessarily a faithful one. Parrot checks for empty or excessively changed output, language changes, and loss of protected terms or code tokens, then falls back to the raw transcript when validation fails.

Accomplishments that we're proud of

We successfully built a highly reliable, low-latency dictation pipeline that runs entirely on-device without compromising user privacy. Successfully serializing WhisperKit and MLX-driven Qwen3 inference within a strict 16 GB memory footprint on Apple Silicon (while preventing systemic UI freezes) was a major technical milestone for me.

What we learned

Local-first is more than choosing local models. It requires explicit data lifetimes, content-free diagnostics, predictable failure behavior, model integrity checks, and careful integration with the operating system. I also learned to separate synthetic structural tests from claims about real speech quality: private owner-reviewed fixtures are the evidence for accuracy, while public synthetic fixtures keep the repository reproducible without exposing personal content.

What's next for Parrot

Parrot is currently a personal alpha with a working offline core path. Next I will finish representative-app compatibility testing, a 100-cycle reliability soak, and longer owner dogfooding before calling it a general early-adopter release. The product will remain local-first: cloud transcription, accounts, telemetry, and automatic cloud fallback are outside the default path.

Built With

  • appkit
  • mlx
  • qwen3
  • swift
  • swiftui
  • whisperkit
Share this project:

Updates