Local-first · Linux · Apache-2.0

Voice typing that never leaves your machine.

Hold a key, speak, release. The text lands wherever your cursor already is — transcribed by NVIDIA Parakeet on your own GPU. No account, no upload, nothing to subscribe to.

holdRight Ctrland speak idle
press and hold to dictate… release → text 36ms
0 bytes leave the machine 36 ms from release to text 307× realtime on an RTX 3080 Ti
Measured, not estimated

Every number here came off a stopwatch.

Eleven seconds of speech, warm median of five runs, on two RTX 3080 Ti. The clock is the engine's own monotonic origin and the interval is release-to-text — the gap you actually feel.

0 ms
Release to text
fp32 on CUDA
Faster than realtime
11 s transcribed in 36 ms
0 B
Sent anywhere
no network path exists
0
Tests
across eight crates
How it works

Four steps, and only one of them is machine learning.

The hard part of local dictation is not transcription — it is getting the words into the application you are actually using.

01
0 ms

Trigger

evdev reads the key straight from the kernel, so it works in any session and reports press and release separately.

02
live

Capture

The microphone never stops. A rolling pre-roll means the first syllable survives talking before the key is fully down.

03
36 ms

Transcribe

NVIDIA Parakeet TDT through ONNX Runtime, punctuating and capitalising on its own. Re-run while you speak for live text.

04
<60 ms

Inject

A /dev/uinput virtual keyboard the compositor cannot tell from real hardware. No portal, no clipboard, no cooperation needed.

Push-to-talk, or hands-free

Hold to dictate. Double-tap to lock it on and speak freely; press again to stop. A stray tap emits nothing.

Your words, your vocabulary

A custom dictionary fixes names and jargon, and spoken commands — “new paragraph”, “scratch that” — do what they say.

Live text as you speak

The overlay shows words appearing mid-sentence, produced by the very model that will type them, so what you watch is what you get.

Latency

Where the milliseconds actually went.

int8 is a CPU optimisation. On the CUDA provider most quantised operators have no kernel, so the graph is copied back and forth across the bus and arrives exactly where it started — Murmur picks the right weights for your hardware by itself.

WeightsDeviceWarm medianRealtime factor
int8CPU477 ms23×
int8CUDA460 ms24×
fp32CPU464 ms24×
fp32CUDA36 ms307×
What we found

Three things that changed the design.

Each of these was discovered by measuring something that was supposed to work.

Wayland

GNOME cannot paste

Mutter exposes neither ext-data-control nor wlr-data-control, so a background process cannot set the clipboard at all. The paste trick most dictation tools rely on simply does not work here — Murmur types through the kernel instead.

ONNX Runtime

A device you must verify

ORT logs a failed GPU registration and quietly continues on the CPU, so a build can report success while running at a fraction of the speed. Murmur watches that log and reports the device it actually got.

Streaming ASR

The tail you cannot flush

Streaming gives a flat 14 ms tail, but never emits its final partial chunk — up to 560 ms of speech. Dictation ends exactly where that risk peaks, so live text comes from the batch model instead.

Built on

Standing on other people's shoulders.

Names and logos belong to their owners and appear here to say what Murmur is built with — not to suggest any of them endorse it.

Engineering notes

The hard part isn't the model.

Speech recognition is solved and fast. Getting the words into the window you are looking at is where Linux fights you — GNOME cannot paste, evdev cannot swallow a single key, and an overlay that takes focus types into itself. Read the notes →

Install

Two packages, three commands.

Each package carries both binaries, a desktop entry, the icon, and the udev rule that makes /dev/uinput reachable.

after installing
# read access to your keyboard, so Murmur knows when the key is held
$ sudo usermod -aG input $USER   # then log out and back in

# the speech model — 640 MB, or 2.5 GB for full precision on a GPU
$ murmur models pull

# check this machine can actually run it
$ murmur doctor
#   ✓ uinput      /dev/uinput is writable
#   ✓ trigger     RIGHTCTRL declared by 3 device(s)
#   ✓ model       parakeet-tdt-0.6b-v3-fp32 [Fp32]  ← selected

# then either
$ murmur hud      # the overlay
$ murmur listen   # the terminal

The group membership is a deliberate step, not something the package does for you. Read access to /dev/input/event* is the ability to read every keystroke on the machine; Murmur needs it to know when the trigger key is held, and no package should grant that quietly on your behalf.