Confirmation Model
Every mutating action an agent can take resolves to one of four confirmation tiers. The tiers appear under three different vocabularies depending on where you configure them (connection policies, custom tool metadata, or the request tool call itself), but they describe a single underlying model. This page maps the vocabularies to each other; the pages for Connections, Tools, and Guardrails cover each surface in depth.
The Four Tiers
| Tier | Behavior |
|---|---|
| Auto-approve | The agent executes without user interaction; the default for reads. |
| Confirm | Execution pauses. The runtime emits a confirmation_required event and waits for approval before running the call. |
| Review | The agent cannot execute the call itself; it requires human review through the operator surface. |
| Never | The operation is blocked entirely (only callable by other tools, never by the agent). |
One Model, Three Vocabularies
| Surface | Where configured | Vocabulary | Tier it resolves to |
|---|---|---|---|
| Connection endpoint | policy.json confirm | omitted / true / "review" / "never" | auto / confirm / review / never |
| Custom tool | tool.ts exposure.kind | open / operator-gated / requires-confirmation | auto / operator UI only / confirm (recorded at the review tier) |
| Request tool call | intent parameter | 'read' / 'write' / 'confirmed_write' | declares which side of the handshake a call is on (see below) |
Connection endpoints: policy.json confirm
For connection policies, confirm accepts only true, "review", or "never"; omit it for read endpoints (false is not a valid value here). See Connections for the full policy format, and Escalation below for the rules that can raise an endpoint's tier at call time.
Custom tools: exposure.kind
Custom tools declare their tier through exposure.kind in tool metadata:
open(the default): the agent calls the tool freely.requires-confirmation: every call pauses for explicit approval before executing (an optionalpromptfield customizes the message). The loader records these tools at the"review"confirm tier.operator-gated: the tool runs only from operator UI actions, never autonomously. Pair it withllm_callable: falseso the model does not see the tool at all.
The request tool handshake: intent
The built-in request tool declares intent: 'read' | 'write' | 'confirmed_write' on every call. Mutating methods (POST, PUT, PATCH, DELETE) must declare 'write' or 'confirmed_write'; the permission checker rejects them with intent: 'read'.
When a write hits an endpoint at the confirm tier, the two-phase handshake runs:
- The agent calls with
intent: 'write'. No request is sent; the tool returns a preview and the runtime emitsconfirmation_requiredto the client. - The user approves (the SDK chat surfaces render this automatically).
- The agent calls again with
intent: 'confirmed_write', which executes the previewed request.
Endpoints at the review or never tier deny the call regardless of intent.
The confirmation_required Event
Whenever execution pauses for approval, the runtime emits the confirmation_required SSE event (SSEConfirmationRequiredEvent in the SDK) with endpoint, method, reason, escalated, and timestamp fields. It fires in three cases: a connection write hits a confirm tier, a requires-confirmation tool is called, or a hook returns an ask decision. The chat SSE stream documents the client-side view.
Escalation
A configured tier is a floor, not a ceiling; two rules can raise it at call time:
- Threshold escalation: endpoint policies can escalate based on request parameters, e.g.
{ "field": "body.amount", "above": 10000, "escalate": "review" }. - Delegation escalation: when a sub-agent acts on behalf of a user (
isDelegated) and the connection's policy setsdelegations.escalateConfirm: true,confirmescalates toreview.
Escalation only raises tiers to review or never, both of which deny the call; an escalated tier therefore surfaces as a denial with an escalation reason, not as a confirmation_required event.