> ## Documentation Index
> Fetch the complete documentation index at: https://docs.matrices.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Permissions

> Selector grammar, condition operators, and the stacking rules.

A role holds an `allow` list and an optional `deny` list. A
[profile](/model/profiles) selects up to eight roles, and every agent on that
profile gets exactly that access.

## Selector grammar

Every selector is at most 176 bytes. `tool:*` is the only unqualified form;
every other selector names the tool's owner:

| Form | Example | Selects |
| - | - | - |
| Everything | `tool:*` | Every tool from every source. |
| Source | `tool:managed:*` | Every tool from one source. |
| Namespace | `tool:workspace:billing.*` | One namespace, including tools added to it later. |
| Exact | `tool:workspace:billing.lookup_invoice` | One logical tool name. |

Use `builtin` for tools Matrices ships, `managed` for managed providers, and
`workspace` for toolsets your workspace registered.

A namespace is lowercase, starts with a letter or digit, and runs up to 32
characters of `[a-z0-9_-]`. Partial wildcards (`tool:workspace:bill*`),
unqualified selectors (`tool:billing.*`), bare names
(`billing.lookup_invoice`), and duplicates are rejected.

`deny` accepts only unconditioned built-in selectors: `tool:builtin:*`, one
built-in namespace, or one exact built-in tool. Conditional objects, `tool:*`,
and managed or workspace selectors are rejected.

## Conditional allows

An `allow` entry may be an object instead of a string:

```json theme={"theme":{"light":"github-light-default","dark":"github-dark-default"}}
{
  "tool": "tool:workspace:billing.refund",
  "where": [
    { "path": "input.region", "op": "eq", "value": "eu" }
  ]
}
```

`where` holds at most eight conditions and every one must match. `path` starts
with `input.` and is evaluated against the tool input exactly as the model wrote
it, before executor defaults.

| Operator | Value | Matches when |
| - | - | - |
| `eq` / `neq` | scalar, or an array of scalars | The value at `path` is (not) equal. |
| `prefix` / `not_prefix` | string | The string at `path` does (not) start with it. |
| `suffix` / `not_suffix` | string | The string at `path` does (not) end with it. |
| `contains` / `not_contains` | string | The string at `path` does (not) contain it. |
| `in` / `not_in` | non-empty array | The value at `path` is (not) one of them. |
| `exists` / `absent` | — | `path` is present (or missing). |

An optional `quantifier` of `any` or `all` decides how a condition applies when
`path` resolves to an array. There is no regex and no type coercion.

## Stacking

```text theme={"theme":{"light":"github-light-default","dark":"github-dark-default"}}
effective built-in tools = union(allows) − union(denies)
```

| Across the profile's roles | Result |
| - | - |
| One matching allow, no matching deny | Allowed |
| A conditional allow whose `where` matches | Allowed for that call |
| A conditional allow whose `where` does not match | Not allowed by that entry |
| Any matching deny, in any selected role | Denied. A deny beats every allow. |
| No selected roles at all | Every tool denied |

Conditions narrow one grant; they never subtract from another. If a second role
on the same profile grants the same tool unconditionally, the call is allowed.

Denies only apply to built-in tools. Workspace and provider toolset namespaces
are controlled by positive allows alone.

## Attenuation

An agent using `roles.create`, `profiles.create`, `agents.create`, or the
matching update tools can only produce something covered by its own live
authority. Every permission it writes must be covered by a permission it holds,
and `roles.update` may add denies but never remove them. `tool:*` does not
exempt an agent from this.

There is one asymmetry to watch for when an agent creates an agent with an
inline `profile`: omitting `roleIds` inherits the caller's turn-start roles, so
the child gets everything the parent had. Send `roleIds: []` for a tool-less
child, or an explicit list for anything narrower. For an ordinary API-key
caller, omitting the field creates a profile with no role access at all.

## Limits

| Limit | Value |
| - | - |
| Roles per workspace | 64 |
| Roles per profile | 8 |
| `allow` entries per role | 32 |
| `deny` entries per role | 32 |
| Conditions per grant | 8 |
| Role name | 128 bytes |
| Role description | 1024 bytes |
| Selector length | 176 bytes |
| Condition value | 512 bytes |

## Inspecting effective access

`GET /v1/agents/{agentId}/effective-permissions` resolves the agent's profile
and roles right now and reports `roles` (each with its version), `builtIns` (the
exact tool names), `toolsets`, and `conditional` grants.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.