PRTOTYPE.COM · Production studioAudit · Build · Maintain
PRoTOTYPE.COM
Productive Voice case study
Case study · Windows desktop product

Speak. It lands where you type.

Productive Voice is a Windows dictation app priced at $39, paid once. A floating pill records speech, a speech service transcribes it on the customer’s own account, an optional AI model tidies it, and the text is pasted into whichever window has focus. PRTOTYPE.COM designed it, built it and ships it.

Type
Desktop app · Electron
Under it
Win32 · streaming STT · signed licensing
Status
Product · v0.5.2
1,317 unit tests passing
3 speech providers · your keys
30-day trial · $39 once
The brief

One payment, your own keys.

Dictation on Windows is mostly rented. At November 2026 prices, Wispr Flow Pro costs $15 a month, or $144 for a year paid up front, and Dragon Professional sells for about $699. The $39 one-time slot that VoiceInk fills on macOS did not exist on Windows.

Productive Voice takes that slot. The buyer pays once, connects their own Deepgram, AssemblyAI or Groq key, and pays the provider at cost with no markup. Audio goes from the PC to that provider’s account and nowhere else. The app sends no telemetry.

That decision sets the engineering problem. With no server of ours in the audio path, capture, retry, paste, key storage and the licence check all have to work on the customer’s machine, unattended, on hardware we never see.

The first commit was on 10 March 2026. Version 0.5.2 was published on 11 November 2026, with a changelog that lists what is still not done.

“$39. Pay once. Dictate anywhere on Windows. Your keys, your data, no subscription.”
1,317
Unit tests passing · 97 files · run 12 Nov 2026
26.5k
Lines of TypeScript in the app
3
Speech providers behind one interface
~10 MB
Upload per hour of audio · was about 116 MB
7 days
Offline grace when the licence server is out of reach
The product

A pill on the desktop, and an app behind it.

These are captures of version 0.5.2 running on Windows with demonstration data. The meeting, the names and the keys are invented; the screens are the shipped ones. Click any plate to see it full size.

01 / History

Dictate into any window.

Click the pill or press the hotkey, speak, and the text is pasted into whichever app has focus through the Win32 API. History files each dictation under the app it went to: Outlook, Slack, Visual Studio Code, Notepad. None of the text on this screen was typed.

Win32 paste via koffiGlobal hotkeySearchable history
02 / AI summary

A meeting, read back as decisions.

Long recordings get a summary in one of five templates: meeting, client call, lecture, interview or brain dump. The summary names the model that wrote it and tells the reader to check important details against the audio. Actions carry the speaker names the user chose.

5 summary templatesModel named on the outputRegenerate
03 / Transcript

Who said what, and when.

Speaker labels come from the speech provider, and the app says on screen that they can be wrong. Click a name to rename a speaker; click a time to play the audio from that line. If a provider refuses speaker labels, the app transcribes again without them and still returns the text.

Speaker labels, renamableClick a time to playFallback on HTTP 400
04 / Chapters

Click a chapter, hear it.

Each recording gets a chapter timeline written from its transcript, with times that point to the nearest spoken line. A player is docked under the recording, with a seek bar and the chapter now playing. A recording that is not transcribed yet shows its estimated cost before the user commits.

Chapter timelineDocked playerCost shown before transcribing
05 / Settings

The customer picks the providers.

Speech goes to Deepgram, AssemblyAI or Groq. Text tidying goes to OpenRouter or OpenAI, or is switched off for raw dictation with one key. HIPAA-safe routing is described in plain words on the toggle itself: it does not make the app HIPAA compliant. Updates are checked at launch and every six hours.

3 speech providersRaw mode: one keyIn-app updates
06 / Licence and keys

A trial that survives a reinstall.

The 30-day trial is anchored to the licence server, so wiping settings does not restart it. Provider keys appear as masks, each with a connection state and the provider’s rate beside it: about $0.0077 a minute for Deepgram. The key itself never reaches this window.

Server-anchored trialKeys shown as masksRate per minute on screen
Under the surface

What a paying customer never sees.

A desktop product runs on the buyer’s machine, where anyone can open it up. These are the rules the app holds itself to, each one enforced in code.

Signed licence replies

Every reply from the licence server is verified with Ed25519 against a public key built into the app. Only a signed refusal can lock the app. A network failure starts a seven-day offline grace period.

Ed25519 · 7-day grace

A clock policy

A reply signed more than ten minutes from the PC’s clock is reported as a clock problem, with the reason shown to the user. Setting the clock back never locks the app and never starts a new trial.

10-minute skew window

Electron fuses set at build

The installed app cannot be started as a plain Node program, ignores --inspect and NODE_OPTIONS, and loads only the app.asar built with the release, with its integrity checked. A packaged test reads the fuses back from the exe.

4 fuses · fuses.spec.ts

Keys stay in the main process

Saved API keys are not sent to the app’s windows. Settings receives a mask, and checking a saved Deepgram key works from the mask. The page security policy allows no inline scripts, and the font ships inside the app.

Mask only · strict CSP

Private audio, recovered after a crash

Audio waiting to be processed lives in a private folder inside the app’s data, under random names. After a crash, only a file the app made itself is recovered. A recording left mid-transcription is reset on the next start.

Private folder · crash recovery

The terminal guard

“Press Enter after paste” would run a half-dictated command in a shell. The app checks the focused process against 17 known terminals and withholds Enter. A terminal inside an editor cannot be detected, and Settings says so.

17 terminal processes
Under the hood

From a spoken sentence to pasted text.

Six stages, run by one state machine with every side effect injected. The machine is pure, so its timing rules are tested without a microphone, a network or a window.

01
Capture
Pill window · audio worklet
The pill is its own always-on-top window. It captures the microphone and streams audio to the main process, which also buffers a copy to disk in a private folder. That copy is what makes a retry possible.
02
Streaming speech-to-text
Deepgram · AssemblyAI · Groq
Audio goes straight from the PC to the provider the customer chose, on the customer’s own key. Partial text returns while the user is still speaking; the final transcript arrives on stop.
03
Finalise without clipping
State machine · 3 s safety timeout
On stop, the stream stays open while the pill flushes the last fraction of a second of audio. Closing early used to clip the final word of every dictation. If the end-of-audio signal never arrives, a safety timeout closes the stream after three seconds.
04
Optional AI tidy
OpenRouter · OpenAI direct · raw mode
A model fixes punctuation and applies the chosen voice, or the step is skipped in raw mode. The session is checked again after the model replies: if the user cancelled during the call, the result is dropped.
05
Paste
Win32 via koffi
The text is pasted into the focused window. If the paste fails, the text stays on the clipboard and the pill says so.Enter is never sent into a terminal
06
History and recordings
Machine-bound encrypted store · Ogg/Opus upload copy
Every dictation is written to a store encrypted with a key derived from the machine. Long recordings upload as a 32 kbps Opus copy, about 10 MB an hour in place of about 116 MB, and the original audio is left unchanged.
src/main/dictation/stateMachine.ts (the stop action)
// src/main/dictation/stateMachine.ts — the 'stop' action (logging removed)
case 'stop': {
  // A stop arriving before the mic became ready is a cancel of the start:
  // no audio has been streamed yet, so there is nothing to finalize.
  if (this.currentState === 'starting') {
    this.isCancelled = true;
    this.deps.stopSTT();
    await this.deps.discardAudioBuffer();
    this.setState('idle');
    return;
  }
  if (this.currentState !== 'listening') return;

  this.setState('finalizing');
  // Do NOT close the STT stream here. The renderer flushes its worklet
  // tail (final <256ms of speech) during 'finalizing' and then sends
  // AUDIO_END, which closes the stream.
  // Closing here used to clip the last word(s) of every dictation.
  // Safety net: if AUDIO_END never arrives (renderer crashed), force
  // the stream closed after 3s so we never hang in 'finalizing'.
  this.finalizeTimeout = setTimeout(() => {
    this.deps.stopSTT();
  }, FINALIZE_SAFETY_TIMEOUT_MS);
  break;
}
Errors replay from disk
A stream error in the middle of a dictation triggers one replay of the buffered audio through a fresh stream. A second error during the replay does not start another.
Late results are dropped
A result that arrives after a cancel, or after the session has ended, is never pasted and never written to history a second time.
Lengths in the log, never words
The log records the length of a transcript. Dictated text, HTTP headers and cookies do not reach the log file, and the support report is redacted before the user sees it.
The release log

Four releases, with the gaps in print.

Each release ships with a changelog, and the two latest carry a section for what is not done. These are the entries, shortened, with those known gaps as published.

0.4.0
10 Sep 2026

The trial moves to the server

The 30-day trial is anchored to the licence server, so reinstalling does not restart it. Development builds no longer bypass the licence gate. The dependency audit is cleared to zero known problems.

0.5.0
10 Nov 2026

Recordings become meetings

AI summaries with five templates, speaker labels with renaming, a chapter timeline for each recording, and an in-app update flow.

0.5.1
11 Nov 2026

Long recordings, and a claim removed

Long recordings upload as a compressed copy, so an hour of audio no longer times out on an ordinary connection. Transcribing again no longer deletes the old transcript when the new attempt fails. The claims that audio is processed locally and that the app has an offline mode were removed, because it has no offline speech-to-text.

Known gaps, as published
AssemblyAI and Groq were not tested against live accounts in this release. Deepgram was.
0.5.2
11 Nov 2026

Keys leave the windows

Saved keys are no longer sent to the app’s windows, Electron fuses are set, waiting audio moves to a private folder, and Recordings becomes a list with the chosen recording beside it and a docked player.

Known gaps, as published
The installer is not code-signed. Windows SmartScreen may warn.
The Settings and first-run redesign is not done.
The stack

One installer, no server of ours in the audio path.

The app talks to the customer’s providers and to one small licence server. Everything else runs on the PC it is installed on.

Electron 42
Shell
Two windows, the main app and the always-on-top pill, with two separate preload bridges.
React 18 + TypeScript
Interface
26,500 lines of TypeScript under src, with files held under about 500 lines.
koffi
Win32 bridge
Finds the focused window and pastes into it, with no C++ of our own to compile.
Deepgram · AssemblyAI · Groq
Speech-to-text
Three providers behind one interface, each on the customer’s own key.
OpenRouter · OpenAI
Text tidying
Optional. Rate limits wait and retry; provider errors show the provider’s own message.
Self-hosted licence server
Licensing
Ed25519-signed replies. A Stripe webhook mints and emails the key, proven end to end in Stripe test mode.
electron-builder + updater
Release
NSIS, MSI and portable installers; updates arrive from a public releases page.
Vitest + Playwright
Tests
1,317 unit tests in 97 files and 19 Playwright spec files, including tests on the packaged build.
Why it holds up

Checks you can run.

1,317 tests
The unit suite passed in full on 12 November 2026. Typecheck and lint must be clean before any work is called done.
Signed
The app trusts no licence reply without a valid Ed25519 signature, and the public key is never fetched at runtime.
Hardened
Electron fuses, ASAR integrity, a no-inline-script policy and a short list of sites the app will open.
Stated gaps
The installer is not code-signed yet, and two of the three speech providers await a live-account check. Both facts are in the changelog.
Version 0.5.2

See it shipped.

Version 0.5.2 is on the public releases page, with a SHA-256 value for each installer. The installer is not code-signed yet, so Windows SmartScreen may warn. A 30-day trial starts on first run.

Productive Voice
Case study · Windows dictation · Designed, built and shipped by PRTOTYPE.COM · Written November 2026

Like what you see

Need a desktop product shipped?

Productive Voice went from a first commit in March 2026 to a licensed, self-updating Windows product. If you have a desktop app that needs native integration, licensing or a hardened release, let's talk it through.

Fixed prices · Set against a written spec
Book a Production Consultation→