Repository navigation
Linux packaging & deployment: zero-toolchain install (deb / rpm / AppImage) + release artifacts #168
Copy link
Copy link
Open
Labels
enhancementNew feature or requestNew feature or requesthuman-verification-requiredCode is complete; a human must verify on real hardware / a live session before closingCode is complete; a human must verify on real hardware / a live session before closingspikeDesign-doc spike work (input injection, focus watcher, etc.)Design-doc spike work (input injection, focus watcher, etc.)
Description
Activity
- addedenhancementNew feature or requestNew feature or requestspikeDesign-doc spike work (input injection, focus watcher, etc.)Design-doc spike work (input injection, focus watcher, etc.)
on Sep 23, 2026 Decision: AppImage
Recorded as ADR-0012.
- Flatpak/Snap rejected — a sandbox cannot write the udev rule, see
/dev/uinput(--device=alldoes not reliably expose it), reach the session bus unfiltered (xdg-dbus-proxyfilters names), or install the compositor plugin. This is the Docker argument restated indocs/GUIDE.md:593. - AppImage is the primary artifact. It is unsandboxed, so daemon + D-Bus + serving the client all work as from a checkout. Focus watcher (
~/.local/share/gnome-shell/extensions, KWin dirs) and XDG autostart are user-level and installable. - The root step is unavoidable on every channel (udev rule +
inputgroup). Factored into one idempotentinstall-system-integrationhelper run viapkexec/sudo, with a matching uninstall. - deb/rpm stay a later thin wrap of the same relocatable tree — not a competing design.
Phase 0 substrate is unchanged: relocatable tree + install script + docs. The channel is the skin on top.
Open sub-decisions (need input before Phase 0 lands)
- Runtime: PyInstaller
onedir(reuse macOS spec) vsuvstandalone CPython + venv. - Helper UX:
pkexecGUI helper vs.shwithsudovs print instructions. - Focus watcher: auto-install (detect GNOME/KDE) vs instruct.
- Autostart: XDG
.desktopvs install the systemd user unit. - Arch: x86_64 first vs x86_64 + aarch64.
- Flatpak/Snap rejected — a sandbox cannot write the udev rule, see
Sub-decisions resolved (ADR-0012 updated):
- Runtime: PyInstaller
onedir(parity with macOS packaging & deployment: self-contained .app + DMG release #165). - Root step:
.shhelper run withsudo, prints changes, ships uninstall. - Focus watcher + autostart: helper auto-installs both (GNOME/KDE detect +
~/.config/autostart/deckd.desktop). - Arch: x86_64 + aarch64 (aarch64 needs an
evdev-binarysource build in CI).
- Runtime: PyInstaller
- added a commit that references this issue
on Sep 30, 2026 - addedhuman-verification-requiredCode is complete; a human must verify on real hardware / a live session before closingCode is complete; a human must verify on real hardware / a live session before closing
on Sep 30, 2026 Phase 0 merged in #171.
Verified on NixOS 26.05 / GNOME 50 Wayland (x86_64): AppImage build + boot (health, bundled client, layout seeding, log file), input injection end-to-end (typed
deckd injected thisthrough the packaged daemon into a live Text Editor and saved it), live focus with the v6 extension (layout switching,RaiseApp/RaiseWindow,smoke_focus_live), and the helper's install→uninstall lifecycle sandboxed (pre-existinginputgroup/extension preserved).Still open on this issue:
- Autostart-at-login with the real helper on a clean machine (no pre-existing deckd service).
- The release workflow's first run on a
v*tag (x86_64 + aarch64).
Helper root-step UX follow-up: #173 (pkexec front-end + uaccess-first).
Metadata
Metadata
Assignees
Labels
enhancementNew feature or requestNew feature or requesthuman-verification-requiredCode is complete; a human must verify on real hardware / a live session before closingCode is complete; a human must verify on real hardware / a live session before closingspikeDesign-doc spike work (input injection, focus watcher, etc.)Design-doc spike work (input injection, focus watcher, etc.)
Problem
deckd runs on Linux today only from a source checkout:
just setup-linux(uv + Python + Node),just build-client, thenjust install-service, which sed-substitutes@PROJECT_DIR@intopackaging/systemd/deckd.serviceand points the user unit at.venv/bin/deckd. On top of that the user must hand-install the udev rule +inputgroup membership (packaging/udev/70-deckd-uinput.rules) and the desktop-specific focus watcher (GNOME Shell extension / KWin script). That needs git, Python, Node, uv, and a checkout.Nix users are covered by the flake (#17:
packages.deckd+ NixOS/home-manager modules own the service, udev rule, and group), but that's a different audience and a different install path.#165 gives macOS a zero-toolchain path (self-contained
.appin a DMG, built and published by a release workflow). Linux has no equivalent.Goal
Any Linux user can install deckd with zero toolchain: download an artifact from a GitHub release, install it, grant
/dev/uinputaccess once, install the focus watcher for their desktop, and run. No Python, Node, or checkout required.Follows
#165 (macOS
.app+ DMG +release-macos.yml). Mirror the shape: a build recipe that produces a distributable artifact, and a release workflow that attaches it to the tag. Reuse theDECKD_VERSIONversion seam (#165) so tag and artifact naming stay consistent across platforms.Candidate channels (to decide)
.deb/.rpm— the package can own the udev rule, the systemd user unit, and a desktop file, and post-install can add the user toinput. Needs per-distro CI./etc/udev/rules.dor add groups, and ships no systemd unit. Would need a first-run helper for the privileged steps./dev/uinput, reads other apps' windows through a compositor plugin, and talks to the session D-Bus bus. The GUIDE already rules out Docker for exactly these reasons, so this is likely a poor fit — but worth a sentence in the exploration.Linux-specific complications
inputgroup), so the artifact can't be fully unprivileged — unlike the macOS DMG.[dbus]extra is required on Linux (thedbus:action primitive + MPRIS); the macOS bundle deliberately omits it.uvstandalone CPython) vs depend on the distro's Python.evdev-binaryhas no aarch64 wheel — source build, seesetup-linux).client/dist,layouts/,layouts.*)..desktop.Open questions
.deb?)onedir(reuse the macOS spec shape) vs auv-built standalone CPython + venv.Plan (draft)
Phase 0 — doable anywhere, testable on a checkout
just build-linux-app/build-linux-tarball) that assembles the runtime + client + layouts into a relocatable tree.inputgroup, and writes the systemd user unit.Phase 1 — on a Linux desktop
4. Run the artifact, fix packaging issues, verify the service + focus watcher + input injection.
Phase 2 — release pipeline
5. A GitHub Actions job that builds the artifact and attaches it to the release (mirror
release-macos.yml).Related
.app+ DMG release (the template)