v2.34.0 — Windows and macOS never had a GUI at all¶
Released 2026-08-27. Upgrade:
sudo snap refresh yazses # snap
pipx upgrade yazses # or: uv tool upgrade yazses
scoop update yazses # Windows
Three fixes, all reported or found by using the shipped product on a Windows machine rather than by any test. The largest of them had been true since the graphical features were written, on every Windows and macOS install YazSes has ever produced.
Settings opened nothing, and dictation showed no sign of running¶
Two symptoms, reported first-hand from a Windows desktop: clicking Settings… in the tray menu did nothing whatsoever, and holding the hotkey typed correct text with no visible indication that anything had happened — no sonar rings, and a tray icon that never changed colour.
The first symptom, and half of the second, are one line of code repeated three times:
That is how settingsui/launch.py, core/daemon.py and tray/launch.py each decided, independently, whether a graphical session exists. DISPLAY and WAYLAND_DISPLAY are X11 and Wayland variables. Windows and macOS set neither one and never have — so all three answered headless, always, on those platforms:
- the Settings window refused to open,
- the daemon never spawned the voice-activity overlay,
- the daemon never auto-spawned the tray icon.
Reproduced against the published 2.33.0 binary on a clean Windows host: yazses-cli.exe --settings exits 1 with "needs a graphical session — no DISPLAY or WAYLAND_DISPLAY is set". PySide6 is present in the bundle; the gate was the only thing refusing. From the windowed YazSesApp.exe that explanation has no console to print to, which is exactly why the button looked inert rather than broken — and why a defect this total survived every release.
The predicate now lives in one module, system/graphical.py, and takes the platform as an argument, because the honest answer differs by platform: on Windows and macOS an interactive process has a desktop by construction and nothing announces it in the environment, while on Linux and the BSDs those variables are the only evidence available. A build-failing guard forbids any module deciding it again on its own — but matched precisely enough to still permit inject/target.py, which asks the genuinely different question "is this plain X11?" before shelling out to xdotool.
The tray colour was a second, independent defect¶
Fixing the gate would have launched the tray and left the icon just as blue, because the tray could not see a short dictation at all. It polled the daemon once a second at rest, and only dropped to its 0.15 s rate after it had already observed a recording state — a chicken-and-egg, since the fast rate exists to track a burst the slow rate has to catch first. A one-to-two-second hold could begin and end between two samples and never be observed.
The overlay polls the same RPC for the same transition at 0.25 s, and says why in a comment: quick enough to catch recording start. The reasoning had been written down in one of the two processes that needed it. The tray now matches, and its test ties the rate to how long a burst actually lasts rather than to a number that can quietly be raised again. The cost is four status queries a second over a local socket while idle; the CPU and battery page carries the updated figure.
Every Scoop install silently had no Start Menu entry¶
scoop install yazses printed
Creating shortcut for YazSes (yazses.exe) failed:
Couldn't find C:\scoop\apps\yazses\current\yazses.exe
and then reported success. There is no yazses.exe in the bundle and there never was: the Windows build produces YazSesApp.exe (windowed — tray and daemon) and yazses-cli.exe (console — the CLI, shimmed onto PATH as yazses). The manifest's bin entry named the second one correctly, which is why the CLI always worked and this stayed invisible; the shortcuts entry named a file that does not exist — while the manifest's own notes told the user to launch the tray from the Start Menu.
A new guard reads the executable names out of the PyInstaller spec and fails if any bin or shortcuts target is not one the installer actually ships, so renaming a binary now breaks a test rather than a shortcut.
The shape of all three¶
None of these could be caught by a test that runs where the tests run. Two were found by installing the published build on a bare Windows host and reading what it printed rather than what it returned; the third was reported by someone holding the key on their own machine. An exit code said success in every case.