Permissions list what each agent may do and may not do.
Each agent carries two lists of tool patterns: allow says what it may do, and deny says what it may not do. Permissions decide by the tool name, and rules decide by everything else.
An entry names a tool, and sometimes a server.
{
"allow": [{ "tool": "payments.*" }, { "tool": "*", "server": "docs" }],
"deny": [{ "tool": "payments.transfer" }]
}- In a pattern,
*stands for any run of characters, as in the actions of AWS IAM.payments.*coverspayments.refundandpayments.transfer. No other character has a special meaning. - An entry without
serverapplies to every server. An entry withserverapplies only to a request that carries this server, such as the host of an HTTP call or the name of an MCP server. - Each list holds at most 100 entries.
An agent becomes closed as soon as an entry names it.
- An agent without any entry stays open: its permissions say nothing, and only the rules decide.
- Once an entry names the agent, in either list, an action passes only when an
allowentry covers it and nodenyentry covers it. - A
denyentry always wins over anallowentry, like an explicit deny in AWS IAM. - An agent with only
denyentries may therefore do nothing.
A refusal of the permissions counts as block.
When the permissions refuse an action, Paidwen counts a block. The rules still run, and a stricter active rule still wins: a quarantine stays a quarantine. An active rule that returns allow never lifts a refusal of the permissions.
The decision carries the permission field, with the entry that decided:
{"allowed": true, "tool": "payments.*"}: anallowentry let the action through.{"allowed": false, "tool": "payments.transfer"}: adenyentry refused it.{"allowed": false}: no entry lists the tool.
The message of DeniedError says that the agent's permissions refused the action. The journal keeps the field, and the audit uses it to answer with which permission an agent acted.
The API replaces both lists at once.
PUT /v1/agents/{agent_id}/permissions
Content-Type: application/json
{"allow": [{"tool": "payments.refund"}], "deny": []}GET /v1/agents/{agent_id}/permissions reads both lists. Two empty lists remove all of the agent's permissions. A change reaches every decision point in under a second. An agent's page in the dashboard edits the same two lists.
Permissions have four limits.
- Permissions read neither the parameters nor the cost. A condition on an amount belongs in a rule.
- A permission names one agent. An organization of 10,000 agents writes them agent by agent, with the API and a script.
- The server of an MCP call is the name that the server announces, and a server can lie. An entry that must resist a lying server names the tool.
- Permissions have no observe mode. A new list applies as soon as it reaches the decision point. To try a change first, write a rule in observe mode.