Approval Gate
Block execution and ask the user to approve a risky or high-stakes agent action.
Install
npx ax-depute@latest add approval-gatepnpm dlx ax-depute@latest add approval-gateyarn dlx ax-depute@latest add approval-gatebunx ax-depute@latest add approval-gateOverview
Approval Gate is the trust boundary primitive. It pauses agent execution and surfaces a structured approval UI before the agent crosses a trust boundary — sending emails, writing to a database, calling an external API.
The key design principle (from Stripe's SPT pattern): approvals are scoped grants, not binary yes/no decisions. A user approving "send emails" shouldn't be approving "send unlimited emails forever."
Send external email
The agent will send a follow-up email to 3 recipients.
Basic usage
<ApprovalGate
title="Send email to customer"
description="The agent will send a follow-up to 3 recipients."
agentReasoning="Task requires notifying stakeholders of completed analysis."
status="pending"
onApprove={() => agent.continue()}
onReject={() => agent.abort()}
/>With scoped grant
<ApprovalGate
title="Charge payment method"
description="The agent will charge $49.00 to the customer's card on file."
agentReasoning="Subscription renewal detected. Auto-charge is enabled for this account."
mode="simple"
status="pending"
scope={{
target: 'Stripe API',
resourceLimit: 4900, // in cents
durationSeconds: 300, // expires in 5 minutes
}}
onApprove={() => agent.continue()}
onReject={() => agent.abort()}
/>Staged mode (Preview → Confirm → Execute)
For high-risk multi-step actions, use mode="staged" to walk the user through three phases before execution:
<ApprovalGate
title="Deploy to production"
description="The agent will deploy the current build to the production environment."
agentReasoning="All tests passed. Deployment window is clear."
mode="staged"
status="pending"
onApprove={() => agent.deploy()}
onReject={() => agent.cancelDeploy()}
/>Props
| Prop | Type | Default | Description |
|---|---|---|---|
title | string | — | Short label for the action being approved |
description | string | — | Human-readable explanation of what the agent will do |
agentReasoning | string | — | Why the agent thinks this action is necessary |
mode | 'simple' | 'staged' | 'simple' | Staged adds Preview → Confirm → Execute steps |
status | 'pending' | 'approved' | 'rejected' | 'pending' | Controls gate state |
scope | ApprovalScope | — | Optional scoped grant (target, resourceLimit, durationSeconds) |
onApprove | () => void | — | Called when user approves |
onReject | () => void | — | Called when user rejects |
Composition flow
Approval Gate usually sits immediately after a Plan Card and before Run Controls:
Plan Card → [Approval Gate] → Run Controls → Tool TraceIt pauses execution and requires a human cryptographic signature (or explicit click) to proceed.
Design rationale
Why scope? Binary approve/reject is the wrong mental model for agents. Stripe never approves an action with a simple yes/no — they issue capability grants scoped to a specific target, resource limit, and time window.
Why mode="staged"? Agent flows are state machines, not request-response cycles. staged mode maps to Stripe's Authorization Chain pattern: Intent → Plan → Permission Check → Execution → Audit. Each phase can fail or pause for human input.