Agent roles
How an agent's requests are bounded: the three system agent roles, the ceiling-versus-request model, and the delegation ceiling that stops an agent outgrowing the person it acts for.
People get roles. So do agents.
An agent in Oxagen is a principal in its own right, with its own identity and its own role. It does not borrow yours. The resolver decides every capability the agent asks for against that role, audits the call under principal_kind='agent', and meters it to your org. This page covers the three built-in agent roles, how a role combines with the agent's own configuration, and the one rule above the whole model.
For human roles and the IAM resolution order they share, see RBAC and roles.
The three system agent roles
Oxagen seeds every organization with three agent roles. They differ along one axis, what the agent may change. Pick the smallest one that still lets the agent do its job.
| Role | Reads | Mutations | Graph | MCP tools |
|---|---|---|---|---|
| Agent Observer | Allowed | Denied | Read only | All denied |
| Agent Contributor | Allowed | Low- and medium-risk allowed. High-risk routed to a person. | The agent's own setting | First-use consent (ask) |
| Agent Operator | Allowed | High-risk allowed too, except vcs, billing, and secret, which still route to a person | May extend | Allowed |
Agent Observer: read and answer only
The agent can search the graph and answer questions. It cannot write anything, anywhere. The rule denies every mutation outright rather than routing it for approval, caps graph access at read mode, and denies MCP tool calls.
Pick it for question-answering agents, reporting and summarization agents, research agents, and anything customer-facing that should never change state. If you are unsure, start here. Widen later through the role-assignment capabilities.
Agent Contributor: the standard worker
The default. The agent reads freely and makes ordinary changes (drafting documents, updating records), and any high-risk request is routed to a person first. MCP tools need first-use consent.
Pick it for almost everything a person starts and watches: drafting agents, triage agents, and agents you run from chat. Every new agent starts as a Contributor, so this is what you get unless you choose otherwise.
Agent Operator: trusted automation
The agent may take high-risk actions without waiting for a person, because no person is there to answer. Version control, billing, and secret capabilities are the exception. Those still route to a person even for an Operator, so an unattended agent cannot push code, move money, or read credentials on its own.
Pick it for scheduled and event-driven agents that must finish unattended runs: nightly reconciliation, an agent that reacts to inbound webhooks, or a cleanup job on a cron.
Operator is the only role that lets an agent take a high-risk action with nobody watching. Give it a narrow tool list and a scoped ontology, and prefer Contributor whenever a person actually starts the run.
Ceiling vs. request
A role does not describe what the agent does. It describes the most the agent may ever do.
role = the CEILING (what this agent may ever do)
agent config = the REQUEST (what this agent asks to do — its tools,
graph access, and budgets)
effective scope = ceiling ∩ requestOxagen intersects the two on every dimension, and the narrower side always wins:
| Dimension | How they combine |
|---|---|
| Capabilities | The role's grant decides allow / require approval / deny for each capability the agent equips. |
| Graph mode | The stricter of the two. Observer's read ceiling narrows a config asking for extend back down to read. |
| Graph budget | Element-wise minimum: hops, nodes, and traversal time. |
| Node & relationship types | Set intersection of the role's scope and the agent's scopeToTypes. |
| MCP servers | The role's rules are evaluated first-match-wins against each server the agent equips. |
Two consequences follow, and both are deliberate:
- Equipping a tool does not mean the rule allows it. An Observer agent configured with a write capability never gets to call it. The configuration is not an error. The ceiling holds.
- Narrowing the config narrows the agent. Widening the config does not widen the agent. To give an agent more reach, raise its role, which is an audited, permission-checked change.
The builder shows you the intersection before you save. On the Review step, the effective-scope panel renders all four dimensions for the role you picked. It uses the same computation the runtime enforces, so what you approve is what runs.
The delegation ceiling
One rule sits above everything else:
An agent never exceeds the person it acts for.
You cannot attach a role to an agent that grants capabilities you do not hold yourself. Oxagen resolves every capability the role confers against your own effective grants. If any of them comes back more permissive than what you have, Oxagen rejects the assignment with agent_role_ceiling_exceeded and names the capabilities that overreached.
This closes the obvious route to more reach. Without it, any member could create an agent, give it an Operator role, and use it as a proxy for grants the member does not hold. With it, delegation only moves sideways or down.
In the builder, roles above your own grants render disabled with an explanation, rather than failing at save time. That is a convenience, not the enforcement. The server runs the check again for every assignment.
Every assignment runs these checks, in order, inside the same transaction that writes it:
A retired agent takes no new role. revoke_agent_role still removes one it holds. Human system roles are never assignable, because the system org Owner role allows everything not explicitly denied. Attaching it to an unattended agent would widen that agent by construction. The per-capability comparison runs on Enterprise organizations, the only plan where the resolver decides a person's grants capability by capability. On other plans the IAM layer does not restrict people, so there is nothing for an agent to exceed. When the call comes from an Oxagen API key, "you" is the person who created the key.
Choosing a role
Work from the narrowest role outward:
- Does it change anything at all? No → Agent Observer.
- Does it run unattended (a schedule or an inbound event starts it, and nobody is present to answer an approval), and does it need a high-risk action to finish the job? Yes → Agent Operator.
- Otherwise → Agent Contributor.
Step 2 hinges on who is present. A high-risk agent someone runs by hand does not need Operator. Contributor routes the action to a person, and the person who started the run is there to answer. Operator exists for the case where waiting for an answer means the run never finishes.
Custom agent roles
You can attach your own IAM roles to agents instead of the three built-ins, for an agent that needs a precise, hand-built capability set. Custom roles are subject to every rule on this page, including the delegation ceiling. Every plan can create and assign them (ADR-069). Your plan decides whether the kernel enforces a role's grants, and list_iam_roles reports that as enforcement.
The three system agent roles are available on every plan.
Changing an agent's role
Use the role-assignment capabilities to change an agent's role.
From the REST API, assigning and detaching are two separate calls. POST /v1/{orgSlug}/{workspaceSlug}/agent/roles/assign attaches a role, and POST .../agent/roles/revoke with the same body detaches one. Assign first, then revoke, to match the builder's ordering. agentId accepts the agent's public id (agt_…), UUID, or slug.
curl -X POST "https://api.oxagen.sh/v1/$ORG_SLUG/$WORKSPACE_SLUG/agent/roles/assign" \
-H "Authorization: Bearer $OXAGEN_API_KEY" \
-H "Content-Type: application/json" \
-d '{"agentId": "agt_…", "roleName": "Agent Observer"}'Assigning a role the agent already holds is not an error. The response comes back with alreadyAssigned: true.
The audit log records every assignment and revocation, with the agent as the target and the acting person named. Read it in Organization → Audit.