Roles & Permissions
Crewship implements role-based access control at two levels: workspace roles (human users) and agent roles (AI agents within crews).Workspace Roles (Human Users)
Users are assigned one of five roles within a workspace:
Roles are defined as the
OrgRole enum in the Prisma schema:
Permission Mapping (Code Implementation)
ThecanRole() function in Go (internal/api/helpers.go) maps roles to internal actions, grouped into three permission tiers:
In the current implementation, MEMBER and VIEWER have identical permissions (both map to
read only). The distinction exists in the schema for future granularity (e.g., MEMBER may gain send_message or run_agent permissions).Mutation routes declare their role at registration (complete mediation)
Every state-changing endpoint (POST/PUT/PATCH/DELETE) declares the
role it requires at route registration, and a single middleware enforces
that declaration before the handler runs. This is Saltzer & Schroeder
complete mediation: authorization is a property of the route table, not a
hand-placed check a new handler might forget.
Workspace-scoped mutations register through authedMut(method, pattern, role, handler)
(internal/api/rbac_routes.go), which records {method, pattern, role} into a
walkable table and mounts the route behind RequireAuth → RequireWorkspace → requireRoleMW(role). The declared role is one of:
create—MANAGER+ (the create/update tier). AMEMBER/VIEWERis refused403.manage—ADMIN+ (the manage/delete tier, e.g. workspace/member administration, feature flags, backups, approvals, hooks, GDPR data deletion).self— self-scoped: the handler enforces ownership byuser_id(own preferences, reactions, a saved view the caller owns, inbox items the caller can see).inline— the handler runs a layered gate the middleware must not pre-empt: the role-or-capability gate (aMEMBERholding an explicit capability passes) or the per-agent owner / per-crew-elevation gate. The middleware guarantees workspace membership and passes through; the handler decides.
MANAGER+ include crew-template deploy, crew
policy, routine execution/control (run, replay, bulk_replay, signal,
metadata, dry_run, test_run, tags, step overrides), checkpoints, agent /
crew persona edits, and crew-composition suggestions.
Two tests make this a build-time invariant
(
internal/api/route_authz_invariant_test.go):
TestEveryMutationRouteDeclaresRole walks the recorded route table and fails
if any mutation route lacks a declared role, and
TestNoLegacyAuthedMutationRegistration fails if a mutation route is
registered through the old authed(...) chain instead of authedMut /
authedSelfMut. Adding a new mutation route without declaring its role
fails the build — the omission that previously slipped past review can no
longer ship. The pre-existing inline requireRole / canRole checks are
kept as belt-and-suspenders behind the middleware.Signup Control
New user registration is controlled by theCREWSHIP_ALLOW_SIGNUP environment variable (or auth.allow_signup in YAML config). When disabled, only existing users can invite new members.
Agent Roles
Every AI agent has one of two functional roles:AGENT
Individual contributor. Executes tasks, writes code, runs tools. The standard role for most agents.
LEAD
Crew orchestrator. Assigns tasks to agents, creates missions, monitors progress. Has access to the full sidecar API.
Agent Role Capabilities
The Equality Principle
Agent roles are functional, not hierarchical. A Lead is an equal colleague with orchestration responsibility — not a boss. This is a core Crewship philosophy.
You are part of a crew on the Crewship — an expedition with a shared purpose that transcends any individual.LEAD:
You are a crew member with orchestration responsibility. You are not a boss — you are an equal colleague who carries the soul and mission of the expedition to the whole team.
Internal API Authentication
The internal API (sidecar-to-crewshipd communication) uses token-based authentication:- Auto-generated cryptographically at startup if not configured
- Passed to sidecar processes via the IPC config
- Verified on every internal API request
Container Security Boundaries
Agent processes run as UID 1001, while the sidecar runs as UID 1002. This prevents agents from:- Reading the sidecar’s credential store
- Modifying network policy configuration
- Accessing the IPC token
- Tampering with the proxy’s authentication headers
Credential Access Control
Credentials are protected by multiple layers:- Workspace scoping: Credentials belong to a workspace
- Agent assignment: Credentials must be explicitly assigned to agents
- Encryption at rest: AES-256-GCM with versioned keys
- Sidecar injection: Agents never see raw credential values
- Keeper gating: L2+ credentials require AI evaluation
- Audit trail: All credential access is logged
JWT Authentication
User authentication uses JWT tokens signed withNEXTAUTH_SECRET:
- WebSocket connections use short-lived tokens (
ws_token_expiry, default 5 minutes) - API requests use session-based JWT tokens
- Token validation is handled by the middleware layer