Public beta · Solo Build
Yohoho
A voice dictation app. Press a key, talk, and your words land as text. Nothing leaves your device.
Design + build · Python, ONNX, Swift · Current build v0.9.2 · Updated Jul 2026
- Local
- The speech model runs on your machine. No account, no API key, nothing uploaded.
- Free
- Dictation is free and unmetered on every platform.
- Built in
- Eight days, from the first commit to a signed Mac beta.
Why this exists
Typing is fast if you have spent your life getting fast at it. Voice is just natural, and it keeps up with your thoughts. Once I started using dictation, and once most of my work became a conversation with AI, the keyboard started to feel like the bottleneck.
The tools that do this well are expensive and full of features I never touch. I wanted the 20% that does the 80%: press a hotkey, talk, and the text appears where you were already typing. Free, and running entirely on your own machine.
It all started as a couple of hours in a shell to find out whether I could build it myself and here we are. In fact, this case study was dictated with it.
Where it landed
Yohoho is in public beta, with a first set of users I'm collecting feedback from. It ships as a Python package that installs on any device and runs behind a hotkey, and as a Mac app. Both run a small cleanup model over the raw Parakeet output, so what lands on the page reads cohesive and not as a transcript.
Where this is going
Yohoho should be ubiquitous, seamless and delightful to use.
- A native Windows and Mac app
- Multi language support and per app dictionary
- A choice of local models, not just the one default
How it got here
The decisions, dead ends and small wins worth keeping. Not everything, just what mattered.
-
Jun 2026 product
It started on Windows, in about two hours
I run Windows for work, Mac for personal projects, and Linux for VPS boxes. VoiceInk does not run on Windows, and Wispr Flow was one more subscription I could not justify next to everything I already pay for. What actually decided it was how far local speech models have come. Parakeet in particular is small enough to run on your own machine and accurate enough to trust. So one evening I wired it to a hotkey in Python: press a button, speak, get text. It worked well enough that I kept using it the next day.
-
Jun 2026 build
Whisper was the obvious choice, and it lost
Every dictation project starts at Whisper, so I did too. On my CPU it ran slower than the speech itself, roughly 0.8x realtime: talk for ten seconds, wait twelve to see the words. So I stopped assuming and raced the candidates on the laptop I actually use, not on a GPU I don't have. Parakeet came back at about nine times realtime from a 660 megabyte file, and accurate enough to trust. The most consequential technical decision in the project was settled by a stopwatch.
-
Jun 2026 build
The version that typed "wordsmashedtogether"
The first output path pressed keys one at a time, like a ghost at your keyboard. Under real use it dropped spaces and fused words, and a transcript you have to proofread is worse than typing it yourself. The fix was to stop typing: put the transcript on the clipboard, send one paste, put your old clipboard back. You lose the letter-by-letter theater. In exchange, every word arrives intact, every time.
-
Jun 2026 build
One portable core, thin shells on top
Yohoho was born on Windows and I still need it there, so the one thing I could not afford was writing the product twice. The split that fell out: one Python core that listens and transcribes, identical on every platform, and a thin native shell on top that owns only what the operating system cares about, the hotkey, the microphone, the paste, the menu bar.
The Mac shell is Swift and AppKit. It keeps the core warm as a long-lived child process and talks to it over a small binary protocol I wrote by hand: a four-byte length prefix, a little JSON, then raw audio. Adding a platform means writing another shell, not another product. The architecture is not foresight. It is just the shape the constraint left behind.
What it costs
Two languages, a framing protocol that has to stay byte-identical on both sides, and an embedded Python runtime baked into the app bundle so it runs on a Mac that has never seen Python. That is a lot of machinery to avoid writing a transcription engine twice, and it only pays off if the second platform actually ships. Which is exactly why a native Windows app is next in the pipeline.
-
Jun 2026 design
The command line is still wearing the old face
The very first version used system toasts. Recording started. Recording done. Pasting. Then the command line got this, a horizontal dot-matrix bar, which was the best I could come up with at the time and is still exactly what it ships today. The Mac app went somewhere else entirely and never looked back, so the two now disagree about what Yohoho looks like. The version numbers say the rest: the Mac app is at 0.9.2, the command line is at 0.4.0.
-
Jun 2026 design
The caret macOS could not find
The obvious place for a listening indicator is where the words are about to land, at the text caret. I spent a while trying to put it there, and on the apps that cooperate it felt right.
The problem is that macOS will not tell you reliably where the caret is. A terminal would not report it. VS Code and Zed would not report it. So the indicator would appear correctly in some apps, and nowhere at all in the ones I use most, which is worse than not doing it. I would rather ship one thing that works everywhere than a nicer thing that works sometimes.
The cursor was available and I turned it down on purpose. Text lands at the caret, not at the pointer. Putting a recording indicator on a pointer that roams across three monitors, while the words are quietly going somewhere else entirely, would tell people the wrong thing about where their sentence is about to appear.
-
Jun 2026 build
macOS trusts your terminal, not your tool
A dictation tool needs two sensitive grants: the microphone, and permission to press paste on your behalf. On macOS that trust attaches to the app that launched the process. For a Python script, that is whatever terminal you happened to start it from.
Grant it in one terminal and it is broken in the next. Update the terminal and the grant silently dies. Nothing inside the script can fix this, because the operating system does not consider the script to be the thing it is trusting. I patched around it for a while, and every patch just moved the failure somewhere less predictable.
This constraint, more than any feature, is why the native Mac app exists. A signed app bundle is something macOS will trust directly, so the grant finally sticks to the product instead of to the room it was launched from.
The permission I almost asked for twice
The first onboarding asked for three permissions. Reading Apple's behavior more closely showed that Accessibility already covers both the hotkey listener and the synthetic paste, so Input Monitoring came out entirely. One less scary dialog, and nothing was lost.
-
Jun 2026 design
The ticker bar that did not survive
Before the ring settled, status ran across a horizontal dot-matrix ticker, with the letters sampled into a seven-row grid and long messages scrolling like an LED sign. It reads beautifully in a design file. On a panel that is on screen for four seconds, nobody finishes reading it.
-
Jun 2026 design
Two directions I killed
A drifting starfield for the idle state, and a literal waveform for speaking. The starfield was calm and said nothing about whether the app was actually listening. The waveform said it plainly and looked like every other audio tool ever made.
-
Jul 2026 design
Why it is a dot matrix
When I picture sound as a digital thing, I picture a dot matrix. That is not analysis, it is just the first version of it I ever saw, in the Winamp visualiser on a Windows machine when I was a kid. Yohoho got a ring of dots because that is what listening looks like to me.
Getting it to feel alive took longer than choosing it. The version I kept solves a specific problem: when speaking hands back to idle, the bloom used to vanish into black and leave a dead beat in the middle of the animation. It now melts into a faint always-on ring with the sparkle rising on top of it, so there is never an empty frame. I built a small harness with sliders for the handoff overlap, the resting glow and the noise gate, and tuned it against my own voice rather than guessing.
The part that was pure taste
None of this makes dictation more accurate. It is the difference between an app that works and one you do not mind having on screen all day, and it is the part I would not hand to anyone else.
-
Jul 2026 build
Cancelling something that cannot be cancelled
Double-tapping Escape throws away a sentence mid-thought, and it has to feel instant. The core does not cooperate: it processes one utterance at a time in a blocking loop, so by the time you ask, the work is already in flight and there is nothing to interrupt.
How it actually works
It does not cancel. Every session carries a generation number, and results are gated on the way out, so an abandoned session finishes quietly in the background and its text never pastes. From the outside it feels like a clean cancel. Underneath, nothing was cancelled at all.
-
Jul 2026 build
A window that must never take focus
The status panel has one hard rule: it can never take the keyboard from the app you are dictating into, because the moment it does, your words go to the wrong place.
Holding that rule cost three fights. A normal window steals focus, so the panel became a non-activating one that refuses to become key or main and ignores the mouse entirely. SwiftUI's TimelineView, which I reached for to drive the animation, froze inside that kind of window, so the ring runs on an explicit sixty-frames-a-second timer instead. And Apple's translucent material renders flat and grey on any inactive window, which is what this window always is. The panel is pitch black by constraint before it was ever black by taste.
Designed in, not tested in
Focus safety is built into how the window is constructed, not checked afterwards. Even the toast that warns you about Escape exists from the moment the window is created, because adding it later would resize the panel, and a resize is one more chance to steal focus.
-
Jul 2026 build
A second model, only if you want one
Speech recognition gives you exactly what you said, including the false starts and the filler. An optional second model, about two gigabytes, runs locally at temperature zero and tidies that into the sentence you meant. It is off by default, and if it is not installed the raw transcript is used instead.
Why it runs as its own process
Two gigabytes is too much to hold hostage for a feature you might use twice a day, so the cleanup model runs as a separate process that is killed after ten minutes idle and restarts on demand. If it crashes twice in quick succession it parks itself and stops trying, rather than thrashing in the background while you work. And it is never allowed to hang the pipeline: the worst case is capped at fifteen seconds to load and twelve to answer, then the raw transcript goes through instead. Slow, but never stuck, and never silent.
-
Jul 2026 design
The ship, and why it is water
The name came from Brook, who sings yo ho ho in One Piece, which I was watching at the time. Once a pirate name sticks you owe it a ship, so the site has one: a galleon on the same dot grid as the panel, riding waves that roll right to left. Click the water and it swells. Under reduced motion it holds one still frame.
I did not pick water because it fit the pirate joke. I picked it because water takes the shape of whatever you put it in and keeps moving whether or not you are watching. If I had to pick an element, I would pick that one.
It only occurred to me afterwards that I had built the same thing twice. Yohoho is one portable core poured into a different shell on each platform, and your voice is a fluid thing that ends up shaped by whatever app happens to have focus.
The Winamp part
The dot matrix came from the Winamp visualiser, but what I actually loved as a kid were the skins: the same player wearing a different face depending on what you dressed it in. Twenty years later I built a core with a thin shell per platform, and did not notice the resemblance until I wrote this down.
-
Jul 2026 product
Free, because anyone could build it
Dictation is free in Yohoho, on every platform, with no cap on how much you use it. That is not a launch promotion. A local speech model behind a hotkey is something a lot of people could now assemble in an evening, and charging rent on something anyone could build for themselves is exactly the thing that annoyed me into starting.
What is left to pay for is taste. Choosing a different model, changing how the panel looks and behaves, the tuning I did against my own voice for a week. If someone pays, they are paying because their taste and mine line up and they would rather not build it themselves. That seems like the only honest thing to charge for.
Where that leaves the money
Nowhere yet. Nothing is charged for today, the beta has an expiry date I keep pushing forward with each release, and I have not decided what happens when it runs out. The free half is settled. The paid half is still a sentence, not a product.
-
Jul 2026 thought
The real limit is social, not technical
I built this assuming the constraint was accuracy or speed. It is neither. People will not talk to their computer with other people in the room, so dictation only gets used in the hours somebody happens to be alone. It is the reason feedback is slow, and it is a bigger ceiling on this category than anything in the model.
-
Jul 2026 thought
Eight days, because I already knew what I wanted
First commit to a signed Mac beta took eight days, and the interesting part is what made that possible. I had built a small text-to-speech thing before, so I already knew a model under a billion parameters is comfortable on 16GB of RAM and small on disk. I knew I wanted ONNX. I chose Python because I can read it, and would have reached for Rust otherwise. None of the decisions needed research, so the model I was building with never had to make one.
Nothing filed under that one yet.