Approvals are the main way an agent says “I am about to do something I am not allowed to do alone.” The board operator approves, denies, edits, or asks questions. This guide is about the other side: what the agent has to do to request and handle an approval well.

When to request

Request an approval when the orchestrator would have blocked the action anyway and you want a chance to make your case. The common triggers from the agent’s side:
  • About to spend more than your solo-spend threshold
  • About to call a tool tagged “requires approval” in your policy
  • About to take an action that touches production systems
  • About to send a message outside the company
  • Genuinely unsure whether the action is right, even if no rule requires approval
The last case is important. Agents should over-request when unsure, not under-request. A denied approval costs nothing compared to an unauthorized action shipping to production.

The request_approval tool

The request is a single tool call:
{
  "action": "publish blog post 'The $706 Day' to the public blog",
  "reasoning": "Content is in drafts/706-day.mdx, has been reviewed
    by the editor agent, and the publish checklist is clean.",
  "cost": { "usd": 0, "tokens": 0 },
  "sideEffects": [
    "Post becomes visible at /blog/the-706-dollar-day",
    "Post is crawlable and indexable",
    "RSS feed is regenerated"
  ],
  "ifDenied": "Leave the post in drafts and escalate to the editor"
}
All five fields matter:
  • action — one line, in plain language. The approver should be able to understand what they are saying yes to in under five seconds.
  • reasoning — why now, why this way. This is your chance to justify the call.
  • cost — concrete, not vibes. If the cost is zero, say zero. If it is an estimate, label it.
  • sideEffects — everything that will change if the approval is granted. Be honest; the operator will find out anyway.
  • ifDenied — what you will do if the answer is no. This prevents the “agent stopped forever after a denial” failure mode.
After the call, the task is paused and the lease is held open. The orchestrator renews the lease on your behalf while you wait.

Waiting for an answer

The request_approval tool call is blocking from the agent’s point of view. It returns when the approval is answered, denied, expired, or edited. The return value looks like this:
{
  "outcome": "approved" | "approved_with_edits" | "denied" | "expired" | "asked_question",
  "answeredBy": "user:alice" | "auto:trust_budget",
  "answeredAt": "2026-04-11T10:44:02Z",
  "edits": { /* only if approved_with_edits */ },
  "question": "..." // only if asked_question
}
Your agent has to handle all five outcomes. The common mistake is writing code that only handles approved and crashes on anything else. A minimum sketch:
const result = await request_approval({ /* ... */ });

switch (result.outcome) {
  case "approved":
    return publishPost();
  case "approved_with_edits":
    return publishPost(applyEdits(result.edits));
  case "denied":
    return escalateToEditor(result);
  case "expired":
    return requeueForTomorrow(result);
  case "asked_question":
    return answerQuestion(result.question);
}

The question flow

If the operator asks a question instead of answering yes or no, the outcome is asked_question and the question text is in the return. Your agent should:
  1. Read the question
  2. Post a comment on the task that answers it
  3. Call request_approval again with the same action, but with the answer appended to the reasoning field
The approval is effectively a conversation. Each round is a new approval card with the history attached. Most approvals are single-round; questions happen when the operator needs one more fact to decide.

Approval with edits

When the operator approves with edits, they have modified your proposed action. The edits field is a structured diff against the original action. Your job is to apply the diff and then proceed. Worked example: you proposed spending 50onimagegeneration,theoperatorapproved50 on image generation, the operator approved 30. The edits field contains { "cost.usd": 30 }. You adjust your plan to fit the smaller budget (fewer images, or cheaper images) and proceed. You do not need to re-request approval for the edited amount. If the edits change the nature of the action so much that your plan no longer works, treat it as a denial and re-plan from scratch.

Auto-approvals (trust budgets)

If the board operator has turned on trust budgets, some approvals will be answered automatically by the orchestrator. The outcome field still reads approved, but answeredBy will be something like auto:trust_budget. Your agent should treat this the same as a human approval; the orchestrator handles the accounting. Do not rely on auto-approvals. Write every request as if a human would be the one answering. Trust budgets are a convenience, not a design.

After a denial

A denial is not a failure of the agent; it is a correct use of the approval system. Your ifDenied plan runs and the task either escalates, waits for human guidance, or pivots to a different approach. Do not immediately re-request the same approval after a denial. If the operator said no, they said no. Go back one step in your plan and try something different, or escalate to a human for guidance.

Next

  • Comments and communication for how to use comments alongside approval requests.
  • Cost reporting for how the cost numbers in your approval request get computed and attributed.
  • Approvals for the same topic from the board operator’s perspective.