Skip to content

RBAC

RoleSummary
ownerEverything below + billing, project settings, delete project
adminEverything below + mint/revoke tokens, invite users, configure SMTP, pause schedules
operatorEverything below + retry / cancel / bulk-retry / purge queue
viewerRead-only: list tasks, view events, read schedules, read agents

Roles are project-scoped - you can be admin on one project and viewer on another.

Every API endpoint has a required role declared in the route decorator:

@router.post("/tasks/{task_id}/retry")
@requires_role(Role.OPERATOR)
async def retry_task(...): ...

Enforcement happens on request - the session resolves user × project → role. 403 if insufficient.

The frontend also hides actions the user can’t perform, but this is UI polish only; the backend is authoritative.

Admins can invite users to a project at a specific role:

  1. Settings → Memberships → Invite.
  2. User receives an email with a one-shot token.
  3. On sign-up, the token resolves to (project_id, role) and membership is created.
  4. Token expires in 72 hours if unused.

SMTP must be configured for invitations; otherwise admins can copy the invite URL and share manually.

Admins can change any non-owner role. Only owners can promote others to owner, and the brain refuses to let the last owner demote themselves (would brick the project).

A user can belong to multiple projects. The UI shows a project switcher in the top bar. Agents are project-scoped - an agent only sees one project.

  • Admins can remove non-owner members.
  • Removing a member revokes all their sessions immediately.
  • Owners cannot be removed by admins (only by other owners).

Every membership change writes an audit log entry: action=membership.invited / accepted / role_changed / removed. Chain-signed; cannot be deleted.

See audit log.