Skip to content

Handle approvals#

This page covers asking for approvals — in an agent's policy, its budget or a flow — and deciding them. The concepts (who may decide, how long things wait) are in Approvals.

Before you begin#

  • To decide: the editor or admin role, and to be among the approval's approvers. Viewers and auditors see approvals.
  • For the API: ASTRA_TOKEN and WS as in the REST API page. The CLI has no approval commands.

Ask for an approval#

To hold Write
A kind of tool call A permit rule marked @approval (and optionally @approval_wait("1h")). The connections' Writes need approval level writes it for you.
A run past its own limit When reached: Ask for approval (budget.on_exceed: approval).
Runs past an agent's or workspace's budget A budget with on_exceed: approval.
A step of a flow An approval step.
Slack: posting needs an admin
@id("slack-reads")
permit (principal, action == Action::"http", resource in Server::"slack")
when { resource.path like "/conversations.*" || resource.path like "/users.*" };

@id("slack-posts")
@approval("role:admin")
@approval_wait("2h")
permit (principal, action == Action::"http", resource in Server::"slack")
when { resource.method == "POST" && resource.path == "/chat.postMessage" };

See what is waiting#

Anemoi → Approvals (its count is shown in the menu) lists what waits: when it was asked, What (the call, or the step's question), From (the agent and run, or the flow, execution and step), Policy, Who decides, and when it expires. All shows decided ones too. A run waiting is tagged waiting for approval in its agent's Runs.

Editors and admins who may decide are also told by email.

$ curl -sS "$WS/approvals?state=Pending" -H "Authorization: Bearer $ASTRA_TOKEN" \
    | jq -r '.items[] | [.metadata.name, .spec.kind, .spec.target, (.spec.approvers | join(",")), .spec.expires_at] | @tsv'
approval-64bf968ac66992da   flow_step   Tag release v2.4.0 of acme/api? role:editor 2026-10-02T19:39:40Z

Filters: state (Pending, Approved, Denied, Expired, Used), run, agent. Newest first.

Approvals waiting

Read what the call would do#

Open the approval. What is asked shows the call (github PUT api.github.com/repos/acme/api/pulls/7/merge), the policy that asked, the run, agent and version, the machine holding it and since when. The call shows its Arguments, read from that machine now — shortened, and values that look like keys hidden — and its fingerprint.

$ curl -sS "$WS/approvals/approval-3f1c09a7b2e44d10" -H "Authorization: Bearer $ASTRA_TOKEN"
$ curl -sS "$WS/approvals/approval-3f1c09a7b2e44d10/details" -H "Authorization: Bearer $ASTRA_TOKEN"

details asks the machine holding the call; it is not stored. For a budget approval, spec.amount_usd is the amount asked for.

Decide#

On the approval, under Decide, write a reason if you like (the agent is told it on a denial) and press Approve or Deny.

$ curl -sS -X POST "$WS/approvals/approval-3f1c09a7b2e44d10/decision" -H "Authorization: Bearer $ASTRA_TOKEN" \
    -H "Content-Type: application/json" -d '{"decision": "deny", "reason": "Not before the release freeze ends."}' \
    | jq .status

decision is approve or deny; reason at most 500 characters.

What happens next:

  • Approved: the held call goes ahead once, and the approval becomes Used. The same call again asks again.
  • Denied: the call is refused, with who denied it and why.
  • If the call's wait ran out before you decided, the agent was told not yet; the approval stays Pending for 24 hours from when it was asked, and if the agent makes the same call again it goes ahead on your approval.
  • A flow's approval step succeeds or fails, and the flow goes on.
Refusal Why
403 NOT_AN_APPROVER You are not among its approvers (the message lists them).
409 APPROVAL_NOT_PENDING It was decided already, or it expired.
400 INVALID_DECISION decision is not approve or deny, or the reason is too long.

Every decision is recorded with who, when and why, appears in the run's receipt and in evidence packs.