api-reference gains a Settings section (GET/PUT /api/settings, the model config, the case order and PUT /api/config, with the 403 FORBIDDEN a non-admin gets in multi-user mode). The Multi-User Mode wiki page explains what a regular user's App Settings save does now, Settings-Reference links it, the plan's Settings row is marked implemented, and CLAUDE.md notes the gate for the Multi-user paragraph and for anyone adding a settings write. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
5.8 KiB
Multi-User Mode
Share one Codeman with a small trusted team. Each person gets their own login and workspace, and sessions, cases, search, and live events are scoped to their owner.
Off by default. Without the flag, behaviour is identical to single-user Codeman, because every scoping check short-circuits.
Read this before enabling it
Multi-user mode separates workspaces. It does not sandbox users from each other.
Every session still runs as the same operating system account. A determined user's agent can reach another user's files, because at the OS level they are the same user. This is a convenience and organization feature, not a security boundary.
If you need real isolation:
- Pair each user with Docker Cases, which gives their work its own filesystem and network.
- Or run separate Codeman instances under separate OS accounts, each with its own
CODEMAN_INSTANCE.
"Small trusted team" is the honest description of who this is for.
Enabling it
codeman users add alice --admin # create the first admin, prompts for a password
codeman web --multiuser # or CODEMAN_MULTIUSER=1
Then manage users from the CLI or the Users entry in App Settings:
codeman users add bob # a regular user
codeman users list
codeman users passwd bob # reset to a one-time password
codeman users rm bob
--password-stdin reads the password from standard input, for scripts.
Accounts live in ~/.codeman/users.json with scrypt-hashed passwords, mode 0600.
Administrative actions are audited to ~/.codeman/admin-audit.jsonl.
What each user gets
| Thing | Scope |
|---|---|
| Case space | ~/codeman-users/<name>/cases, their own. |
| Sessions | Only theirs are listed, reachable, or controllable. |
| Events | Live event routing is per owner, and fails closed. |
| Search | Scoped on read, including historical results. |
| File previews | Scoped to sessions they own. |
| Path picker | Only their own user space as a root, not the whole home directory. |
Admins see everything.
Ownership threads through every list endpoint, the session lookup helper, the WebSocket layer, and file previews. A user cannot address another user's session even by id.
Server-wide settings are admin only
There is one set of server settings (~/.codeman/settings.json) for everyone: the feature
switches, the run mode, respawn presets, the case order, the Cloudflare tunnel, the default
models. Every user can read them, but only an admin can change them. For a regular
user the settings write routes answer 403 FORBIDDEN (see the
HTTP API and docs/api-reference.md).
In the browser this means:
- App Settings → Save still keeps a regular user's per-device settings (skin, fonts, header buttons, keyboard bar and the rest of the per-device keys) on that device. If they also changed a server-wide setting, one notice says it can only be changed by an admin, and the setting keeps the server's value.
- A regular user's run-mode pick and respawn presets are kept in that browser and not sent to the server, and their last used case is not recorded server-wide. What an admin set still loads on the next visit.
- Reordering cases and switching the tunnel on or off are admin actions.
Per-user server settings are not part of this version.
Safer defaults for regular users
Non-admins get tighter defaults, and lifting them is an explicit per-user grant:
| Default | Meaning |
|---|---|
Claude runs in auto permission mode |
Anthropic's classifier-guarded mode instead of skip-prompts. |
| Raw shell sessions require a grant | A plain shell is unmediated machine access. |
| Skip-permissions requires a grant | Same reasoning. |
Cron launchCommand requires a grant |
It is an arbitrary command on a schedule. |
| Pi project trust defaults to off | Trust makes Pi execute repo-local TypeScript. |
These exist because the OS boundary is shared. They narrow what a normal account can do casually; they do not make the account a sandbox.
Accounts and sessions
Each user authenticates with their own name and password rather than the shared
CODEMAN_PASSWORD. Logins are individually revocable: disable, reset, or delete an account
at any time, and existing browser sessions can be revoked.
Gotchas
- Enabling it does not migrate existing cases into a user space. They stay where they are, owned by whoever the ownership rules resolve them to.
- Admins see everything, including other users' sessions. Choose admins accordingly.
- The audit log is append-only and local. Ship it somewhere if you care about it.
- It is not a substitute for OS accounts. Restating this because it is the one thing people get wrong.
Read next
- Security - where this fits in the model, and what it does not cover.
- Docker Cases - the isolation story that actually isolates.
docs/multi-user-plan.md- the design.