# Permissions and roles

**What this is:** the permission keys, the seeded roles, and the rules that narrow a key (plan, billing state, assurance).
**Who it is for:** tenant admins who must answer "who may do this, and why was this person refused?".
**You will learn:** how keys are named, what each system role holds, how a plan removes a key, and how comp access works.

## How keys are named

Code names keys, never roles. A key is `area.thing` or `area.thing.verb`.
A trailing `.*` marks a family (`gateway.tool.<name>`, `model.role.<alias>`). Platform keys use a dot (`platform.kill_switch`);
one uses a colon (`platform:grant_complimentary`). Each key carries:
A trailing `.*` marks a family (`gateway.tool.<name>`, `model.role.<alias>`). Platform keys use a dot (`platform.kill_switch`);
one uses a colon (`platform:grant_complimentary`). Each key carries:

- **On**: the kind of object it is checked on (tenant, agent, binding, channel, board, device and so on).
- **Assurance**: the weakest sign-in strength allowed: `none`, `weak`, `linked`, `strong`, `strong_mfa`.
- **Plan gate**: empty, a plan name (that plan or higher), or `entitlement:<name>` (the plan must grant it).
- **Class**: `read`, `write`, `admin` or `platform`. Writes in chat can carry an obligation (see below).

Keys starting `platform.` belong to Bill and Ben staff and are not available to customers.

## Which permission lets a person command Ben?

`agent.command` on the Ben binding. `agent.ask` only lets Bill or Ben answer questions with read tools.
Then each tool needs its own key: `code.push` for branches and pipelines, `ado.write` and `ado.comment` for Azure DevOps,
`target.sandbox.use` for sandbox work, `target.device.use` for a device. A person with `agent.command` but not `code.push`
can start a task, and Ben still cannot push for them.

## Seeded roles

Seven roles are copied into each new tenant.
A role is a list of keys or `prefix.*` patterns. Admins may edit them in the [admin console](../admin/console.md); custom roles are a plan feature (`custom_roles`).
The last Owner cannot be removed.

| Role | Holds |
|---|---|
| `owner` | `console.*`, `agent.*`, `meeting.*`, `channel.*`, `canvas.*`, `target.*`, `code.*`, `ado.*`, `gateway.*`, `knowledge.*`, `model.*`, `admin.*`, `audit.*`, `privacy.*`, `billing.*`, `usage.*`, `tenant.grant_complimentary` |
| `admin` | `admin.*`, `audit.view`, `usage.view`, and the console pages for users, roles, agents, channels, usage, audit, privacy, devices, knowledge, gateway |
| `billing_admin` | `billing.*`, `usage.view`, console pages for billing and usage |
| `developer` | `agent.ask`, `agent.command`, `target.sandbox.use`, `target.device.*`, `ado.comment`, `ado.write`, `code.push`, `canvas.board.*`, `canvas.plan.execute`, `knowledge.search`, `gateway.connect` |
| `ops` | like `member`, plus `target.server.run_script` and `target.device.use` |
| `member` | `agent.ask`, `agent.command`, `target.sandbox.use`, `ado.comment`, `canvas.board.*`, `knowledge.search`, `gateway.connect` |
| `viewer` | `agent.ask`, `canvas.board.view` |

Every role also holds `usage.view_own` (Owner through `usage.*`), so each person sees their own usage on the Home page.
Platform keys are never in a seeded role. Operators in tenant #1 hold them through their own grants.
`canvas.plan.execute` is a key, not a fixed rule: an admin can give it to any role.

## Order of checks

The permission check runs these in order and stops at the first refusal. The reason is returned to the caller.

| Step | Refuses with | When |
|---|---|---|
| Subject | `unknown_subject` | not an active user of a known tenant, or a service or anonymous caller |
| Kill switch | `tenant_suspended` | platform or tenant kill switch is on (platform keys are exempt) |
| Tenant and billing state | `tenant_suspended`, `tenant_restricted` | tenant not active; `restricted` or `read_only` allows reads only |
| Platform scope | `no_permission` | a platform key from outside tenant #1 |
| Agent state | `no_permission`, `agent_paused` | agent missing or disabled; paused agents allow only `agent.pause` and `agent.configure` |
| Plan gate | `plan_feature_missing`, `quota_exceeded` | the effective plan lacks the entitlement, or its monthly quota is used |
| Assurance | `weak_identity` | sign-in weaker than the key needs |
| Role and grants | `no_permission` | no role, group or direct grant gives the key |
| Failure | `pdp_unavailable` | any error, timeout or bad answer |

After OpenFGA, **obligations** may be attached to an allow:

- `confirm_out_of_band`: a write or admin key asked from a chat or voice channel needs an approval card first.
- `summary_only`: a gateway call without `gateway.detail.full` may only return summaries.

## Plan gates and entitlements

The effective plan for a person is the best of: a complimentary grant for them, a tenant-wide grant, or the live subscription.
Admin overrides win over plan values. Entitlement names in the seeded plans:
`meeting_minutes`, `sandbox_minutes`, `server_scripts`, `gateway` (`summary` or `full`), `model_roles`, `devices`, `custom_agents`,
`custom_roles`, `sso`, `scim`, `audit_export`. Numbers are per user, so the quota is the number times the seats,
and `-1` means unlimited. For `model.role.<alias>` the alias must be in the plan's `model_roles` list. What each plan includes: [Plans and billing](billing.md).

## Complimentary access

Staff can give a tenant or one user a plan at no charge. Rules:

- The key is `platform:grant_complimentary`. Grants, changes and revokes are checked again and audited.
- A grant has a reason and may have an end date and a model-spend budget. **Spend caps still apply**: the grant's budget counts toward the team spend cap.
- Staff can delegate the right by assigning the platform role `comp_grantor`. A delegate cannot delegate further.
- `tenant.grant_complimentary` is the scoped version: a tenant's own Owner may comp the tenant's own users, if the platform allows it.
- Bill and Ben staff hold a permanent grant for their own tenant.

## Run grants: who is asking while an agent works

When an agent starts work for you, it receives a temporary pass for that run. The pass is tied to you, your tenant, the agent and the place you asked from,
and may be narrower than your own rights: it lists the only permissions the run may use, even if you could do more.
The model never says who is asking. Without a valid pass the agent cannot use a tool, and a tool outside the pass is refused too.
The pass lasts at most 12 hours. When one agent hands work to the other, the pass handed on is never wider than the original and is shorter-lived.
A pass you revoke stops working within seconds.

## Tool permission map

Before every tool the agent uses, Bill checks that you are allowed. Each tool needs one key: reading and searching needs `agent.ask`; comments on
Azure DevOps items need `ado.comment`; changing work items needs `ado.write`; branches, pipelines and pushes need `code.push`; sandbox work needs `target.sandbox.use`;
device work needs `target.device.use`; allow-listed server scripts need `target.server.run_script`. A tool that is not listed counts as a write and needs `agent.command`.
Writes asked in chat or voice may need an approval card first.

## Caching and failure

Answers are remembered briefly (allows for at most 15 seconds, denies for at most 5), and a role change takes effect straight away.
If the check cannot answer in time or answers badly, the request is refused with reason `pdp_unavailable` and nothing is remembered. Try again shortly, and tell your Bill and Ben contact if it keeps happening.


## All permission keys

Change the catalogue, then regenerate this table; never edit it alone.

### Console pages

| Key | On | What it allows | Assurance | Plan gate | Class |
|---|---|---|---|---|---|
| `console.section.users.view` | tenant | see the users console page | strong | - | read |
| `console.section.roles.view` | tenant | see the roles console page | strong | - | read |
| `console.section.agents.view` | tenant | see the agents console page | strong | - | read |
| `console.section.channels.view` | tenant | see the channels console page | strong | - | read |
| `console.section.usage.view` | tenant | see the usage console page | strong | - | read |
| `console.section.billing.view` | tenant | see the billing console page | strong | - | read |
| `console.section.audit.view` | tenant | see the audit console page | strong | - | read |
| `console.section.privacy.view` | tenant | see the privacy console page | strong | - | read |
| `console.section.devices.view` | tenant | see the devices console page | strong | - | read |
| `console.section.knowledge.view` | tenant | see the knowledge console page | strong | - | read |
| `console.section.gateway.view` | tenant | see the gateway console page | strong | - | read |

### Agents

| Key | On | What it allows | Assurance | Plan gate | Class |
|---|---|---|---|---|---|
| `agent.ask` | binding | the agent answers a question (read-only tools); a tenant may opt in to weak assurance | linked | - | read |
| `agent.command` | binding | the agent takes a task, uses write tools, joins work | linked | - | write |
| `agent.configure` | agent | change instructions, skills, tools and the unauthorised policy (creating custom agents is gated by the custom_agents entitlement, checked by the console) | strong | - | admin |
| `agent.pause` | agent | pause or resume an agent | strong | - | admin |

### Meetings

| Key | On | What it allows | Assurance | Plan gate | Class |
|---|---|---|---|---|---|
| `meeting.invite_agent` | binding | send the agent into a meeting | linked | `entitlement:meeting_minutes` | write |
| `meeting.voice_command` | binding | spoken commands are accepted | linked | - | write |

### Channels

| Key | On | What it allows | Assurance | Plan gate | Class |
|---|---|---|---|---|---|
| `channel.bind_agent` | channel | enable an agent in a chat, channel or meeting series | strong | - | admin |

### Helmora

| Key | On | What it allows | Assurance | Plan gate | Class |
|---|---|---|---|---|---|
| `canvas.board.list` | tenant | list the boards you can open | strong | - | read |
| `canvas.board.create` | tenant | create a board | strong | - | write |
| `canvas.board.view` | board | view a board | strong | - | read |
| `canvas.board.edit` | board | edit a board | strong | - | write |
| `canvas.board.manage_members` | board | manage who can use a board | strong | - | admin |
| `canvas.plan.execute` | board | press Execute on a plan | strong | - | write |
| `canvas.node.approve` | plan_run | approve a gated node (still needs the node's own target permission) | strong | - | write |

### Execution targets

| Key | On | What it allows | Assurance | Plan gate | Class |
|---|---|---|---|---|---|
| `target.sandbox.use` | target | run work in the sandbox | linked | `entitlement:sandbox_minutes` | write |
| `target.device.use` | device | run on this device (owner by default; sharing = tuples) | strong | `business` | write |
| `target.device.enrol` | tenant | enrol own device | strong | `business` | write |
| `target.server.run_script` | target | allow-listed ops scripts | strong | `entitlement:server_scripts` | write |

### Code

| Key | On | What it allows | Assurance | Plan gate | Class |
|---|---|---|---|---|---|
| `code.push` | tenant | Ben pushes branches or pull requests | linked | - | write |

### Azure DevOps

| Key | On | What it allows | Assurance | Plan gate | Class |
|---|---|---|---|---|---|
| `ado.write` | ado_project | change Azure DevOps work items | linked | - | write |
| `ado.comment` | ado_project | comment on Azure DevOps items | linked | - | write |

### Gateway

| Key | On | What it allows | Assurance | Plan gate | Class |
|---|---|---|---|---|---|
| `gateway.connect` | tenant | connect an external AI client to the gateway | strong | `entitlement:gateway` | write |
| `gateway.tool.*` | tool | use one gateway tool, e.g. gateway.tool.<name> | strong | `entitlement:gateway` | write |
| `gateway.detail.full` | tenant | gateway answers in full detail instead of summary mode | strong | `business` | read |

### Knowledge

| Key | On | What it allows | Assurance | Plan gate | Class |
|---|---|---|---|---|---|
| `knowledge.search` | collection | search a knowledge collection | linked | `business` | read |
| `knowledge.manage` | collection | manage a knowledge collection | strong | `business` | admin |
| `knowledge.admin` | tenant | run the library: create and list collections, search model and ranking settings (owner and admin through `knowledge.*`) | strong | `business` | admin |

### Model roles

| Key | On | What it allows | Assurance | Plan gate | Class |
|---|---|---|---|---|---|
| `model.role.*` | tenant | use a model role alias, e.g. the deeper-reasoning model | none | `entitlement:model_roles` | read |

### Administration

| Key | On | What it allows | Assurance | Plan gate | Class |
|---|---|---|---|---|---|
| `admin.users.manage` | tenant | administer users | strong | - | admin |
| `admin.roles.manage` | tenant | administer roles | strong | - | admin |
| `admin.identity.manage` | tenant | administer identity providers (SSO/SCIM need the Business plan, checked by the console) | strong | - | admin |
| `admin.agents.manage` | tenant | administer agents | strong | - | admin |
| `admin.channels.manage` | tenant | administer channels | strong | - | admin |
| `admin.models.manage` | tenant | edit the tenant model allow-list (which model vendors the tenant's agents may use) | strong | - | admin |
| `admin.meeting_logins.manage` | tenant | register the tenant's own meeting bot accounts (Attendee login group) | strong | `business` | admin |
| `admin.entra.connect` | tenant | start the Microsoft 365 admin consent that links the tenant's Entra tid | strong | - | admin |
| `admin.teams_package.download` | tenant | download the Teams app package for a custom upload (the store listing is the normal route) | strong | - | admin |

### Audit

| Key | On | What it allows | Assurance | Plan gate | Class |
|---|---|---|---|---|---|
| `audit.view` | tenant | read the audit log | strong | - | read |
| `audit.export` | tenant | export the audit log | strong | `business` | read |

### Privacy

| Key | On | What it allows | Assurance | Plan gate | Class |
|---|---|---|---|---|---|
| `privacy.export` | tenant | GDPR export | strong | - | read |
| `privacy.delete` | tenant | GDPR delete | strong | - | admin |
| `privacy.retention.manage` | tenant | set retention periods | strong | - | admin |

### Billing

| Key | On | What it allows | Assurance | Plan gate | Class |
|---|---|---|---|---|---|
| `billing.view` | tenant | see invoices and plan | strong | - | read |
| `billing.manage` | tenant | change plan and spend cap | strong | - | admin |

### Usage

| Key | On | What it allows | Assurance | Plan gate | Class |
|---|---|---|---|---|---|
| `usage.view` | tenant | see usage | strong | - | read |
| `usage.view_own` | tenant | see your own usage | strong | - | read |

