Skip to content

dev.agentpod.permission.v2

A harness permission prompt in AgentPod’s decision envelope, on the station room’s prose message beside the v1 card: options with what they mean and how far they reach, and a harness-permission/v1 subject whose preview shows what the agent would do. Readers ignore properties they do not know. x-uniqueBy lists paths whose values must not repeat (JSON Schema cannot say so): a[].b is field b of each item of list a.

An m.room.message whose content carries suite_event_type: "dev.agentpod.permission.v2".

Field Type Required Description Constraints
msgtype "m.text" no
body string no
suite_event_type "dev.agentpod.permission.v2" yes
schema_version integer yes at least 1
request_id string yes at least 1 character
session_id string yes at least 1 character
request_seq integer yes at least 0
title string yes
tool_kind string no at least 1 character
options array of object yes at least 1 item; at most 20 items
options[].id string yes at least 1 character; at most 200 characters
options[].label string yes at most 200 characters
options[].meaning one of "approve", "reject", "choose" yes
options[].scope one of "once", "always" no
subject yes

x-uniqueBy: the values at these paths must not repeat, the one rule JSON Schema cannot state. a[].b is field b of each item of list a.

  • options[].id

From fixtures/matrix-events/examples.json, case “a command, with all four ACP option kinds”:

{
"msgtype": "m.text",
"body": "Permission needed: Run the test suite\n\n1. Allow once\n2. Always allow\n3. Reject\n4. Never allow\n\nReply with the number, or the option's name.",
"suite_event_type": "dev.agentpod.permission.v2",
"schema_version": 1,
"request_id": "acps_3f0c:12",
"session_id": "acps_3f0c",
"request_seq": 12,
"title": "Run the test suite",
"tool_kind": "execute",
"options": [
{
"id": "allow_once",
"label": "Allow once",
"meaning": "approve",
"scope": "once"
},
{
"id": "allow_always",
"label": "Always allow",
"meaning": "approve",
"scope": "always"
},
{
"id": "reject_once",
"label": "Reject",
"meaning": "reject",
"scope": "once"
},
{
"id": "reject_always",
"label": "Never allow",
"meaning": "reject",
"scope": "always"
}
],
"subject": {
"id": "acps_3f0c:12",
"digest": "bb03bfd8ee6d757e6957d029cd6a7b8e004f16386755ce672e3f97f445563878",
"schema": "harness-permission/v1",
"revision": 1,
"expires_at": "2026-11-07T10:30:00.000Z",
"preview": [
{
"type": "field",
"label": "Tool",
"value": "Run the test suite"
},
{
"type": "field",
"label": "Kind",
"value": "execute"
},
{
"type": "text",
"label": "Command",
"text": "bun test"
},
{
"type": "field",
"label": "Location",
"value": "apps/hub"
}
],
"preview_complete": true
},
"dev.agentpod.permission": {
"schema_version": 1,
"session_id": "acps_3f0c",
"request_seq": 12,
"title": "Run the test suite",
"options": [
{
"option_id": "allow_once",
"name": "Allow once"
},
{
"option_id": "allow_always",
"name": "Always allow"
},
{
"option_id": "reject_once",
"name": "Reject"
},
{
"option_id": "reject_always",
"name": "Never allow"
}
]
}
}

The corpus has 2 valid cases in all:

built: a harness asks to run a command
{
"msgtype": "m.text",
"body": "The agent wants to run a command.",
"suite_event_type": "dev.agentpod.permission.v2",
"schema_version": 1,
"request_id": "acps_1:4",
"session_id": "acps_1",
"request_seq": 4,
"title": "Run bun test",
"tool_kind": "execute",
"options": [
{
"id": "allow",
"label": "Allow once",
"meaning": "approve",
"scope": "once"
},
{
"id": "reject",
"label": "Reject",
"meaning": "reject",
"scope": "once"
}
],
"subject": {
"id": "acps_1:4",
"digest": "c0ffee",
"schema": "harness-permission/v1",
"revision": 1,
"expires_at": "2030-01-01T09:30:00.000Z",
"preview": [
{
"type": "text",
"label": "Command",
"text": "bun test"
}
],
"preview_complete": true
}
}

Each of these must fail. The corpus says why:

  • an option with no meaning (refused by schema)
  • a subject of another schema (refused by schema)
  • no request_id: nothing an answer can name (refused by schema)
  • a subject revision that is not a whole number (refused by schema)
  • an expiry that is a date only (refused by schema)
  • an expiry written as a person would (refused by schema)
  • an expiry with no offset (refused by schema)
  • an expiry with no seconds (refused by schema)
  • an expiry with a space for the T (refused by schema)
  • an expiry whose offset has no colon (refused by schema)
  • an expiry in lower case (refused by schema)
  • an expiry on a day the month does not have (refused by schema)
  • no options: nothing to answer with (refused by schema)
  • twenty-one options: more than any decision card carries (refused by schema)