Skip to main content
A role holds an allow list and an optional deny list. A profile 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: 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:
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. 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

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

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.