-
Notifications
You must be signed in to change notification settings - Fork 0
Users vs Sessions
An agent-box host has Linux users, and each user has one or more sessions. This page says which one to add when. Issue #59 decided the architecture; the decision rule stayed implicit in its comments and kept getting re-derived, so #127 asked for it in writing.
-
Linux user = trust boundary. Separate credentials and secrets
(
tokenDir, the~/.config/agent-box/envfile, the settings daemon), separate blast radius, separate systemd hardening, separate auth path. A user is created with Nix plus a rebuild — deliberately expensive, because adding a trust domain should be a declared act. -
Session = unit of concurrent work. One agent, one job. Created at
runtime through
sessions.json, theagent-box-sessionCLI or the web UI. No sudo, cheap, destroyable, and spawnable by another agent.
Ask one question about the new agent: would it be a problem if it could read the other agents' tokens, memory and files?
-
No → a new session under an existing user. Shared memory, shared
clones and a shared
CLAUDE.mdare a feature here, not a leak. - Yes → a new user. Use this for a different human owner, a different credential set, or a different risk posture — for example a skip-permissions agent that must not reach another agent's secrets (the threat model behind #49).
The rule above is not only a preference. A session is unable to hold a boundary, so the "yes" branch has no cheaper answer than a new user. Measured on the maintainer's box on 2026-08-11, from inside a live session (uid 1001, five sessions on one user):
-
A sibling session's environment is readable.
/proc/<pid>/environof another session returnedGH_TOKEN,AWS_ACCESS_KEY_IDandAWS_SECRET_ACCESS_KEY.kernel.yama.ptrace_scopeis1on that box, but Yama gates onlyPTRACE_MODE_ATTACH;/proc/<pid>/environusesPTRACE_MODE_READ, so Yama does not apply. The same uid is sufficient.hidepid=does not help either — it hides other users' processes, not same-uid ones. -
The tmux server is shared. One server owns every session of the
user, so
tmux -L agent-box list-sessionsandsend-keysfrom one session drive a sibling's pane. That is full control of the other agent, without reading any environment.
Closing both would need a PID namespace with its own /proc and a
tmux server per session — a container per session. That breaks the
supervisor, find_supervisor_pids in modules/src/settings-daemon.py
(it scans the host /proc for same-uid pids), and the session manager.
So per-session isolation is off the table by construction. Any future feature that implies a per-session security boundary is a design error.
Per-session environment, per-session working directory and per-session secrets are convenience and scoping layers. They must say so, and they must never advertise isolation.
Worked example: #135 (per-session env, persisted and RAM-only). The RAM-only half buys a shorter secret lifetime — the keys stay out of EBS snapshots, the AMI, the qcow2 and backups, and they die on reboot or Spot interruption. It buys no confidentiality from a sibling session, because of the two facts above.
- Most boxes want few users and many sessions.
claudeandcodexas separate users was a pre-#59 workaround for per-CLI units, not a trust decision. - Cross-user sharing (opening HOMEs,
chmodgymnastics) is an anti-pattern signal. Agents that routinely need each other's state belong in the same user. Genuine cross-domain sharing calls for a setgid shared directory, not readable HOMEs. - Workspace trampling inside one user is solved at the session layer (#126, one working directory per session), not by splitting users.
This is a common special case of the rule, and it is often the right one. It follows when the project carries its own credential set — its own GitHub token, its own cloud keys. Then the project boundary and the credential boundary coincide, and the Nix-plus-rebuild cost buys a real trust domain.
It does not follow when several projects share one credential set and one human owner. You then pay a rebuild per project and gain nothing, and you re-create the cross-user sharing anti-pattern above: the agents keep needing each other's clones and memory, which is the signal that they belong in one user. Split by credentials and owner, not by directory.