Shared project accounts
Create a local account and grant roles only for the projects that person should see. Review the role table before allowing contributions or maintenance, and revoke access when it is no longer needed.
Share review access
The server owner can create local accounts and assign one of four project roles; each role includes everything the roles before it may do. A viewer reads project run results, safe verification metadata, changed-file diffs and sanitized result exports. A reviewer also records human file-review coverage and comments in a separate thread anchored to the exact result commit. A contributor also owns tasks on the project's team board and runs them on their own computer with their own agents. A maintainer also assigns any task owner, defines a project's repository keys, deletes board tasks and checkpoints, revokes runners, cancels hand-overs and approves instructions to agents; accounts and roles stay with the owner. The contributor and maintainer capabilities are described in Team collaboration. The owner reads and replies to comments through Changes → Human collaboration comments on the normal run page. Comments are collaboration records: they never enter an agent's prompt or resume work.
The owner retains administration and generic run controls. Project roles alone do not allow users to start or resume arbitrary runs on this server, approve agent/tool requests, send agent notes, run checks/setup/services, change repository files, choose Docker images or authentication volumes, use terminals, merge/push/post to GitHub, edit private memory/conventions, configure integrations, manage accounts or inspect global filesystem/settings/quotas. Project assignment is not an operating-system sandbox. An explicit owner grant under Settings → Connections → Share access → People allows a contributor to queue their own team tasks on the host through the dedicated host execution queue. This delegates host execution authority to trusted teammates; it does not provide an operating-system sandbox. Generic run and shell APIs remain owner-only. A separate interactive terminal grant lets a trusted contributor open their own shell on the host. That shell has the host OS user’s authority, including file changes and access outside the project; the review API restrictions do not sandbox terminal commands.
The review dashboard uses independent bootstrap requests so shared users do not load the normal composer's global health/configuration APIs. Lists, searches, cursors, attention items, run events, reconnect snapshots and exports must be filtered by current project membership on the server. Unauthorized object identities are answered as unavailable. The dashboard holds one board/review event stream for the tab it shows (/api/events on Results, /api/team/events on Board), reloads on its frames and loads the bell's unread count once with the page, keeping it live only while the Board tab is shown; it sends no periodic request of its own, so an idle dashboard does not renew its session by polling. An open interactive terminal has its own authenticated output stream. Removing a repository from a project removes shared access to its runs. An ambiguous legacy run without an explicit project is not shared automatically.
Shared review projections omit local paths, run commands, environment/volume configuration, raw agent tool events/logs, session identifiers, capability receipts, context/manifests, notes, memory and private conventions. Result summaries and final output are project-visible and have recognized secret patterns redacted; arbitrary sensitive prose cannot be detected reliably. Credential files and rename sources are omitted from shared diffs and coverage. Coverage describes only shared-reviewable files and reports omitted files requiring owner review. Parent/continuation references are included only when that related run is also authorized. Private conventions drafts are owner-only even when a user is assigned to their project.
Shared results bound task text to 24 KiB, summaries to 32 KiB and errors to 4 KiB of UTF-8. Only the latest 200 steps are included, with 8 KiB final-output and 4 KiB error previews per step. Truncation and omitted-step counts are explicit in the API and dashboard. Exports retain these same safe preview limits. Raw transcripts are not shared exports.
Authentication and storage
Accounts live in private CODEFLOW_HOME/shared-accounts.json; the server never returns password hashes or session hashes. Passwords require at least 15 characters and at most 1024 UTF-8 bytes, without normalization or truncation. Built-in scrypt uses a fresh 16-byte salt, a 32-byte key and parameters N=131072, r=8, p=1. Verification compares keys in constant time and performs a dummy derivation for unknown accounts. At most two password derivations run concurrently; a full queue is refused. Login attempts have bounded global, socket-address and username rate limits.
Sessions use 32 random bytes and store only SHA-256 hashes. They expire after 12 hours or 30 minutes idle; each account retains at most eight sessions. Role/display-name/enabled/password changes and owner revocation invalidate every session for the account. Session activity extends idle time in memory; a restart can expire a session earlier than its last activity. Revoked identities must lose open streams immediately. Corrupt or symbolic account storage disables shared authentication without overwriting the file; the owner's printed recovery-token link remains available.
Network sign-in and authenticated shared requests require actual HTTPS, independently of the phone development override. Cookies are HttpOnly and SameSite=Strict, Secure on HTTPS. The server validates Host/Origin and mutation request type. Shared cookies are distinct from owner and phone sessions. An explicit valid owner bearer credential on the local listener takes precedence; otherwise a valid shared cookie takes precedence. The network listener refuses local owner bearer credentials and recovery links; use its separate phone pairing or shared sign-in. Shared sign-in clears the owner browser cookie, and an explicit local owner recovery link clears the shared cookie. Account creation disables first-browser owner claiming.
Backup and restore omit account/session stores, including older archives. Recreate accounts and assign project roles deliberately after restoring. Human collaboration comments can be retained with application data but convey no authentication authority.
API and enforcement contract
POST /api/auth/login {username,password} sets the session cookie. GET /api/auth/self returns only the current public identity; POST /api/auth/logout revokes the current session. Owner administration uses GET/POST /api/accounts, PUT /api/accounts/:id and POST /api/accounts/:id/revoke-sessions. Every mutation carries the exact current account-state revision; stale updates fail with 409 while preserving the existing state. Project IDs must be validated against the current project store before assigning roles.
Run collaboration uses GET /api/runs/:id/collaboration and, for reviewers and higher roles, POST /api/runs/:id/collaboration {branch,expectedHead,text}. The server authenticates the actor and resolves an owned result branch; the store rejects a changed commit. Comments are bounded to 4000 characters and 200 entries per run, with immutable author/time/commit metadata. File reviews use the existing revision-guarded POST /api/runs/:id/review-coverage with authenticated actor audit. User-supplied actor fields never grant identity.
canonicalSharedPath checks the original request target before URL normalization, accepts the versioned /api/v1 alias, and rejects encoded separators, double encoding, dot segments, empty segments and extra ambiguous suffixes. sharedRoutePolicy allows only explicitly enumerated method/path pairs; unknown routes default to owner-only. Global authorization must run before all API/workspace handlers, and resource authorization must precede Git/filesystem operations. Public pairing/webhook routes retain separate secret capabilities and do not inherit a shared user's project roles.
The account, access-policy and comment-store tests cover hash-only storage, modes, exact revisions, role escalation refusal, revocation, expiry, bounded login work, malformed paths/aliases, cross-project membership, projection privacy and durable commit-anchored comments. End-to-end server/browser tests are required before exposing the shared routes.
The password parameters and authorization model follow the OWASP Password Storage Cheat Sheet, Authorization Cheat Sheet and Session Management Cheat Sheet.