# packaging/systemd — the user unit pair for veloxd Provided by lane DAEMON (`daemon/docs/AGENT-DAEMON.md` build step 7: "systemd user units — `velox.service` + `velox.socket` for socket activation"), for PKG/QA to install per `docs/07-packaging.md`'s layout: ``` /usr/lib/systemd/user/velox.service /usr/lib/systemd/user/velox.socket ``` `packaging/` outside `nativehost/` is PKG/QA's per `CLAUDE.md`'s lane table; these two files are here because they are inputs to that packaging step, not a claim on the rest of the directory — same relationship `packaging/nativehost/` already has. ## Why both files, and what `RuntimeDirectory=` is doing `velox.socket` binds `$XDG_RUNTIME_DIR/velox/velox.sock` **before `veloxd` ever runs** and hands the daemon the already-listening fd at startup (`daemon/src/rpc/systemd_activation.cpp` implements the receiving half — `LISTEN_PID`/`LISTEN_FDS`, fd 3 — without a `libsystemd` link). Two things this buys over the daemon binding its own socket on every start: - **No window where a client gets `ECONNREFUSED`.** The socket exists and queues connections from the moment `velox.socket` is active, not from whenever `veloxd` finishes starting up — this is the actual point of socket activation, not just "start on demand." - **Cold-boot ordering is free.** Nothing has to wait for `veloxd` to be ready before the GUI, the CLI, or a native-messaging host can attempt a connection; the kernel queues it. `RuntimeDirectory=velox` on the socket unit creates `%t/velox` (mode 0700) before the `ListenStream=` bind — without it, binding fails outright the first time (nothing has created the parent directory yet). `veloxd` itself creates that same directory (`ensure_private_dir` in `runtime_dir.cpp`) for the case where it's started directly, outside systemd (`./veloxd` in a terminal, still supported and how most of this daemon's own testing runs) — the two paths converge on the same directory with the same mode either way. `UdsServer::start()` (`daemon/src/rpc/uds_server.cpp`) checks for the activated fd first and, if present, skips create/bind/chmod/listen entirely — the socket file's lifecycle then belongs to the unit (including `RemoveOnStop=yes` on stop), not to the daemon. Falls back to binding its own socket exactly as before when not socket-activated (a manual run, or a distro that ships the daemon without the unit files). ## What was deliberately left out `velox.service` does **not** set `ProtectSystem=`, `ProtectHome=`, or `ReadWritePaths=`. `saveTo.allowedRoots` is user-configurable to anywhere on the filesystem — an external drive, a second mount, anywhere `fs/safepath.hpp`'s own canonicalize-and-check accepts — not a fixed set of directories a unit file could enumerate ahead of time. A filesystem-level sandbox here would turn a legitimately-configured save location into an opaque `EROFS`/`EACCES` the daemon can't explain, in place of its own clear `-32011` — worse than no sandbox, specifically for a download manager. `NoNewPrivileges=yes` is kept: it has no such trade-off. ## Verifying socket activation without a real install `systemd-analyze verify --user velox.service velox.socket` checks unit-file syntax (it will complain that `/usr/bin/veloxd` and the `velox(1)` man page don't exist on a dev box that hasn't installed the package — expected, not a unit bug). To exercise the actual activation handshake without installing anything: bind a Unix socket, `dup2` it onto fd 3, fork, set `LISTEN_PID=` and `LISTEN_FDS=1` in the child's environment, clear `FD_CLOEXEC` on fd 3, and `execve` `veloxd` — a real `session.hello` round-trips over that fd with no `bind()`/`listen()` call ever happening inside the daemon for that run. This is exactly what `velox.socket`'s `Requires=`/`ExecStart` sequence does in production; systemd supplies the fd, `veloxd` doesn't know the difference.