Paidwen

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.

JSON
{
  "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.* covers payments.refund and payments.transfer. No other character has a special meaning.
  • An entry without server applies to every server. An entry with server applies 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 allow entry covers it and no deny entry covers it.
  • A deny entry always wins over an allow entry, like an explicit deny in AWS IAM.
  • An agent with only deny entries 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.*"}: an allow entry let the action through.
  • {"allowed": false, "tool": "payments.transfer"}: a deny entry 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.

HTTP
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.