Skip to content

harness: shared -L forge tmux socket couples multi-agent supervision under systemd #18

Description

@orveth

Follow-up flagged while reviewing #15 (headless systemd start). Not a regression in #15#15 correctly fixes single-agent headless start, which was 100% broken before. This is about what happens with 2+ agents under one runAs user, which the current demo (single agent) doesn't exercise.

Proven (environment-independent, via tmux's own reporting)

The harness uses a shared -L forge socket per user ("enumerates every agent on this user"). tmux runs exactly one server per (user, socket):

  • tmux -L <sock> new-session -d -s agent-a … starts the server (daemonizes; server PPID becomes 1).
  • A second tmux -L <sock> new-session -d -s agent-b … does not fork its own server — it connects to the existing one, and the server forks agent-b's pane.

Local proof: server pid 1283301 (PPID 1), and both panes are its children — agent-a pane 1283302, agent-b pane 1283305. So agent-b's process tree lives under the server that agent-a's invocation created.

Consequence

With per-agent systemd services (forge-agent-<name>.service, Type=forking, default KillMode=control-group) all sharing -L forge:

  1. The single shared server lives in one service's cgroup (whichever created it). The other agents' service cgroups don't contain their own claude.
  2. systemctl stop/restart of the server-owning service tears down that cgroup → kills the shared serverevery co-user agent's session dies, not just the targeted one.
  3. The non-owning services' supervision (MainPID, Restart=on-failure) is decoupled from the claude they nominally manage.

Honest limitation

I could not faithfully reproduce the systemd-level states locally: transient-unit repros (both systemd-run --user and sudo systemd-run --service-type=forking -p User=…) couldn't even sustain the single-agent active(running) baseline that #15 validated on the real deploy — my tmux server died on cgroup cleanup immediately. That divergence means my repro doesn't match the real units, so I'm not asserting the exact multi-agent MainPID/ActiveState. The shared-server coupling above is proven and environment-independent; the precise systemd failure mode should be confirmed with a real 2-agent deploy. (Secondary: that my repro couldn't sustain even single-agent may hint Type=forking + daemonizing tmux is fragile — worth a second look, but it contradicts the validated single-agent result, so likely a repro artifact.)

Recommended fix (operator's call)

  • Per-agent socket-L forge-<name> instead of shared -L forge. Each service gets its own server ⇒ clean 1:1 supervision and isolated stop/restart. Cost: tmux -L forge ls no longer rolls up all agents; restore with a tiny wrapper that loops per-agent sockets. Smallest change.
  • Per-agent runAs user — the forge-agent-<name> user swap the spec already calls a 1-liner. Distinct users ⇒ distinct socket paths ⇒ problem vanishes, and it also delivers the OS-level trust isolation currently deferred.

Either eliminates the shared-server coupling. Recommend deciding before the team adds a second agent under one user.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions