QML bar widget + popout panel (dev.woodard.streamdeck) that drives streamdeck-ctl: key grid shaped by the connected model, per-key editor, brightness slider, and daemon controls. Themed via qs.Commons. Makefile gains build-ctl, install-ctl, install-plugin, validate-plugin and uninstall-plugin targets. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BjuZBBfzXqZgxRhxzJvkkC
Stream Deck — Omarchy shell plugin
A bar widget for Omarchy that controls the streamdeck-go daemon: device and daemon status, brightness, and a live 8×4 key grid you can edit in place.
Every colour and metric resolves through Omarchy's qs.Commons theme tokens
(Color.*, Style.*), so the widget follows the active theme rather than
carrying a palette of its own.
What it does
Bar icon — a miniature deck that fills in proportionally to how much of the deck is mapped, and dims when the deck is unplugged or the daemon is stopped.
Panel
| Section | Behaviour |
|---|---|
| Header | Title, status line, and an on/off switch for the streamdeck-go user service |
| Brightness | Slider writing brightness: into config.yaml; the daemon hot-reloads, so the deck dims as you drag |
| Facts | Device model, connection state, daemon state and uptime |
| Key grid | One cell per physical key, with icon previews, slot indices, and labels. Empty slots are shown so you can fill them |
| Editor | Right-click a key to edit its module/function, parameters, shell command, icon, label, and label colour |
| Actions | Restart the daemon, open config.yaml, open the icons folder, follow the log |
A red dot on a cell marks a priv: key. Those run through the privileged helper
and are deliberately not runnable from the panel — press them on the deck.
Mouse and keyboard
| Input | Action |
|---|---|
| Left-click bar icon | Open/close the panel |
| Right-click bar icon | Refresh |
| Middle-click bar icon | Start/stop the daemon |
| Left-click a key | Run that key's command (fire-and-forget, like a physical press) |
| Right-click a key | Open the editor for that key |
| Arrow keys | Move the grid cursor |
Enter |
Edit the focused key |
Space |
Run the focused key |
e |
Edit the focused key |
r |
Refresh |
p |
Start/stop the daemon |
Esc |
Leave the field → close the editor → close the panel |
Requirements
- Omarchy with
omarchy-shellrunning streamdeck-goinstalled and its user service presentstreamdeck-ctl— the helper CLI the plugin drives. The panel refuses to show controls without it and tells you how to install it.
The plugin never edits YAML or probes USB itself; it shells out to
streamdeck-ctl, which reuses the daemon's own config and device code. That
keeps one implementation of the config format rather than two.
Install
From a checkout of the streamdeck-go repo:
make install-plugin # builds + installs streamdeck-ctl, links the plugin
omarchy plugin enable dev.woodard.streamdeck right
make install-plugin symlinks this directory into
~/.config/omarchy/plugins/dev.woodard.streamdeck, so edits to the QML are live
after a rescan:
omarchy-shell shell rescanPlugins
Qt caches compiled QML in
~/.cache/quickshell/qmlcache, and a running shell can keep serving a stale compiled unit across a rescan. If an edit doesn't seem to take effect,omarchy restart shell.
To validate before committing:
make validate-plugin
omarchy plugin validate refuses a symlinked plugin folder by design, so this
target validates the source directory rather than the installed link.
Remove
make uninstall-plugin
Settings
Configurable from the Omarchy bar widget settings:
| Setting | Default | Meaning |
|---|---|---|
refreshIntervalSec |
10 | Poll cadence while the panel is open; closed, it relaxes to at most once a minute |
ctlPath |
(empty) | Explicit path to streamdeck-ctl; empty searches ~/.local/bin, ~/go/bin, /usr/local/bin, then $PATH |
configPath |
(empty) | Explicit config.yaml; empty uses ~/.config/streamdeck-go/config.yaml |
hideWhenDisconnected |
false | Hide the bar icon entirely when no deck is connected |
IPC
omarchy-shell dev.woodard.streamdeck open
omarchy-shell dev.woodard.streamdeck toggle
omarchy-shell dev.woodard.streamdeck status # "20 of 32 keys in use"
omarchy-shell dev.woodard.streamdeck refresh
omarchy-shell dev.woodard.streamdeck brightness 60
omarchy-shell dev.woodard.streamdeck press 3
Useful for Hyprland binds — e.g. a key that dims the deck without opening the bar.
Security note
Module keys can reference secrets via {{env "TOKEN"}} in their exec templates.
streamdeck-ctl status never emits the rendered command — the panel shows only
module · function for module keys — so tokens can't leak into the UI or into
anything scraping the CLI's JSON. On Linux, key press merges the systemd user
manager's environment over the caller's before running, so a token imported with
systemctl --user import-environment reaches panel presses exactly as it reaches
hardware presses. (macOS keeps the caller's environment — launchd has no
equivalent bulk query.)
A note on config formatting
Saving from the editor rewrites config.yaml through a YAML node-level editor.
Comments and blank lines are preserved, but two normalisations happen on any
save:
- trailing whitespace on values is trimmed
- a comment block dangling at the end of a key entry may be re-indented to match the block it attaches to
Both are cosmetic. Values, ordering, and comment text are preserved.
Files
manifest.json plugin metadata + settings schema
Panel.qml bar icon and popout panel (entry point)
Service.qml owns every streamdeck-ctl invocation
KeyGrid.qml the 8x4 (or 5x3) key grid
KeyEditor.qml per-key editor
StreamDeckIcon.qml drawn deck icon, takes its colour from the caller
Model.js parsing and formatting helpers
License
MIT — see LICENSE.