Roles and permissions
On this page
Polyant authorizes every management-API request against a permission, not against a role name. Roles are named bundles of permissions; the permission is what the route declares and what the guard checks.
This page is the reference for the permission taxonomy, the four system roles and their exact grants, how a decision is resolved, and how custom roles and API keys fit in.
Two tiers of permission
Every permission is decided at one of two levels, and which one is a property of the permission itself:
| Tier | Decided against | Examples |
|---|---|---|
| Workspace | the caller’s workspace binding, falling back to the organization binding | everything under agent., plus agent:*, conversation:*, memory:*, analytics:read, audit_log:read |
| Organization | the caller’s organization binding only | org:*, org.member:manage, org.plugin:*, workspace:write, workspace.member:manage, skill.catalog:*, org.secret:*, org.governance:*, org.audit:read |
The distinction is not cosmetic. An organization-addressed route has no workspace to resolve a workspace-tier permission against, so several org-tier keys exist precisely as the siblings of workspace-tier ones - org.secret:read beside agent.secret:read, org.governance:read beside agent.governance:read, org.audit:read beside audit_log:read. Gating an organization-wide surface on the agent-level key would mean one agent’s rights reading the whole organization: a Member holds agent.secret:read for the agents they build, and that must not open the tenant’s provider connections.
The permission taxonomy
A permission is resource:action. Agent-scoped resources are namespaced under agent..
Workspace tier
| Permission | Covers |
|---|---|
agent:read / agent:write / agent:delete | An agent’s identity and lifecycle, and (managed services) which connection each of its credential roles is bound to |
agent.playground:use | Testing an agent from the panel: the Playground and the agent page’s test chat, through the panel session. It needs neither the agent’s API key nor its Web channel |
agent.prompt:read / agent.prompt:write | Prompt sections |
agent.tool:read / agent.tool:write | Enabled tools, and the hook-function catalogue |
agent.skill:read / agent.skill:write | Skill assignments, pins, and skill env |
agent.knowledge:read / agent.knowledge:write | Knowledge documents, including its export/import |
agent.channel:read / agent.channel:write | Channel configuration |
agent.room:read / agent.room:write | Room configuration and event sources |
agent.task:read / agent.task:write | Scheduled tasks |
agent.secret:read / agent.secret:write | One agent’s encrypted secrets, and (managed services) its private provider connections |
agent.governance:read / agent.governance:write | Governance, compliance, hooks, and opt-out |
agent.export:read | The full configuration export |
conversation:read / conversation:delete | Conversations, their state, and retention |
memory:read / memory:write | The memory store |
analytics:read | Analytics and the activity stream |
audit_log:read | The tool audit log |
agent.dev:write | Issuing, inspecting and revoking an agent’s dev-mode session |
workspace.knowledge:write | Filling a workspace’s own knowledge library |
Organization tier
| Permission | Covers |
|---|---|
org:read / org:write | Organization settings, custom roles, API keys. org:read is the membership floor every role holds, not a general read grant |
org.member:manage | Who belongs to the organization, and invitations |
workspace:write | Which workspaces exist - creating, renaming, deleting them |
workspace.member:manage | Placing a person in a workspace (the workspace-scope bindings) |
workspace.assignment:manage | Which skills, plugins and AI providers a workspace may draw on |
workspace.knowledge:manage | Which workspaces may draw on a shared document |
org.knowledge:read / org.knowledge:write | Reading a shared knowledge library, and filling the organization’s |
org.plugin:read | The organization’s plugins, their health and the marketplace catalogue, read-only |
org.plugin:manage | (managed services) Installing a marketplace plugin, switching its version (update or rollback) and uninstalling it |
skill.catalog:read / skill.catalog:write | The organization’s skill catalogue |
org.secret:read / org.secret:write | The organization’s shared secrets, its provider connections, its own credential roles, the Organization-credentials-only switch, and the embedder of its shared knowledge libraries |
org.governance:read / org.governance:write | The organization’s governance policy catalogue |
org.audit:read | The authorization audit trail, and the organization’s own management-audit trail |
org.analytics:read | The organization-wide analytics, including what each workspace spends |
Those last three groups of keys, and the three workspace ones, are what make a custom role able to express a standing the four system roles cannot - “may create workspaces but administers nobody”, or “may read the authorization audit and nothing else”.
Some of those keys deserve their own note:
workspace.assignment:manageis organization-tier on purpose, even though what it edits is a single workspace’s allow-list: the person the allow-list constrains must not be able to lift it. An admin bound only to that workspace is refused - and the refusal actually comes from the route shape rather than the tier, because the routes carry an organization segment and the scope resolves to no workspace, which no workspace binding can match. The org-tier declaration is the belt to that braces: it keeps the refusal in place if the route shape ever changes.org.knowledge:readis separate fromorg:readfor the same reason.org:readis held by every system role, so a disclosure gated on it is public inside the tenant - and a shared library lists what an organization has written down. The two write keys beside it are organization-tier on theworkspace.assignment:managereasoning: the people an allow-list constrains must not be able to lift it.agent.dev:writereads secret values. A dev session bridges a developer’s local tools onto a running agent, and the bridge hands those tools the agent’s resolved credentials - so this key is a stronger grant than its name suggests and sits above the ordinary agent-configuration keys. See Dev mode.org.plugin:readwas split out oforg:read.org:readis the membership floor that every role holds - it answers “you are inside this tenant”, which is not the same question as “you may enumerate what this installation runs”. Member and Viewer consequently no longer read the plugin inventory. Nothing else moved:org:readstill covers organization settings.org.plugin:manageis what changes the tenant’s code. An installed plugin runs inside the engine for every agent the organization assigns it to, so installing one, or moving it to another release, is an Admin decision. Which marketplaces exist, which releases are blocked and which plugins an organization may not install stay with a platform admin, by role rather than by permission. See Plugins.
The REST API reference lists the permission each route requires.
agent.secret:read is narrower than it sounds: the API returns configured secret key names, never values, so a secret is write-only through the API. That is what makes it safe to grant to a Member - see below.
The four system roles
| Role | Level | In one line |
|---|---|---|
| Owner | 40 | Everything, including organization settings |
| Admin | 30 | Destruction, governance, forensics, and the organization’s own tenancy |
| Member | 20 | Configures an agent end to end, credentials included, in its own workspaces |
| Viewer | 10 | Read-only, agent secrets excluded |
The level is a hierarchy used to prevent privilege escalation, not an extra permission.
The grants are strictly nested - each role holds everything the role below it holds, plus its own additions:
| Role | Adds on top of the role below |
|---|---|
| Viewer | agent:read, agent.playground:use, agent.prompt:read, agent.tool:read, agent.skill:read, agent.knowledge:read, agent.channel:read, agent.room:read, agent.task:read, agent.governance:read, conversation:read, memory:read, analytics:read, skill.catalog:read, org:read, org.knowledge:read, org.governance:read |
| Member | agent:write, agent.prompt:write, agent.tool:write, agent.skill:write, agent.knowledge:write, agent.channel:write, agent.room:write, agent.task:write, memory:write, agent.secret:read, agent.secret:write, agent.export:read |
| Admin | agent:delete, agent.dev:write, agent.governance:write, conversation:delete, skill.catalog:write, org.member:manage, workspace:write, workspace.member:manage, workspace.assignment:manage, workspace.knowledge:manage, workspace.knowledge:write, org.knowledge:write, org.plugin:read, org.plugin:manage, audit_log:read, org.secret:read, org.secret:write, org.governance:write, org.audit:read, org.analytics:read |
| Owner | org:write |
Where the lines fall, and why:
- A Member configures an agent end to end, credentials included. Requiring Admin to attach a channel or set an API key would mean granting Admin to everyone who ships an agent, which is not a role boundary at all. The exposure is narrower than the key names suggest: the secrets API returns key names only, so a secret is write-only, and the organization’s shared credentials stay at Admin under
org.secret:*.agent.export:readsits at Member for the same reason - the bundle enumerates key names, carries no values, and strips credential-like channel configuration. - The Member/Admin line is destruction, governance and forensics - not configuration. Member builds; Admin destroys, governs and audits, and holds the organization’s own tenancy (people, workspaces, catalogue, shared credentials).
- Every role may test an agent.
agent.playground:usesits at Viewer because testing an agent from the panel is not editing it. With managed services, the 1.2.0 upgrade also granted it to every custom role holdingagent:write; any other custom role needs it added in the role editor. - A Viewer cannot see agent secrets at all - not even which keys are configured. Deliberate, not an oversight in the read tier. It does read the organization’s policy catalogue, which is consistent with a read-everything role; writing it is Admin.
conversation:deletealso gates the retention policy, because a scheduled purge is a deletion schedule, not a setting.
How a decision is made
Which organization the decision is made in
Not the one in your session token - the one the request addresses. The scope is resolved most-specific-first: the agent named in the path, else the organization named in the path or the X-Org-Slug header, else the organization recorded in the token.
That last one is only a landing preference. A person who belongs to two organizations is judged by the bindings they hold in the organization they are looking at, so an Owner of A is a Viewer in B if that is what B granted them. A caller holding nothing in the addressed organization is refused by that lookup finding no bindings.
For a request addressing an agent, the organization is the agent’s own - a fact from the agent’s workspace, never compared against the token. Its own bindings there decide the answer.
Then, in order
- Platform-admin bypass. A platform admin is allowed, ahead of any role resolution. This is an installation-level flag on the user, read from the database rather than from the session token, not an organization role - see Authentication. The same flag also decides which organizations they may address at all: on a route naming an organization, it is consulted after the membership lookup has found nothing, which is what lets a principal who belongs to no organization administer every one of them. See Where a platform admin reaches.
- Workspace binding, if one exists for the agent’s workspace, and the permission is workspace-tier. It is authoritative: it both grants permissions the organization baseline lacks and revokes ones the baseline grants. Most-specific-wins, in both directions. Workspace-scoped bindings are available with managed services.
- Organization binding, otherwise - and always, for an organization-tier permission.
- Deny. No applicable binding means no access - empty is deny, everywhere.
Because a workspace binding replaces rather than adds to the org baseline, giving someone a Viewer binding on one workspace is how you narrow an org-wide Admin down for that workspace.
Enforcement fails closed in both directions: a denied permission is refused, and so is a route that declares no permission at all.
Bindings are cached briefly for the hot path. A membership change flushes the acting user’s cache immediately, so a role assignment takes effect on the very next request. A permission change to a custom role self-heals within the cache TTL instead - plan a revocation accordingly rather than assuming it is instant.
Two guards protect against lock-out and escalation on every membership mutation:
- Owner-last. An organization can never be left without an Owner, whether by demoting or by removing its only one.
- No self-escalation. An operator cannot grant a role above their own level, nor modify a member who already outranks them.
Two refinements to that second guard matter:
- A platform admin outranks everyone. They normally hold no binding inside a tenant, which put them at level 0 - below a Viewer - so every membership mutation was refused for the one principal the guard otherwise waves through. Concretely, an organization that had lost its last Owner could not be repaired by anybody. A platform admin now ranks above every role.
- For a custom role, the level is not the test - the permission set is. A system role’s level is a faithful proxy for what it carries, because system roles are strictly nested. A custom role’s level and its permissions are chosen independently, so a level-10 custom role can legitimately contain
org:write. Ranking it by level alone would let an Admin hand out a low-level role carrying a permission the Admin does not hold - escalation laundered through the role catalogue. The level cap still applies, but the real check is a subset test: you may only hand out permissions you already have.
Custom roles (managed services)
Managed services. Available with Polyant managed services.
An organization can define its own roles: a key, a display name, a level (0 to 100), and any subset of the permission taxonomy above. Custom roles are per-organization and are resolved exactly like system roles - the resolution rules are unchanged, only the set of available roles grows.
System roles are immutable, and a custom role can never take a system role’s key. See Roles (admin panel).
Management API keys
A management API key authenticates as a service principal rather than a user: it is bound to one organization and carries an explicit permission set. It never gets the platform-admin bypass, and it can never address a second organization - that organization is its whole authority.
A key’s authority is stamped on the key row and is not derived from whoever created it. A key minted by a platform admin therefore keeps working after that flag is removed, and only deleting the key stops it.
Without the granular-API-keys licence entitlement, a key carries the full Owner permission set. With it, a key can be restricted to any subset of that set - never more. See API keys.
The installation role is a different axis
The users table also carries an installation-level boolean, is_platform_admin, used by the account administration API in the Admin Console. That axis governs who can administer sign-in accounts; the roles on this page govern what an operator can do inside an organization. Do not conflate the two.
It is a flag rather than a role value: the users.role column that used to hold platform_admin (earlier superadmin) has been dropped. See Platform members.
See also
- Members and roles - assigning organization roles.
- Workspaces - workspace-scoped bindings.
- Roles - the custom-role editor.
- API keys - service principals.
- Authorization audit - the trail of role and membership changes.
- REST API reference - per-route permissions.