Skip to content

install-daemon: run the daemon as a launchd LaunchAgent at login #59

Description

@nonreagent

Type: AFK

What to build

Today the daemon only runs when started by hand (adj daemon), and client commands don't auto-spawn it — they error with "Start it with adj daemon." For daily use the daemon should come up at login and restart if it dies.

Add adj install-daemon / adj uninstall-daemon to manage a per-user launchd LaunchAgent (label ac.adj.acent). A LaunchAgent runs as the user, so — unlike install-port-forward and install-ca — this needs no sudo and stays within the never-root contract. The command can write the plist and launchctl bootstrap it directly rather than printing a command for the user to run.

ProgramArguments[0] is pinned to the absolute path of the currently-running adj, so the service runs the same binary that installed it. This matters for the CA: the keychain ACL is bound to that binary's cdhash (#44), so adj install-ca must be run from the same binary the agent launches.

Acceptance criteria

  • adj install-daemon writes ~/Library/LaunchAgents/ac.adj.acent.plist with: absolute path to the running adj, daemon arg, RunAtLoad=true, KeepAlive=true, stdout+stderr → ~/.adjacent/daemon.log.
  • It bootstraps the agent into the gui domain (launchctl bootstrap gui/$(id -u) …) and kickstarts it — no sudo anywhere.
  • Re-running install-daemon is idempotent: boots out the old label first, so it re-bootstraps cleanly even if the binary path changed.
  • adj uninstall-daemon boots the agent out and removes the plist.
  • ~/.adjacent/ is created if missing before launchd opens the log file (launchd creates the file, not its parent dir).
  • Docs: usage/README note the command, that it's rootless, and that install-ca must run from the same binary the LaunchAgent launches.

Out of scope / design notes

  • Does not remove the pf port-forward. A LaunchAgent runs as the user and still can't bind :80/:443; the daemon keeps binding :8080/:8443, so install-port-forward is still required for implicit-port URLs.
  • Alternative considered — bind :80/:443 without pf via socket activation. A root LaunchDaemon (/Library/LaunchDaemons, one-time sudo) can have launchd bind the privileged sockets and pass the fds to a non-root daemon (UserName key + launch_activate_socket()). That would let us drop pf entirely, but it trades the pf sudo for a LaunchDaemon sudo and adds fd-passing code. Deferred — file a follow-up if we want it.

Related

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions