Platform
ScaiWave ScaiGrid ScaiCore ScaiBot ScaiDrive ScaiKey Models Tools & Services
Solutions
Organisations Developers Internet Service Providers Managed Service Providers AI-in-a-Box
Resources
Support Documentation Blog Downloads
Company
About Research Careers Investment Opportunities Contact
Log in

Custom Roles

The six built-in roles cover 80% of needs. For the remaining 20% — cross-cutting access patterns, module-specific personas, tenant-specific hierarchies — use custom roles. Compose exactly the permissions you want from the platform's core + module permission set, assign to users.

For basics, see Roles and Permissions.

Anatomy of a custom role#

json
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
{
  "id": "role_abc",
  "tenant_id": "tenant_acme",
  "name": "Analytics Team",
  "slug": "analytics",
  "description": "Read-only usage + export, no admin access",
  "core_permissions": [
    "accounting:view_tenant",
    "models:list"
  ],
  "module_permissions": [
    "scaimatrix:view",
    "scaimatrix:search"
  ],
  "created_by": "user_tenant_admin",
  "created_at": "2026-04-22T10:00:00Z",
  "updated_at": "..."
}
  • Tenant-scoped. Custom roles live inside a tenant. A super admin could create a shared template, but the role instances are per-tenant.
  • Composable. Mix core permissions with module permissions freely. Must be a subset of what the tenant has enabled.
  • Additive. Assigning a custom role doesn't revoke built-in role permissions; both stack. User's effective permission set is the union.

Design patterns#

Pattern 1: Read-only specialist#

Most common pattern — give a team read access to something but not write:

json
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
{
  "name": "Support Read-Only",
  "slug": "support-ro",
  "core_permissions": ["models:list", "accounting:view_own"],
  "module_permissions": [
    "scaibot:bots:read",
    "scaibot:conversations:read",
    "scaimatrix:search"
  ]
}

Support team can look at bots, see conversation histories, search the knowledge base — but can't modify anything. Useful for first-line support who observe but don't configure.

Pattern 2: Domain-scoped power user#

Grant full control over one module, no other admin:

json
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
{
  "name": "Knowledge Administrator",
  "slug": "knowledge-admin",
  "core_permissions": ["models:use"],
  "module_permissions": [
    "scaimatrix:view",
    "scaimatrix:search",
    "scaimatrix:ingest",
    "scaimatrix:manage",
    "scaimatrix:graph_edit",
    "scaimatrix:access"
  ]
}

The owner of your knowledge base can do anything within ScaiMatrix but can't touch bots, accounting, users, other modules.

Pattern 3: Service account with narrow scope#

For a specific integration's API key — narrow it to exactly what it needs:

json
1
2
3
4
5
6
{
  "name": "Analytics Service",
  "slug": "svc-analytics",
  "core_permissions": ["accounting:view_tenant", "models:list"],
  "module_permissions": []
}

Create a user for the service, assign this role, create an API key under that user. The key can read usage; it can't do anything else even if leaked.

Pattern 4: Escalation handler#

Route human-in-the-loop decisions:

json
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
{
  "name": "Checkpoint Resolver",
  "slug": "resolver",
  "core_permissions": [],
  "module_permissions": [
    "scaicore:view",
    "scaicore:checkpoint_resolve",
    "scaiqueue:view",
    "scaiqueue:consume"
  ]
}

People with this role handle human-in-the-loop tasks queued by agents. They can see what's pending, resolve it, but can't change how agents themselves are configured.

Managing custom roles#

Creating#

bash
1
2
3
4
curl -X POST https://scaigrid.scailabs.ai/v1/custom-roles \
  -H "Authorization: Bearer $ADMIN_TOKEN" \
  -H "Content-Type: application/json" \
  -d @role-definition.json

Validates that all requested permissions exist and that the tenant has the relevant modules enabled.

Listing available permissions#

Before building a role, see what's available:

bash
1
2
curl https://scaigrid.scailabs.ai/v1/custom-roles/available-permissions \
  -H "Authorization: Bearer $ADMIN_TOKEN"

Returns core permissions plus permissions from every enabled module, grouped by module. The admin UI has a visual picker built on this.

Assigning to users#

bash
1
2
3
4
5
6
7
curl -X PUT https://scaigrid.scailabs.ai/v1/users/{user_id}/roles \
  -H "Authorization: Bearer $ADMIN_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "roles": ["tenant_user"],
    "custom_role_ids": ["role_analytics", "role_knowledge_admin"]
  }'

A user can have multiple custom roles. Effective permissions = union of all assigned roles + any directly-granted module permissions.

Updating#

bash
1
2
3
4
curl -X PUT https://scaigrid.scailabs.ai/v1/custom-roles/{role_id} \
  -H "Authorization: Bearer $ADMIN_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"module_permissions": [...updated list...]}'

Changes apply to all users with the role immediately, on their next request.

Deleting#

bash
1
2
curl -X DELETE https://scaigrid.scailabs.ai/v1/custom-roles/{role_id} \
  -H "Authorization: Bearer $ADMIN_TOKEN"

Users who had the role lose its permissions. Their built-in roles remain.

Precedence and conflicts#

A user's effective permissions come from:

  1. Built-in roles (union of permission sets)
  2. Custom roles (union)
  3. Direct module permission grants

All three contribute. There's no negation — you can't have a role that revokes a permission. If a user has tenant_user (which includes models:use) plus a custom role without it, they still have models:use.

To restrict a user, give them only what they need — don't try to "subtract" permissions.

Anti-patterns to avoid#

  • One role per user. If you're creating a unique role for every user, use direct module permission grants instead — they're per-user by design.
  • Mirror of built-in roles. Don't re-create tenant_admin as a custom role. Use the built-in.
  • Too many roles, too similar. If you have analytics-ro, analytics-export, analytics-dashboard, consider whether one role covers all three cases.

Group mappings + custom roles#

Group mappings can target custom roles as well as built-in:

bash
1
2
3
4
5
6
7
8
curl -X POST https://scaigrid.scailabs.ai/v1/role-mappings \
  -H "Authorization: Bearer $ADMIN_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "scaikey_group": "acme-support-team",
    "scaigrid_role": "support-ro",
    "tenant_id": "tenant_acme"
  }'

Users in the ScaiKey group automatically get the custom role on authentication. Remove from the group → auto-revoke (if configured).

Updated 2026-05-18 15:01:28 View source (.md) rev 17