Skip to content

v2.26.0 — when dictation stops, you find out

Released 2026-08-17. Upgrade:

sudo snap refresh yazses     # snap
pipx upgrade yazses          # or: uv tool upgrade yazses

This release comes from reading one real machine's daemon log. Every dictation attempt on it for an hour had produced nothing — the key held, words spoken, no text — and YazSes had said nothing at all, four times, because each of the three things that should have noticed was looking somewhere else.

A microphone that hears you but yields nothing

The mic-change guard counts silent discards: audio below vad_threshold. A run of them switches capture back to the last device that worked and notifies "Heard nothing 3× in a row — your mic may have changed."

An empty transcription — audio that clears the gate, reaches the model, and decodes to nothing — logged one line and returned. No streak, no notification, no auto-heal, no earcon. So a microphone capturing audible but unintelligible sound (too quiet, wrong device, badly attenuated) discarded for ever with silent_streak stuck at 0, while the guard built for that exact symptom saw a perfectly healthy microphone.

Measured on the machine in question: four consecutive empty transcriptions at capture levels 0.0022–0.0069, against 0.0199 for its own last successful dictation.

From your side the two failures are one event — hold the key, speak, nothing appears — and the notification's advice is right for both. The empty path now runs the same handler, and plays the error earcon for the reason the silent branch already gives: nothing will be typed, and without a screen that is indistinguishable from a slow decode. A single empty transcription still says nothing; the threshold of three consecutive, reset by any success, is unchanged, so holding the key without speaking costs you nothing.

default is a route, not a microphone

The other half of that guard watches for the OS default input changing. It detects a change by comparing the device's name over time.

On ALSA and PipeWire, default is a virtual entry that forwards to whichever device is current — PortAudio lists it at its own index, alongside sof-hda-dsp: - (hw:0,0). Whatever microphone it points at, the name it reports is default. So the watcher compares default with default for ever, and on the most common Linux audio stack the proactive half of the guard cannot fire: the microphone behind the alias changes and nothing on screen changes with it.

Reading through the alias needs a PipeWire or PulseAudio client library, which is not a dependency worth taking on for one diagnostic. What YazSes can do is stop presenting the alias as an answer — and name what is actually behind it:

OS default:    default
               → Raptor Lake-P/U/H cAVS Digital Microphone  (volume 65%)
               ⚠ that is a routing alias, not a microphone — the device behind it
                 can change without this name changing. Pin a real one to be sure:
                 yazses audio use <name>

That line is the diagnosis, and until now it could only be obtained by leaving YazSes and reading wpctl status by hand. It appears in both yazses audio status and yazses doctor — the surface the documentation points at first — and is suppressed when the default is already a real device, because resolving a name to itself is noise.

Resolved through wpctl, the way this project already reaches notify-send, xdotool and wl-copy: used when present, absent without complaint, never required, never raising into the caller. It reads only the Sources: block, because Sinks: has the same row shape and its own starred default and reporting a speaker as your microphone would be worse than silence — and it says nothing at all when no source is marked default, since which one is current is then genuinely unknown.

gitvoice truncated a branch name, then acted on what was left

"delete branch feature slash login"       ->  git branch -D feature
"delete branch my slash deep slash name"  ->  git branch -D my
"create branch feature slash login"       ->  git checkout -b feature

feature/login spoken is "feature slash login", and feature/… is the most common branch convention there is. The ref patterns capture [\w./-]+, which stops at the space, and re.search is unanchored — so everything after the first segment was discarded and a destructive command was emitted against a different ref than the one named, with nothing on screen showing that anything had been dropped.

A spoken slash now makes the / it sounds like. And every ref pattern is anchored at both ends, which is this project's own rule for spoken grammars — "a suffix match swallows 'click undo' instead of typing it". A phrase the grammar does not model is now refused, with the list of what it does understand, rather than half-understood and run.

Capitalisation you speak is still preserved, because git refs are case-sensitive: "delete branch Feature slash Login" gives Feature/Login.

Also

  • Coverage for three things that were correct. The WCAG contrast used for secondary text in the settings window was verified against 3000 palettes rather than six; the four check-digit schemes were pinned to their published error-detection profiles (Verhoeff detects every adjacent transposition — corrupt one cell of its permutation table and 17 of 18 tests still pass, which is why the property is now tested rather than assumed); and word↔turn alignment was pinned to the property a long meeting depends on, that merging loses no word.
  • A ledger of 63 config keys the loader accepts, validates and documents while no code reads them — [audio] channels is documented with default 1 while the recorder passes a literal channels=1. It fails when a 64th appears, or when one is wired and its entry goes stale.