Skip to Content
Polyant is open source under AGPL-3.0 — star us on GitHub.
ReferenceRoles & Permissions

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:

TierDecided againstExamples
Workspacethe caller’s workspace binding, falling back to the organization bindingeverything under agent., plus agent:*, conversation:*, memory:*, analytics:read, audit_log:read
Organizationthe caller’s organization binding onlyorg:*, 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

PermissionCovers
agent:read / agent:write / agent:deleteAn agent’s identity and lifecycle, and (managed services) which connection each of its credential roles is bound to
agent.playground:useTesting 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:writePrompt sections
agent.tool:read / agent.tool:writeEnabled tools, and the hook-function catalogue
agent.skill:read / agent.skill:writeSkill assignments, pins, and skill env
agent.knowledge:read / agent.knowledge:writeKnowledge documents, including its export/import
agent.channel:read / agent.channel:writeChannel configuration
agent.room:read / agent.room:writeRoom configuration and event sources
agent.task:read / agent.task:writeScheduled tasks
agent.secret:read / agent.secret:writeOne agent’s encrypted secrets, and (managed services) its private provider connections
agent.governance:read / agent.governance:writeGovernance, compliance, hooks, and opt-out
agent.export:readThe full configuration export
conversation:read / conversation:deleteConversations, their state, and retention
memory:read / memory:writeThe memory store
analytics:readAnalytics and the activity stream
audit_log:readThe tool audit log
agent.dev:writeIssuing, inspecting and revoking an agent’s dev-mode session
workspace.knowledge:writeFilling a workspace’s own knowledge library

Organization tier

PermissionCovers
org:read / org:writeOrganization settings, custom roles, API keys. org:read is the membership floor every role holds, not a general read grant
org.member:manageWho belongs to the organization, and invitations
workspace:writeWhich workspaces exist - creating, renaming, deleting them
workspace.member:managePlacing a person in a workspace (the workspace-scope bindings)
workspace.assignment:manageWhich skills, plugins and AI providers a workspace may draw on
workspace.knowledge:manageWhich workspaces may draw on a shared document
org.knowledge:read / org.knowledge:writeReading a shared knowledge library, and filling the organization’s
org.plugin:readThe 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:writeThe organization’s skill catalogue
org.secret:read / org.secret:writeThe 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:writeThe organization’s governance policy catalogue
org.audit:readThe authorization audit trail, and the organization’s own management-audit trail
org.analytics:readThe 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:manage is 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:read is separate from org:read for the same reason. org:read is 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 the workspace.assignment:manage reasoning: the people an allow-list constrains must not be able to lift it.
  • agent.dev:write reads 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:read was split out of org:read. org:read is 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:read still covers organization settings.
  • org.plugin:manage is 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

RoleLevelIn one line
Owner40Everything, including organization settings
Admin30Destruction, governance, forensics, and the organization’s own tenancy
Member20Configures an agent end to end, credentials included, in its own workspaces
Viewer10Read-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:

RoleAdds on top of the role below
Vieweragent: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
Memberagent: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
Adminagent: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
Ownerorg: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:read sits 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:use sits 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 holding agent: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:delete also 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

  1. 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.
  2. 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.
  3. Organization binding, otherwise - and always, for an organization-tier permission.
  4. 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

Last updated on