Appearance
Requests and policy
A request asks a person something: an approval (ask_approval) or an open question (ask_human). The policy decides which agent actions need one.
Requests
A request goes to the project's active channels, email or Telegram, or to the ones named in approvers. The person answers from the message or from a one-time link.
| Status | Meaning |
|---|---|
pending | Not answered yet |
approved | Approved as asked |
denied | Refused |
modified | The person picked one of your options, in decision |
needs_context | The person wants more information; any note is in comment |
answered | An ask_human question was answered |
expired | No answer within expires_in (default 24h): treat it as not approved |
The call waits up to wait_seconds (default 45, max 120) for the answer. After that it returns pending, and the answer arrives later in three ways:
request_status({request_id}), any time;- a
request.resolvedevent in the inbox, withrequest_id,status,decision,commentandstate_ref, unless the request has acallback_url; - a signed POST of that event to
callback_urlinstead, if the request has one (create the signing secret first withPOST /v1/request-callback-secret).
Put the id of your saved task state in state_ref: whoever handles the request.resolved event can resume the work with state_load. At most 50 requests can be pending in a project at once.
Channels
A channel is an email address or a Telegram chat. The owner's email is the first channel. channel_add adds another one; it needs the person to confirm it (the email link, or Start in the Telegram bot) and then the approval of the project's active channels. An agent cannot add a channel that answers its own requests.
Policy
The policy is a list of rules, checked from the top; the first rule whose conditions all hold decides.
json
{
"rules": [
{ "id": "no-big-refunds", "match": { "action": "refund", "amount_gt": 500 }, "effect": "deny" },
{ "match": { "action": "refund", "amount_lte": 50 }, "effect": "auto_approve_notify" },
{ "match": { "tool": "email_send", "to_domain_not_in": ["acme.example"] }, "effect": "require_approval" }
]
}Conditions, all optional: tool, action, risk, agent, platform (a value or a list), to_domain_in, to_domain_not_in (lists of domains), amount_lte, amount_gt. A condition on a value the call does not carry never holds.
| Effect | What happens |
|---|---|
allow | The action goes ahead |
deny | email_send and file_url fail with POLICY_DENIED; an ask_approval comes back denied |
require_approval | A person decides; approvers picks the channels |
auto_approve | Approved without asking anyone |
auto_approve_notify | Approved, and the channels are told; approvers picks who is told |
The policy applies to ask_approval, email_send and file_url. With no matching rule, ask_approval goes to people (so does allow), and email_send and file_url go ahead. ask_human always goes to people.
policy_get reads the policy. policy_set proposes a new one: every active channel sees the whole document, and the policy changes only when a person approves. No rule can approve a policy change, so an agent cannot widen its own permissions. Up to 100 rules and 16 KB.