Wispr Flow just raised $280 million at a $2 billion valuation. It is a push-to-talk dictation app: you hold a key, you talk, and the text lands wherever your cursor is.
I rebuilt the part of it I actually use in about 20 minutes with Claude Code. It runs entirely on my own machine, nothing I say leaves the computer, and when I timed the two side by side, mine came back faster.
This one is written for a complete beginner. You do not need to know Swift, and you do not need to understand the architecture. The entire build is two prompts and some clicking through permission dialogs.
What you end up with
A real macOS app that listens while you hold a key and types what you said into whatever window you are in. Speech to text that runs locally, a searchable history of everything you have dictated, and a dictionary you can teach so it stops mangling names.
The first prompt
I did not tell it how to build anything. I told it what I wanted, asked it to go look the product up, and asked what it would recommend for my machine.
I want to clone Whispr flow look up what this is I basically want it to be a push to talk dictation app What would you recommend for architecture based on my machine. We'll start with the skeleton then build this out into a proper MacOS application and add some cool branding
Start this way. Say what you want, let the model do the research and propose the shape, get to something that runs, then layer the real application on top once the skeleton works.
The architecture it came back with
Claude split it into six pieces. You genuinely do not need to know what any of this means to follow along, but it is worth seeing what a dictation app is actually made of:
- Shell — the app itself, and the little heads-up display with the waveform that pops up while you are talking.
- Hotkey — a
CGEventtap watching for the key you hold. I usedfn. - Audio — the microphone capture.
- Speech to text — the model that turns your voice into words.
- Cleanup — an optional small local model that adds punctuation and cuts the ums.
- Injection — putting the finished text where your cursor is.
For the speech engine it picked SpeechTranscriber, the one built into macOS 26. That choice is the reason this is free. It is on your machine already, so there is no API to call, nothing to pay for, and no model to download. Claude also flagged in its own research that NVIDIA's Parakeet V3 beats it on English accuracy, so it wired Parakeet up as an alternative I could pull from Hugging Face if Apple's engine turned out to be too weak.
Two things you will hit
Permissions. macOS will not let an app read your keystrokes or type for you until you approve it under System Settings, Privacy & Security, Accessibility. Claude tells you exactly what to add. If you already run another dictation app, give this one its own name and its own push-to-talk key so the two do not collide.
Text not appearing. Transcription succeeds, the logs say injection succeeded, and nothing lands in your editor. That is an accessibility API silent failure: Electron apps like Cursor return success and do nothing. Paste the log into Claude and it patches it.
Speed and accuracy against Wispr Flow
Once it worked I wanted numbers, so I had Claude build a small comparison window that records the same audio through every engine at once. Then I ran all three, including Wispr Flow itself, by reading its results out of its own database.
Time to transcribe the same clip:
- Parakeet: 0.27 seconds
- Apple's SpeechTranscriber: 0.48 seconds
- Wispr Flow: 0.91 seconds
One caveat, and Claude raised it before I did: reading Wispr Flow's timing out of its database adds latency that is not really the app's fault, so its number is inflated. Even generously, the gap is small. On accuracy it was closer still. Apple heard "clone" as "Cologne" and "rant" as "rent". Wispr Flow spelled its own name correctly, which is not surprising. All three of them fumble "Claude Code", which is the single phrase I say most.
The honest read is that the difference in speed and accuracy is marginal. I went with Apple's engine anyway, because it needs no download and works out of the box.
Turning it into a real app
At this point it was a floating waveform and a keyboard shortcut. Useful, but not something you would call an app. The second prompt is where it becomes one.
I did not write this prompt cold. I opened a separate Claude session that already knew the project and asked it what prompt I should give. Then I added the design direction myself, because I did not want another purple gradient voice app.
Now turn this into a proper macOS application. Not a menu bar utility. A real app: dock icon, app menu, a standard resizable window, a Settings window on Cmd+comma, and a double-clickable .app I can keep in Applications. Drop LSUIElement. Keep a menu bar item as well, for status and the hotkey while I'm working in another app - but it is secondary now, not the whole interface. The main window holds: - Past transcriptions, searchable, with copy on each one. - The live level meter while recording. - Start and stop. - A Dictionary. Settings holds the hotkey and the model. THE DICTIONARY A place I can teach it words it keeps getting wrong - names, jargon, product names, the people I work with. Add, edit, delete, and search. It should persist and be editable as a plain file as well as in the UI. Two entry types: 1. A word or phrase I want it to know. "Anthropic", "Vercel", "Supabase". 2. A correction pair - when you hear X, write Y. "cloud code" becomes "Claude Code". Implement both mechanisms, because one alone is not enough: First, bias the engine before it transcribes. Pass my dictionary words to the speech engine as context so it leans toward producing them - whatever the engine supports for this. Keep the list short when you pass it; long context makes these models drift and invent text on quiet audio. Second, run a correction pass on the text afterward. Whole-word, case-insensitive, longest match first. This is the guaranteed path - biasing is a nudge, not a promise, and it will not catch everything. The correction pass must handle words the model glues together. If I add "Claude Code" it has to catch "CloudCode" and "Cloud-Code", not just the spaced version. Match on optional whitespace or hyphen between the parts. Be careful not to corrupt real words. A correction for "Claude Code" must never touch "Cloudflare" or the ordinary word "cloud". Require the full pattern, and show me a warning in the UI if an entry I add looks like it would match something common. In the transcription history, show me when a correction fired and what it changed, so I can tell whether the dictionary is doing anything. Before you write any of it, define a design system and write it down as tokens I can point at later - color, type scale, spacing, corner radius, border, shadow, motion. Every view pulls from those tokens. No one-off values in the components. The direction is 1980s tape recorder. Portable field recorders and cassette decks - Sony TC-D5, Marantz PMD, Nakamichi, Braun. What that means concretely: Brushed aluminum and matte plastic surfaces. A muted palette - warm greys, off-black, cream, silver. One accent only: the red of a record light. Amber or green for level indicators. Physical controls. Buttons that look pressed rather than tinted. Real depth, hard edges, visible seams between panels. Silkscreen-style labels. Small, uppercase, tightly tracked, in a neutral grotesque. Segmented or monospaced numerals for counters and timings. The recording indicator is a VU meter with a needle, not a progress bar. Level and waveform read as analog instrumentation. Restraint over decoration. This should look like equipment, not like a theme. Do not use neon, vaporwave, synthwave, purple-and-pink gradients, glowing text, chrome lettering, or grid horizons. That whole aesthetic is overused and it is not what I am asking for. This is the sober, industrial side of the eighties. Show me the design tokens first and let me approve them before you build the views. The engine stays exactly as it is. This is the interface layer only.
Two things in that prompt are worth reusing. Asking for design tokens before any views get written keeps the app visually consistent instead of drifting per screen. And naming what you do not want is as useful as naming what you do. I banned neon, vaporwave, synthwave and purple-and-pink gradients explicitly, because that is where these models go by default.
The dictionary
Every dictation tool gets proper nouns wrong. Teach it a dictionary, and make it work two ways at once.
Before transcription, your words get passed to the speech engine as context so it leans toward producing them. That is a nudge and it will not always land. So after transcription there is a second pass that does find-and-replace on the result, whole word, longest match first. That one is guaranteed.
The details in the prompt matter more than they look. These models glue words together, so a correction for "Claude Code" has to catch "CloudCode" and "Cloud-Code" too. And it has to be careful in the other direction, because a sloppy rule for "cloud" would happily corrupt "Cloudflare" every time you typed it.
It works. I said "Claude Code" out loud, and the history showed the correction firing and what it changed, which is how you can tell the dictionary is doing anything at all.
What it looks like
Plain. It got the 1980s recorder feel in outline, and it is a long way from the reference photos I gave it. Claude could have done a better job here, and if I keep using this I will push it further. The engine underneath is what I actually cared about, and that part is genuinely good.
The repo
The whole thing is on GitHub: per-simmons/murmur-youtube. macOS is native Swift. There is a Windows build under windows/ in C# and Avalonia, using Parakeet, since Apple's engine is macOS only. Hand the repo to Claude Code or Codex and say "set this up on my machine".
Wispr Flow is still a good product and $15 a month is not much if you want something that works the second you install it. This is for when you would rather own it.