1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
|
# AGENTS.md
Guidance for AI coding agents working in this repository.
## What this is
`deck-it` turns an Android tablet into a second monitor, a stream-deck and an
always-on control surface for a Slackware Hyprland desktop. The PC serves a web
page on a Unix socket and exposes it to the tablet with `adb reverse`; `wayvnc`
streams a headless output to AVNC. Python 3.11+ standard library, plus
`websocket-client` for obs-websocket. Plain HTML/CSS/JS frontend, bash launcher.
Keep the server dependency-free apart from that one package.
## How it fits together
- `deckit/server.py` is the stdlib HTTP server: it listens on
`$XDG_RUNTIME_DIR/deck-it/http.sock`, serves `static/`, `/theme.css`,
`/icons/<name>.svg` and `/api/<module>[/<action>]`.
- A module is `deckit/modules/<name>.py` exporting `make(cfg) -> Module`; the
registry discovers files lazily. `state()` is read, `actions` are
allow-listed, and the client sends ids, never commands.
- The page shell (`static/app.js`) builds tabs from each panel's `tab` property,
mounts panels and polls `/api/<module>`.
- `deckit/theme.py` reads UDT's palette (`~/.config/rofi/udt/palette.rasi`) and
`~/.cache/udt/udt-border.lua`; the frontend uses only those CSS variables.
Text size is keystone's (`~/.config/keystone/fonts.json`, `override.deckit`
else `base`) as `--udt-font-size` on `html`, so `deck.css` sizes text in
`rem`. The shell re-reads `/theme.css` every 5s, so changes reach an open page.
- Launcher icons follow the icon theme Keystone sets (`gsettings
org.gnome.desktop.interface icon-theme`); window icons resolve through the
`.desktop` `Icon`/`StartupWMClass` mapping.
- `deckit/display.py` creates the headless output, centres it under the first
monitor for `position = "auto-below"`, and paints it with the first monitor's
swaybg image.
- The launcher (`deck-it`) handles USB and Wi-Fi (`pair`/`wifi`), the tunnels,
wayvnc and AVNC. `adb mdns` may be unsupported; `deck-it wifi <ip:port>` or
`[wifi] address` gives an explicit one; otherwise the last address that
worked (`~/.config/deck-it/last-wifi`, kept across `stop` and reboots).
`[display] enabled = false` skips the headless output, wayvnc and AVNC.
`deck-it status` prints one JSON line for keystone's page; keep its keys.
- Config: `deckit/config.py` merges `~/.config/deck-it/config.toml` over the
shipped `config.toml` per key within each table (a list is replaced whole).
Keystone's deck-it page (quickshell repo, `desktop/modules/deckit`) writes
that sparse file and reads the defaults from `deck-it defaults`; keep that
JSON shape stable.
- A panel whose source can be switched off (OBS, build VM, LLM, K1C) shows
`static/offline.js`'s card, not raw error text; the error goes in its tooltip.
- `k1c` reads a Klipper printer through Moonraker (`[k1c] url`); its one action
is the emergency stop, a press-and-hold button on the tab. While the printer
is off it backs off 10s between tries. The camera snapshot and the slicer
thumbnail are loaded by the tablet straight from the printer.
- The page holds a Screen Wake Lock while visible, so the tablet never sleeps
over the dashboard; nothing on the tablet's settings is changed.
- Launchers are `[launch] apps`, desktop ids run with `gtk-launch`; label and
icon come from the `.desktop` file. The client sends the id, which must be
configured and installed.
## Conventions
- New behaviour goes in a module under `deckit/modules/`, not in the server.
- Panels keep their scoped wrapper class (`.music`, `.sbb`, `.llm`, `.windows`)
because the CSS is scoped to it.
- Hyprland Lua: a dispatcher must be wrapped in `hl.dispatch(...)` to execute.
`hyprctl eval` alone only builds the dispatcher object.
- No personal data in code, docs, tests or commits; use placeholders.
## Testing
python3 -m unittest discover -s tests
`node --check` any changed JS file. The real hardware paths (wayvnc, adb, OBS,
the tablet) are manual.
## Repo facts
- License: GPLv2 only (`LICENSE`, header in each source file).
- Work directly on master.
|