Skip to content

v2.27.0 — what YazSes said about itself was not what it did

Released 2026-08-17. Upgrade:

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

The previous release came from reading one machine's log and finding that YazSes had said nothing while dictation failed four times running. This one comes from continuing to check its claims against its behaviour — the documentation, the status output, and the quality gates — and finding that a surprising number of them were wrong.

Nothing here changes how dictation works. Almost everything here changes what YazSes tells you about how it works, which had drifted far enough to send people down paths that could not succeed.

yazses status now reports whether dictation is actually working

Decode latency has always been measured, summarised, and shown. Whether a burst produced any text at all was measured and never summarised — and it is the more basic number. A fast decode that types nothing is not usable at all.

status now carries a line like:

typed: 6 of 14 recent bursts (43%)

It is a bounded recent window rather than a lifetime average, because a lifetime average hides exactly the degradation worth catching: the machine that prompted this had gone from 21 typed of 30 to 6 of 14, and nothing reported it. Below five samples it says nothing at all — a rate the data cannot support is worse than no rate, because it will be believed.

One correction to that metric shipped with it. The first version classified a burst by its discard_reason, treating "no reason recorded" as success — but a burst that raises never sets one, so injection failures and vanished backends were being counted as text successfully typed. A health metric that counts failures as successes is worse than no metric, since it is consulted precisely when something is wrong.

"comment this line" was typed into your file instead of commenting it

The command grammar matched comment this line but not several natural forms of the same instruction — comment out, comment the line, comment this selection. An unmatched command is not an error: it falls through to dictation, so the words themselves were typed into the buffer. Asking your editor to comment a line inserted the sentence asking for it.

The README told Linux users to hold the wrong key

Two front-door errors, both of which cost a new user their first attempt:

  • The hotkey shown for Linux was not the one that ships. Someone following the README held a key that does nothing and concluded YazSes did not work.
  • Intel Mac users were sent away from a build that exists. The macOS section described the .dmg as Apple-silicon-only. Intel .dmg builds have shipped since v2.22.0.

Eight pages offered features that cannot be enabled

YazSes distinguishes capabilities that are wired from ones that are designed but not yet wiredfeatures enable refuses the latter, and yazses features labels them planned. The documentation did not carry the distinction. Eight pages listed unwired capabilities in ordinary "enable it with this command" tables, alongside features that work, with no indication the command would be refused.

The accessibility page was the worst of them, offering six such slugs to the readers least able to route around a dead end.

A test now pins this: a line that spells out yazses features enable <slug> for an unwired capability must also say planned. It follows the registry rather than a copied list, so wiring a feature retires the requirement automatically.

Related corrections in the same pass: the remote how-to promised a [remote] default_host default for an argument that cannot be omitted; xdotool was documented as an injection backend and is not one; --min-speakers still advertised itself as a lower bound after being made a no-op; and the README described the Tier 2 SLM router and one other capability in the present tense, as things YazSes does.

Four crashes were waiting behind a gate that said it was clean

make types describes itself as "advisory — currently clean; don't add errors". It was not clean, and because CI does not run it, nothing ever said so. Four of the seven errors standing in it were real AttributeErrors waiting on a code path:

  • Rewrite crashed if it arrived during startup. The function guarded the LLM cleaner for exactly that reason, then dereferenced the injector two lines later without a guard.
  • A spoken question could crash the same way — the recorder and STT engine are both absent until startup finishes.
  • The tray reaped subprocesses through a controller that may not exist.
  • The brand mark built its glyph colour in a way that lost the exactly-three-channels guarantee its RGBA paste depends on.

mypy is now genuinely at zero across 488 files, and the claim in the Makefile is true again.

Also fixed

  • The tray left a zombie process behind every time you opened Settings. The window was launched and never waited on. It is now reaped on the tray's own poll tick, which is correct whether the window closed a second or an hour ago.
  • The man page's release date stopped resolving at 2.25.0, because the changelog changed which dash character it used and the extracting regex knew only the hyphen.
  • The silent-audio troubleshooting page now covers "Empty transcription" alongside "Silent audio" — two different failures that feel identical from the user's side.
  • The second clipboard path is documented, with its platform limit. [injection] fallback_to_clipboard is Linux-only; on macOS and Windows the key is inert in both directions, so it never provided the safety net its name implies.

Full changelog

See CHANGELOG.md for the complete list.