Custom roles
A custom role is a named, admin-authored set of permissions from a fixed catalog, assigned to a member in place of one of the four system roles. It is not a fifth rung on the hierarchy — it replaces the member's rank entirely, pinning it to viewer for every rank-based check in the system, and grants access only through the specific permissions it carries.
That pin matters in one concrete way: a custom-role member does not inherit anything from "viewer" just because their rank reads viewer. Every resource they can reach, they reach because the role explicitly grants it — never because the rank check quietly passed.
The permission catalog
Permissions are named resource:aspect. Most resources have two aspects —
view and manage (create, edit and delete bundled). A few resources
where one action is genuinely irreversible split into three: view,
write (create + edit) and delete as its own, separately grantable
tier — Agents, Tool Registry, MCP Servers, Alerts and Members & Roles all
work this way, so a role can edit an agent without being able to purge one.
| Resource | What it covers |
|---|---|
| Agents | View / create & edit / delete an agent, including tool bindings and running or deploying it. |
| Guardrails | View / edit policy, autopause rules and denylist terms — no delete tier, every action here is reversible. |
| Tool Registry, MCP Servers | View / write / delete, same three-tier shape as Agents. |
| Audit & observability | Read the audit log; view traces, cost and dashboards. |
| Session Insights | View only — the cross-member team roster, per-person profiles, and team comparisons. |
| Billing & budgets | View only. No custom role can ever change a spend cap — that stays admin/owner rank, by design. |
| Alerts | View / write / delete alert channels. |
| Members & roles | View / manage (invite, change role, assign a custom role, author roles) / delete (revoke an invite, delete a custom role). |
| API keys, SSO & SCIM | View / write / delete keys; SSO/SCIM config is view / write, and the write side is reserved for owners only. |
| Model & provider config | View the model catalog and provider secrets; view routing config and benchmarks. |
Connectors, Workspaces and Org Settings are not in the catalog at all — those stay admin/owner rank only, with no custom-role path in.
Every permission key
The table above groups by resource; this is every individual key the role editor actually checks boxes against, grouped the same way.
Agents
| Permission | Name | What it allows |
|---|---|---|
agents:view | View agents | See agent inventory, config, and ownership. |
agents:write | Create & edit agents | Register, edit, reassign owner, bind/unbind tools, run, or deploy an agent. |
agents:delete | Delete agents | Purge an agent, or a purged tool binding. Permanent. |
Guardrails
| Permission | Name | What it allows |
|---|---|---|
guardrails:view | View guardrails | See inbound + outbound policy, findings, activity feed. |
guardrails:write | Edit guardrails | Edit inbound/outbound policy, autopause rules, denylist terms, and the per-agent on/off switch. |
Tool & MCP governance
| Permission | Name | What it allows |
|---|---|---|
tools:view | View tool registry | See the tool registry and agent bindings. |
tools:write | Create & edit tool registry | Register, edit, enable/disable, or bind/unbind a tool. |
tools:delete | Delete tool registry | Permanently delete an already-disabled tool. |
mcp:view | View MCP servers | See registered MCP servers and their tools. |
mcp:write | Create & edit MCP servers | Register, edit, revoke, or enable/disable a server's tools. |
mcp:delete | Delete MCP servers | Permanently delete an already-revoked MCP server. |
Audit & observability
| Permission | Name | What it allows |
|---|---|---|
audit:read | Read audit log | Read the hash-chained audit ledger. |
observability:view | View observability | Per-call cost, tokens, audit linkage, dashboards, insights, notifications. |
Session Insights
| Permission | Name | What it allows |
|---|---|---|
sessions:view | View team Session Insights | See the cross-member Session Insights team roster, per-person profiles, and team comparisons. |
Billing & budgets
| Permission | Name | What it allows |
|---|---|---|
billing:read | View billing | View invoices, plan, usage, and budget/rate-limit posture. There is no write permission here — changing a budget cap or rate limit stays admin/owner only. |
Alerts
| Permission | Name | What it allows |
|---|---|---|
alerts:view | View alert channels | See configured budget-threshold alert channels. |
alerts:write | Create & edit alert channels | Add, edit, or test-fire an alert channel. |
alerts:delete | Delete alert channels | Permanently remove an alert channel. |
Members & roles
| Permission | Name | What it allows |
|---|---|---|
members:view | View members | See the member, invite, and role list. |
members:write | Manage members | Invite/resend, change role/scopes, deactivate/reactivate, assign a custom role, and create/edit custom roles. |
members:delete | Delete members & roles | Revoke a pending invite, or permanently delete a custom role. |
Identity & access infra
| Permission | Name | What it allows |
|---|---|---|
keys:view | View API keys | See a workspace's API keys and their last-used time. |
keys:write | Create & edit API keys | Create, edit or rotate your own developer keys. These keys can call any allowed model (the chat:write scope) and spend money, so set caps on them. Through a custom role this covers only keys you own: creating a key for someone else, reassigning one, or rotating another member's key is refused. |
keys:delete | Revoke API keys | Permanently revoke a developer key. |
identity_config:view | View SSO/SCIM config | See the SSO / SCIM configuration status. |
identity_config:write | Manage SSO/SCIM config | Configure SSO connection and SCIM provisioning. Owner-only — no custom role can hold this. |
Model & provider config
| Permission | Name | What it allows |
|---|---|---|
models:view | View model catalog | See the served model catalog and live gateway configuration. |
routing:view | View routing | See routing config, benchmarks, the routing model catalog, dry-run a routing plan, and past routing decisions. |
routing:write | Send routing requests | Execute a routing request. This dispatches a real, billable call to a model. |
secrets:view | View provider secrets | See which providers are configured, not the key values. There is no secrets:write/delete key — provider secrets stay admin/owner only, non-delegable. |
Creating and assigning a role
Open Members, Roles tab
Admin and owner only. Lists the four system roles alongside every custom role already defined, each row showing its permission count and how many members currently hold it.
New role: name it and pick permissions
Tick individual
resource:aspectboxes from the catalog above.Create role
The role is validated against the catalog server-side — a permission key outside it is rejected, not silently dropped. It starts with zero members.
Assign it
From the Members tab, open a member's row ⋮ menu and choose Change role — the custom role appears in the same list as the four system roles. Or pick it directly while sending a new invite.
The Roles tab lists system and custom roles in one table — Role, Type (System or Custom), Permissions (a count), and Members (how many currently hold it) — so you can see at a glance how a custom role compares to the four built-in ones before assigning it.
Deleting a role that still has members assigned requires picking a reassignment role for them in the same action — there is no state where a member is left pointing at a role that no longer exists.
Some pages need more than one permission to render
A few console pages are agent-scoped: every real endpoint behind Guardrails,
Tool Registry and MCP Servers reads or writes something under
/v1/agents/{id}/.... A role holding only guardrails:view but not Agents
access would open Guardrails to a page that 403s trying to load the agent
list it needs to render its own table. Rather than let an admin build a role
that looks complete but cannot actually be used, these three stay locked to
whatever the Agents checkbox allows. API Keys works the same way against the
model catalog: minting a key needs models:view for its model picker, so
Keys access is locked to that too. Billing is not needed: without
billing:read the Keys page still loads and keys can still be created; only
the per-key spend column stays empty.
Read-scope grants
Beyond the permission catalog, a member can individually hold a small set of
extra read scopes — audit:read, traces:read — layered on top of their
role. These are not hand-picked through a dialog any more; they are seeded
automatically when a member is invited or has their role changed, from a
fixed default per role (viewer gets audit read; builder gets audit and
traces read), and only when the member has no customized scopes of their own
already. Admin and owner need no entry here — both already read everything
through the role check itself.
How enforcement actually works
Every control-plane endpoint is gated by one of a small set of dependency checks, and they combine two things: a role floor, and (where the resource is in the permission catalog) a specific permission.
- Role only (
require_role("admin")) — the classic floor. A custom-role principal never passes this, at any level, because its rank is pinned to viewer regardless of what it can actually do. - Role or permission (
require_permission_or_role) — the shape most catalog resources use. A caller passes if they hold the role floor or the specific permission key, whichever gets them there. - Role, scope, or permission (
require_role_or_scope) — for resources reachable by both a human (role) and a machine API key (scope), now also admitting a custom-role principal via its permission.
A blocked request returns 403 naming what would have let it through — the
role or the permission, whichever is relevant to how the caller authenticated.
See Errors and refusals for the full shape of that response.

