Moving the Main PC to Linux, Halted :(
Peripherals and Claude Code were the only reason I stayed with Windows but now it's time to prep for the leap.


Two things have kept me on Windows.
Peripherals, and Claude Code. Everything else I could live without.
Claude Code was the easy one to retire, and the timing helps. The desktop app now runs on Linux, in beta. It's Debian-based only for now (Ubuntu 22.04 or later, Debian 12 or later), computer use and dictation aren't in yet, and Fedora or Arch users get the terminal version instead. This whole project was built on Linux, start to finish.
Peripherals were the hard one.
I own an Ajazz AKP03E, a small macro deck with LCD keys. Ajazz ships software for Windows. For Linux there's nothing official. So that became the test: if the deck works on Linux, my last reason goes.
Someone had already done the hard part
Before writing anything I went looking. The maker doesn't publish the protocol, so the community reverse engineered it. A Rust library called mirajazz covers these decks. OpenDeck, an open source app that speaks the Stream Deck plugin protocol, drives the hardware through a driver plugin built on that library. The AKP03E is on the supported list as 0300:1002 for the original and 0300:3002 for the second revision.
I didn't have to port anything. I had to build what sits around it.

What I built
An installer comes first. It reads the USB devices on your machine, matches them against the supported list, and writes a udev rule for the one deck it finds. Nobody has to look up a product ID.
Then a small plugin SDK in plain Node, no dependencies, so I can write my own plugins later. I wanted that most.
The first plugin talks to Home Assistant. Press a key and it calls any service. Turn on the state option and the key shows the entity's current state. Hue and PC control are next on the list.
The settings panels use my own design system, black and white with one typeface. Here they are in light and dark. These are browser renders, not yet seen inside OpenDeck.

Attacking my own work
Every step went past a separate security reviewer, another Claude agent whose only job was to find what I'd done wrong. It earned its place.
It found a hole in my zip check. A large enough archive with a ../ path in it sailed through, because the tool listing the files died on a closed pipe and my script read that as "safe". The reviewer reproduced it, and I ran the old code against the same archive to see it get through. A fix you haven't watched fail first is a guess.
It also caught my --yes flag opening USB access for all thirteen supported device IDs without asking. Both are fixed and covered by tests.
The reviewer also made me stop the installer from running downloaded code on autopilot. Fetching someone else's installer or driver now needs its own flag.

What still bothers me
Security work mostly produces a list of things you can't fully fix, and I'd sooner write mine down.
OpenDeck stores plugin settings in plain text, so the Home Assistant token sits there unencrypted. The Stream Deck protocol has no better place for it. All I can do is tell people to create a token with only the access they need.
The driver download isn't pinned or checksummed, because I have no reviewed version to pin it to yet. If that upstream project were compromised, the code would run as me.
And a profile someone shares with you can carry a key labelled "Desk" that calls a service you'd never press on purpose. Plugins are code. I treat them that way.
What I haven't proven
None of this has touched a real deck yet. The tests run against fakes: a fake device tree, a fake OpenDeck, a fake Home Assistant. They caught real bugs, including one where the plugin never received its token. They can't tell me whether the keys light up.
So the README says it plainly. Untested on hardware. I'd rather ship that sentence than a confident guess.
The leap
The next step is the real test. Pick a distro the desktop app supports, install on that machine, run the dry run, plug in the deck, see whether OpenDeck finds it. Then Hue. Then PC control, which is where the SDK's no-shell rules get tested properly.
I'm keeping one rule while I do it. Anything I can't confirm on the real deck goes in the README as untested, not as a promise.
If the keys light up and a Home Assistant call lands, I've run out of excuses.
The code is at github.com/BeardedTech0o/nullajazz. Setup is one command, and the README says what's checked and what isn't.


