Skip to content

Roles & Permissions

Studio uses a two-tier role system: workspace roles determine organizational access, and project roles control content operations.

Workspace Roles

RoleDescriptionAccess Level
OwnerCreator of the workspace. Full control.Implicit access to all projects. Can manage billing, members, settings.
AdminTrusted team lead. Nearly full control.Implicit access to all projects. Can manage members and settings. Cannot transfer ownership or delete workspace.
MemberStandard team member.No implicit project access. Needs explicit project_members assignment.

Workspace Role Hierarchy

Owner > Admin > Member
  • A workspace has exactly one owner (transferable)
  • Admins and members are added via invitation (email)
  • Invited members must accept before gaining access

Project Roles

Project roles are assigned per project to workspace members:

RoleDescriptionContent Access
EditorContent creator.Can create, update, delete content and media. Cannot merge/reject branches.
ReviewerContent approver.Can read all content, merge/reject branches, approve/reject form submissions. Cannot create content.
ViewerRead-only observer.Can read content, models, and submissions. Cannot modify anything.

Role Resolution

Workspace Owner and Admin get all project permissions regardless of project_members assignment. Only workspace Members need explicit project roles.

Tool Access Matrix

This matrix shows which roles can use each agent tool:

ToolViewerReviewerEditorAdminOwner
Read Operations
list_modelsYesYesYesYesYes
get_contentYesYesYesYesYes
brain_queryYesYesYesYesYes
brain_searchYesYesYesYesYes
brain_analyzeYesYesYesYesYes
validateYesYesYesYesYes
validate_schemaYesYesYesYesYes
list_branchesYesYesYesYesYes
branch_healthYesYesYesYesYes
relation_expandYesYesYesYesYes
search_mediaYesYesYesYesYes
get_mediaYesYesYesYesYes
list_submissionsYesYesYesYesYes
Content Operations
save_content----YesYesYes
delete_content----YesYesYes
copy_locale----YesYesYes
update_status----YesYesYes
vocabulary----YesYesYes
upload_media----YesYesYes
update_media----YesYesYes
delete_media----YesYesYes
Review Operations
merge_branch--Yes--YesYes
reject_branch--Yes--YesYes
approve_submission--Yes--YesYes
reject_submission--Yes--YesYes
Admin Operations
save_model------YesYes
delete_model------YesYes
init_project------YesYes
add_locale------YesYes

Permission Resolution

ts
async function resolveAgentPermissions(
  userId: string,
  workspaceId: string,
  projectId: string,
  accessToken: string,
): Promise<AgentPermissions>

Resolution Flow

1. Get workspace member role
   |
   +-- Owner/Admin? → Full access (all tools)
   |
   +-- Member? → Continue to step 2
   |
2. Get project member record
   |
   +-- No record? → No access (empty tools list)
   |
   +-- Has role? → Continue to step 3
   |
3. Normalize role (EE bridge gate)
   |
   +-- EE bridge present? → reviewer/viewer kept as-is on all paid plans
   |                        (Starter, Pro, Enterprise). specificModels is
   |                        honored only when the plan grants it (Pro+).
   |
   +-- No EE bridge (Community Edition)? → reviewer/viewer downgrade to
   |                                       editor, specificModels forced false
   |
4. Filter tools by effective role

AgentPermissions Object

ts
interface AgentPermissions {
  workspaceRole: 'owner' | 'admin' | 'member'
  projectRole: 'editor' | 'reviewer' | 'viewer' | null
  specificModels: boolean       // Model-level restriction active?
  allowedModels: string[]       // Restricted model IDs
  allowedLocales: string[]      // Restricted locale codes
  availableTools: string[]      // Tools this user can invoke
}

Model-Specific Access

On Pro and Enterprise plans, project members can be restricted to specific content models:

ts
{
  role: 'editor',
  specificModels: true,
  allowedModels: ['blog-post', 'team-members']
}

When specificModels is true:

  • The agent only allows tools on models in allowedModels
  • Content reads for other models return access denied errors
  • The system prompt informs the agent of the restriction

Pro feature, EE-gated

Model-specific access requires the roles.specific_models feature flag, granted on Pro and Enterprise plans. The flag is also requires_ee, so it only functions with the Enterprise Edition bridge present. On Free and Starter plans, and in a self-hosted Community Edition deployment, specificModels is always treated as false (full model access).

Workflow Interaction

Permissions interact with the workflow configuration:

Auto-Merge Workflow

All write operations (from any permitted role) are automatically merged through the branch pipeline.

Review Workflow

RoleWrite Behavior
Owner / AdminWrites auto-merge (authorized to approve their own work)
EditorWrites create cr/* branches that wait for review
ReviewerCan merge/reject branches created by editors
ts
function shouldAutoMerge(workflow: string, permissions: AgentPermissions): boolean {
  if (workflow === 'auto-merge') return true
  return permissions.workspaceRole === 'owner' || permissions.workspaceRole === 'admin'
}

API Route Enforcement

Permissions are enforced at multiple levels:

Server Middleware

The auth middleware (01.auth.ts) validates session tokens on every request. Public endpoints are explicitly allowlisted.

Route-Level Checks

ts
// In a route handler
const session = requireAuth(event)
const db = useDatabaseProvider()

// Verify workspace membership with required role
await db.requireWorkspaceRole(
  session.accessToken,
  session.user.id,
  workspaceId,
  ['owner', 'admin'],
)

Agent-Level Enforcement

The agent system filters available tools based on resolved permissions before sending them to the LLM:

ts
const permissions = await resolveAgentPermissions(userId, workspaceId, projectId, accessToken)
const tools = filterToolsByPermissions(STUDIO_TOOLS, permissions.availableTools)
const phaseTools = filterToolsByPhase(tools, phase)

Billing Enforcement

The billing middleware (03.billing.ts) checks workspace billing state and blocks requests when subscriptions are locked:

Billing StateEffect
subscribedFull access
trialingFull access
grace_periodFull access (payment overdue warning)
trial_expired402 blocked
canceled_expired402 blocked

Plan Limits

Permissions are further constrained by plan-based numeric limits:

LimitFreeStarterProEnterprise
Team Members1325Unlimited
AI Messages/Month01501,500Unlimited
Media Storage1 GB15 GB100 GB
CDN API Keys0325Unlimited
CDN Bandwidth02 GB60 GBUnlimited
Form Models0115Unlimited
Form Submissions/Month01003,000Unlimited
Outbound Webhooks0325Unlimited
Conversation API Keys0015Unlimited
API Messages/Month01003,000Unlimited
MCP Cloud Keys0115Unlimited
MCP Cloud Calls/Month05,000150,000Unlimited

Released under the AGPL-3.0 License.