From 0ad77999569d802fad9a1985d4cc86743a1d0085 Mon Sep 17 00:00:00 2001 From: Vuong Hoang Date: Fri, 25 Sep 2026 23:14:48 -0700 Subject: [PATCH] =?UTF-8?q?feat(nh3-dev):=20zellij-fleet@.service=20?= =?UTF-8?q?=E2=80=94=20fleet=20zellij=20server=20in=20its=20own=20cgroup?= =?UTF-8?q?=20(for=20SVOS=20seat=5Fup);=20installed,=20not=20enabled?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../zellij-fleet/10-onfailure-althing.conf | 8 ++++ services/zellij-fleet/README.md | 44 +++++++++++++++++++ services/zellij-fleet/zellij-fleet@.service | 40 +++++++++++++++++ 3 files changed, 92 insertions(+) create mode 100644 services/zellij-fleet/10-onfailure-althing.conf create mode 100644 services/zellij-fleet/README.md create mode 100644 services/zellij-fleet/zellij-fleet@.service diff --git a/services/zellij-fleet/10-onfailure-althing.conf b/services/zellij-fleet/10-onfailure-althing.conf new file mode 100644 index 0000000..5951c61 --- /dev/null +++ b/services/zellij-fleet/10-onfailure-althing.conf @@ -0,0 +1,8 @@ +# Installed as .service.d/10-onfailure-althing.conf on every fleet user +# unit. A drop-in rather than an edit to the unit file so it is visible in +# `systemctl --user cat`, reversible by deleting one file, and survives the +# unit being reinstalled by its own deploy. +# +# %n is the failing unit's full name; the template receives it as %I. +[Unit] +OnFailure=althing-notify-failure@%n.service diff --git a/services/zellij-fleet/README.md b/services/zellij-fleet/README.md new file mode 100644 index 0000000..0f636f2 --- /dev/null +++ b/services/zellij-fleet/README.md @@ -0,0 +1,44 @@ +# zellij-fleet@.service — fleet zellij session server in its own cgroup (nh3-dev) + +Asked for by svos-dev on 2026-09-25 for SVOS `seat_up`: Prime, through Miranda, +assigned a way to bring agent seats up remotely. The rule it enforces is that +**nothing forks the zellij server except this unit**. + +## Why + +`svos.service` runs with `KillMode=control-group`. If SVOS itself ran `zellij +attach -b Claude` to create or resurrect the fleet session, the server and every +agent pane would land in svos.service's cgroup. The next `systemctl --user +restart svos` (a routine deploy, about 100 s of vault reads) would then SIGTERM +the whole fleet. Started from this unit, the server gets a cgroup of its own +(`app-zellij-fleet.slice/zellij-fleet@.service`). + +## Behaviour (all measured on zellij 0.45.1, 2026-09-25, with a throwaway session) + +| case | result | +|---|---| +| session does not exist | created; server in the unit's cgroup | +| session EXITED (serialized) | **resurrected with its layout; command panes HELD** (`start_suspended true`, no process running) | +| session already running (e.g. Prime's ssh-started server) | `attach -b` is a no-op; that server stays in its own scope and stopping this unit does not touch it | +| `systemctl --user stop` | `zellij kill-session`, then the cgroup; the session stays resurrectable (EXITED) | +| environment | `zsh -lc` gives the login env (PATH plus the tokens from `.zshenv`/`.zprofile`, 23 vars). Bare systemd gives 13. The ssh server's extra vars are SSH_*, TERM, XDG_* and `.zshrc` interactive settings, which each pane's own interactive shell sets anyway | + +## Install + +```bash +cp services/zellij-fleet/zellij-fleet@.service ~/.config/systemd/user/ +install -D -m 644 services/zellij-fleet/10-onfailure-althing.conf \ + ~/.config/systemd/user/zellij-fleet@.service.d/10-onfailure-althing.conf +systemctl --user daemon-reload +``` + +Installed on nh3-dev 2026-09-25. **`zellij-fleet@Claude` is NOT enabled.** +Enabling it (`systemctl --user enable zellij-fleet@Claude`) makes the fleet +session come back at boot with every pane held, instead of when Prime first logs +in over ssh. That changes boot behaviour, so it waits until seat_up ships and +Prime agrees. Do not `start` it while a Claude server is already running outside +it: the start is a no-op, and a later `stop` would then not mean what it says. + +Contract use: seat_up checks `zellij list-sessions` for a RUNNING (not EXITED) +session and calls `systemctl --user start zellij-fleet@` only when +there is none. diff --git a/services/zellij-fleet/zellij-fleet@.service b/services/zellij-fleet/zellij-fleet@.service new file mode 100644 index 0000000..ee0c32f --- /dev/null +++ b/services/zellij-fleet/zellij-fleet@.service @@ -0,0 +1,40 @@ +# zellij-fleet@.service — owns a fleet zellij SESSION SERVER in its own +# cgroup. Instance = session name: zellij-fleet@Claude. +# +# Why a unit: a zellij server forked by whatever asks for it (svos.service, +# KillMode=control-group) lands in THAT unit's cgroup, and the next restart of +# the asker SIGTERMs the server and every agent pane under it. Starting the +# server here gives it a cgroup of its own. svos-dev's seat_up starts this unit +# only when `zellij list-sessions` shows the session is not running, and never +# forks the server itself (svos seats contract). +# +# attach --create-background: creates the session if it does not exist, and +# RESURRECTS an EXITED (serialized) session with its layout, command panes HELD +# (nothing runs until someone presses Enter). If the session is already running +# (e.g. a server Prime started from an ssh login), this is a no-op that exits 0 +# and that server stays in HIS scope: stopping this unit does not touch it. +# +# zsh -lc: the server gets the login environment (PATH, tokens from .zshenv / +# .zprofile), not bare systemd --user env. Interactive-only vars (.zshrc) are +# set by each pane's own interactive shell. Measured 2026-09-25: 23 vars vs 13 +# bare vs 44 for the ssh-started server (the difference is SSH_*, TERM, XDG_* +# and .zshrc interactive settings). +# +# STOP = the fleet session goes down (kill-session, then the cgroup). That is +# the honest meaning of stopping it. The session stays resurrectable. +# +# Install: services/zellij-fleet/README.md +[Unit] +Description=Fleet zellij session server "%i" (own cgroup) — eshpfi services/zellij-fleet +After=default.target + +[Service] +Type=oneshot +RemainAfterExit=yes +ExecStart=/usr/bin/zsh -lc 'exec %h/.cargo/bin/zellij attach --create-background %i' +ExecStop=-%h/.cargo/bin/zellij kill-session %i +KillMode=control-group +TimeoutStopSec=20 + +[Install] +WantedBy=default.target