feat(nh3-dev): zellij-fleet@.service — fleet zellij server in its own cgroup (for SVOS seat_up); installed, not enabled

This commit is contained in:
vh
2026-09-25 23:14:48 -07:00
parent 50f113cd7d
commit 0ad7799956
3 changed files with 92 additions and 0 deletions
@@ -0,0 +1,8 @@
# Installed as <unit>.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
+44
View File
@@ -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@<session>.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@<session>` only when
there is none.
@@ -0,0 +1,40 @@
# zellij-fleet@<session>.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