Important
macOS first launch (no code signing yet). After dragging StemDeck to Applications, clear the Gatekeeper quarantine flag or macOS will say the app is damaged:
xattr -dr com.apple.quarantine /Applications/StemDeck.app
Which file do I download?
| Your setup | Download |
|---|---|
| Windows, NVIDIA GPU | StemDeck-Windows-x64.NVIDIA.zip |
| Windows, no NVIDIA GPU | StemDeck-Windows-x64.zip |
| Linux, NVIDIA GPU | StemDeck-Linux-x64.NVIDIA.tar.gz |
| Linux, no NVIDIA GPU | StemDeck-Linux-x64.tar.gz |
| macOS, Apple Silicon (M1-M4) | StemDeck-macOS-arm64.dmg |
| macOS, Intel | StemDeck-macOS-x64.dmg |
| Docker / Unraid | Nothing here - pull ghcr.io/stemdeckapp/stemdeck:0.15.2 |
Pick one. Each Windows and Linux download is complete on its own: unzip and run, no installer, no toolchain. Everything else in the asset list is used by StemDeck itself - in particular the small -app files are the updater's payload and will not run on their own.
On the GPU variants: both ship the same small package. The NVIDIA build downloads the CUDA components matching your card on first launch, so it needs a working NVIDIA driver. If you are unsure, take the non-NVIDIA one - it works everywhere and you can switch later.
Already running StemDeck on Windows or Linux? No dependencies changed, so the in-app updater applies this in place rather than sending you to the full download. If your install is one that will not start at all, take the full download instead, since the updater lives inside the app.
What's new in 0.15.2
Windows portable starts again.
Since 0.14.0, a Windows portable install could stop at the last setup step and report:
backend did not become healthy within 90 seconds.
Another program is already using port 8000 (process 16452).
There was no other program. The process it named was StemDeck's own backend, and it was healthy the entire ninety seconds it was being waited on.
The desktop shell checks that the process answering its health endpoint really is the backend it just started, so a second copy of StemDeck cannot quietly take over the first copy's library and data. It did that check by comparing process IDs. On the Windows portable build that comparison could never succeed: python\Scripts\python.exe is a small launcher that starts the real interpreter underneath itself, so the process holding the port is one step removed from the process the shell spawned. The shell waited out its timeout and then reported the only process ID it had seen as an intruder.
Identity now travels in a token that the shell hands to the backend at startup and the backend hands back. That survives the launcher step, so the check works on the shape the app actually has. The protection against a second copy is unchanged, and slightly stronger, since each launch carries its own token.
Linux and macOS were never affected. There is no launcher in front of the interpreter on either.
Thanks to everyone on #457 who worked out that it was not their machine. The process trees posted there are what identified this.
Under the hood
A test covering port reservation could fail against a port it had just released to a test running beside it. It now uses a port the operating system will not hand out on its own, so a red result means something is actually wrong.
Verified
The failure was reproduced on a locally built Windows CPU-only package, and the same package was confirmed to start normally with the fix, on the same machine and the same data directory with only the executable changed.