Skip to content

feat(bridge): Linux port — systemd daemon autostart + POSIX fixes#54

Open
doug-w wants to merge 2 commits into
puritysb:masterfrom
doug-w:feat/linux-port
Open

feat(bridge): Linux port — systemd daemon autostart + POSIX fixes#54
doug-w wants to merge 2 commits into
puritysb:masterfrom
doug-w:feat/linux-port

Conversation

@doug-w

@doug-w doug-w commented Jul 10, 2026

Copy link
Copy Markdown
Contributor

Ports the Node.js bridge to Linux. The daemon runtime, mDNS (pure-JS bonjour-service), Pixoo/ADB, and the PTY flow already worked; the gaps were autostart and a few macOS-flavored fallbacks. Stream Deck's desktop app is unavailable on Linux, so plugin-host steps are intentionally out of scope.

  • linux-service.ts: systemd --user unit (agentdeck-daemon.service) mirroring windows-service.tsbuildUnitFile (Restart=on-failure ≈ LaunchAgent KeepAlive), hasSystemctl probe, install/start/stop/disable over systemctl --user, XDG-aware path. Unit-tested (systemctl calls integration-only).
  • cli.ts: daemon install/uninstall gain a Linux branch (was a hard exit on non-darwin); degrades to a manual-start hint without systemd; installs Codex/OpenCode hooks for parity.
  • pty-manager.ts / check-deps.ts: shell fallback /bin/zsh/bin/bash when $SHELL is unset (matters for the headless daemon unit).
  • setup.ts: checks for a cc/make/python3 toolchain instead of Xcode CLT; skips Stream Deck app/CLI steps (unavailable on Linux).
  • Docs: daemon.md Autostart, README "Linux (Bridge + Daemon)", CLAUDE.md "Linux dev setup" pointer.

Verified on Debian 13 / Node 24: pnpm build clean, 1696 tests pass incl. the new linux-service suite, node-pty compiles natively, agentdeck CLI runs.

🤖 Generated with Claude Code

Port the Node.js bridge to Linux. The daemon runtime, mDNS (pure-JS
bonjour-service), Pixoo/ADB, and the PTY flow already worked; the gaps
were autostart and a few macOS-flavored fallbacks.

- linux-service.ts: systemd --user unit (agentdeck-daemon.service) mirroring
  windows-service.ts — buildUnitFile (Restart=on-failure ≈ LaunchAgent
  KeepAlive), hasSystemctl probe, install/start/stop/disable helpers over
  `systemctl --user`, XDG-aware unit path. Unit-tested (systemctl calls are
  integration-only).
- cli.ts: `daemon install`/`uninstall` grow a Linux branch (was a hard exit
  on non-darwin) — install writes+enables+starts the unit and installs
  Codex/OpenCode hooks; degrades to a manual-start hint without systemd;
  uninstall gracefully /shutdowns then disables + removes the unit.
- pty-manager.ts / check-deps.ts: shell fallback /bin/zsh → /bin/bash when
  $SHELL is unset (matters for the headless daemon unit).
- setup.ts: Linux-aware — checks for a cc/make/python3 toolchain instead of
  Xcode CLT, skips the Stream Deck app/CLI steps (unavailable on Linux), and
  prints systemd autostart next-steps.
- Docs: daemon.md Autostart, README "Linux (Bridge + Daemon)" section, and a
  CLAUDE.md "Linux dev setup" pointer.

Verified on Debian 13 / Node 24: pnpm build clean, 1696 tests pass incl. the
new linux-service suite, node-pty compiles natively, agentdeck CLI runs.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

@puritysb puritysb left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The Linux port is well scoped, but the generated user unit hardcodes WorkingDirectory=~/.agentdeck. On a fresh install that directory may not exist, causing systemd to fail at the CHDIR step before Node starts. It also ignores the repository-supported AGENTDECK_DATA_DIR override. Please either create the selected data directory during install and use the same resolver as the daemon, or remove WorkingDirectory if it is not required. Add a unit test covering a fresh/overridden data directory. The current CI does not exercise the systemctl integration path, so this failure would otherwise only appear on a real new Linux install.

…ted on install

Addresses PR puritysb#54 review: the generated user unit hardcoded
WorkingDirectory=~/.agentdeck, which (1) ignored the AGENTDECK_DATA_DIR
override the rest of the daemon respects, and (2) could fail systemd's
CHDIR step before Node starts if the dir didn't exist on a fresh install.

- New getDataDir() mirrors the daemon's inline resolver (AGENTDECK_DATA_DIR
  || ~/.agentdeck); buildUnitFile() uses it for WorkingDirectory (with an
  explicit workingDir opt override for testing).
- installUnit() mkdir -p's the data dir before writing the unit, so CHDIR
  never fails on a fresh/overridden install.
- Tests cover the default fallback, AGENTDECK_DATA_DIR override in
  WorkingDirectory, getDataDir resolution, and installUnit creating a
  not-yet-existing nested data dir.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012q6HRNJyVeMZiQcX4ZF7XF
@doug-w

doug-w commented Jul 12, 2026

Copy link
Copy Markdown
Contributor Author

Addressed in 2c0b9a9.

  • WorkingDirectory now resolves through a new getDataDir() that mirrors the daemon's own inline resolver (AGENTDECK_DATA_DIR override, else ~/.agentdeck), so the unit points at wherever the daemon actually reads/writes rather than a hardcoded ~/.agentdeck.
  • installUnit() now mkdir -ps that data dir before writing the unit, so systemd can't fail at the CHDIR step before Node starts on a fresh (or overridden) install.
  • Added unit tests covering the default fallback, the AGENTDECK_DATA_DIR override reflected in WorkingDirectory, getDataDir() resolution, and installUnit() creating a not-yet-existing nested data dir before it reaches systemctl.

Full suite green (1180 bridge tests).

@puritysb puritysb left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for fixing the fresh-directory CHDIR failure. The directory is now created before systemctl runs, and the focused tests/typecheck pass, but the AGENTDECK_DATA_DIR override still does not survive into the service process.

buildUnitFile() uses the install command's current environment to write WorkingDirectory=<override>, but the generated unit does not include an Environment=AGENTDECK_DATA_DIR=... directive (or an EnvironmentFile). A systemd user manager is not guaranteed to inherit the interactive shell environment used for agentdeck daemon install, and after login/boot it normally will not have this ad-hoc variable. The daemon then executes with no AGENTDECK_DATA_DIR, so session-registry.ts/APME/etc. fall back to ~/.agentdeck while systemd merely chdirs into the override directory. This breaks the claimed data-dir parity and can split daemon state across two locations.

Please persist the selected override into the unit with correct systemd escaping (only when explicitly set), or remove override support from this unit and avoid claiming it. Add a test that parses the generated unit and verifies the launched process receives the override, not only that WorkingDirectory and the directory exist. It would also be good to quote/escape all generated path values consistently while touching the unit builder.

Verification at 2c0b9a9: tsc --noEmit passed and linux-service.test.ts passed 12/12.

@puritysb puritysb added changes-requested Review feedback must be addressed before merge enhancement New feature or request platform:bridge Node bridge, daemon, hooks, and CLI labels Jul 18, 2026 — with ChatGPT Codex Connector

Copy link
Copy Markdown
Owner

This remains the closest external PR to merge, so I am keeping it open. The remaining blocker is still the systemd process environment, not only its working directory: when AGENTDECK_DATA_DIR is selected during install, the generated user unit must persist that value with correct systemd escaping so the daemon process reads and writes the same directory after login/reboot.

Please add a unit-file test that verifies the launched process receives the override, rebase onto current master (the branch is now 133 commits behind), rerun the full CI matrix, and repeat the fresh Debian systemd user-service install test. Once those are green, this can return for final review.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

changes-requested Review feedback must be addressed before merge enhancement New feature or request platform:bridge Node bridge, daemon, hooks, and CLI

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants