ai agent approvals
AI agent approval gates, with a Node.js example
An AI agent approval gate checks a proposed tool call before it runs. Policy allows it, denies it, or pauses it for human review. Follow a local file-write example, then adapt the same pattern to your own function.
- For
- Developers and security-minded platform teams adding governed tool use to AI agents
- Reviewed
- Oct 1, 2026
- Length
- 1,526 words

Put the checkpoint next to the side effect
The gateway receives a tool name and arguments before execution. On supported ActionProxy paths, identity and adapter context come from authentication, server, or transport state; caller assertions remain labeled. Reviewers inspect the proposed operation and its actual inputs.
Deterministic policy returns allow, deny, or require approval. Allow proceeds without human review, deny stops, and require approval creates a pending review. An allow decision expresses a configured rule, not a guarantee of safety.
What belongs in the gateway
- Normalize supported requests into a stable action shape before evaluating them.
- Keep verified identity and transport context separate from caller assertions.
- Apply deterministic policy to choose allow, deny, or require approval.
- Bind a human decision to the reviewed action, inputs, policy, reviewer requirements, nonce, and expiry.
- Cross the executor boundary only with current authorization, then record the attempt and reported outcome.
A concrete approval lifecycle
- The agent or application proposes a named tool call with structured arguments.
- The gateway normalizes the request and evaluates the active policy.
- An allow decision proceeds toward controlled execution; a deny decision stops; a require-approval decision creates a pending review.
- An eligible reviewer inspects the proposed operation and either approves, rejects, or, on supported single-reviewer flows, approves edited input.
- Before authorization, the service validates the stored binding and re-evaluates policy, including edited input when present.
- The authorized call crosses a local executor boundary or uses an expiring, one-use grant for an external runner, which reports the outcome.
Node.js example — review a real file write
The approved-file recipe uses the published JavaScript SDK 0.1.1 and a running local gateway. Follow that page for setup and download the complete runner (tar.gz). The standalone example is newer than the v0.1.1 source tag; download it separately. It creates a real Markdown file in temporary storage and needs no provider credentials.
The runner proposes local.write_note with fileName and content, requesting external_grant execution. The bundled policy requires approval for this unknown tool. Your own policy may differ. The Node process performs the write after grant consumption; the gateway's mock registry does not write the file.
Run the downloaded example, open its printed review link, and inspect the proposed filename and content. Before approval, the file does not exist. Choose “Approve exact proposal”, or expand “Technical details and integrity evidence”, change only content in “Approved input JSON”, then choose “Approve edited proposal”. The runner rejects a changed filename or content over 16,000 UTF-8 bytes.
Read the two execution checkpoints
These are selected excerpts from approved-file.mjs, not a runnable replacement. The download includes proposal submission, input checks, directory creation, and outcome/error handling. First it waits for an action status; only authorized passes the runner's next status check. The printed action ID lets you find the proposal if the terminal stops.
Wait for the review result
// Excerpt: submitted.id belongs to the proposed local.write_note call.
const approved = await client.waitForToolCall(submitted.id, {
until: ["authorized", "executed", "blocked", "rejected", "failed"],
timeoutMs: 15 * 60 * 1000,
intervalMs: 1000,
...wait,
});
// The full runner stops unless approved.status is "authorized".Consume the grant before writing approved content
// Selected lines; the full runner validates input and grant first.
const input = approved.input;
await client.consumeExecutionGrant(grant.id, {
input: approved.input,
policyVersionHash: approved.policyVersionHash,
toolCallId: approved.id,
toolName: approved.toolName,
});
// Inside the runner's guarded write block, after directory creation:
await writeFile(outputPath, input.content, {
encoding: "utf8",
flag: "wx",
mode: 0o600,
});Check approval, rejection, and interrupted runs
- After approval, open the printed output file and confirm it contains the reviewed content. The runner reports success and prints executed only after recording the outcome. It never overwrites an existing file.
- Run the example again and reject the new proposal. That run creates no file. Each explicit run proposes a different filename.
- If the 15-minute wait expires or the terminal stops, inspect the printed action ID and reject any pending proposal you no longer need. Stopping the wait does not cancel the proposal.
- If writing or outcome reporting fails, inspect the file and action before another attempt. The runner attempts to report an unknown outcome after a write error; a reporting error can leave a file present without a recorded success. It never automatically repeats the write.
Adapt the runner to your own function
Replace the bounded file-write section with your function, submit its tool name and arguments, and pass only the returned approved input. Keep grant consumption before the function call and report the actual outcome afterward. Add a policy rule for that tool, keep provider credentials in the runner, and remove the agent's direct access to the original function. Calls that bypass the adapter are outside this gate.
Adjust validation and failure handling for the real operation. A provider timeout can leave the effect uncertain; reconcile it before authorizing another attempt. A one-use grant does not deduplicate separately proposed operations.
Approval needs a precise object
"Approve the agent" is too broad to be a useful runtime decision. The reviewer needs an inspectable action: which tool, which arguments, under which policy, for which requester, and for how long the decision remains valid. If the input changes after review, the old decision should not silently authorize the new operation.
ActionProxy's canonical Community paths bind approval authorization to action and input hashes alongside tenant, requester, policy, decision, review requirements, nonce, and expiry. The deeper mechanics are covered in binding approval to an exact tool call.
Choose the review lane deliberately
Reserve human review for actions that need judgment. Separate bounded routine calls from calls that need review and calls that should never run. Map those groups to allow, require approval, and deny, then inspect actual outcomes before relaxing rules.
Risk-based human approval shows how to build that first decision matrix. For a specific use case, email approval for AI agents walks through recipients, message content, and send-time review.
Questions to ask before adopting a gateway
- Does policy inspect the proposed tool call rather than only the surrounding conversation?
- Is the approved payload bound to the eventual execution request, including edits and expiry?
- Can allow, deny, and approval decisions share one execution path instead of creating an approval-only side door?
- What happens after a timeout or lost connection? An unknown result should not be treated as proof that nothing happened.
- Can reviewers see enough context without copying secrets into notifications or logs?
- Are audit records honest about their integrity boundary, storage sensitivity, and retention limits?
Gateway placement is an architecture choice
Review can live inside an agent framework or in a shared gateway. Compare framework HITL versus an external approval gateway. For an existing MCP server, start with MCP tool-call approval.
Follow the same action through proposal, policy, approval, attempt, and outcome. The AI agent tool-call audit trail explains what to correlate and the limits of that evidence.
Common questions
Questions developers ask
What is an AI agent approval gateway?
It is the service at the tool-execution boundary that receives a structured action, applies policy, and returns an allow, deny, or pending-review result before dispatch.
Should every AI agent action require approval?
No. Let policy route routine bounded operations to allow, prohibited operations to deny, and cases that need human judgment to require approval. The boundaries should reflect the application rather than a universal rule.
Can an approver edit a proposed tool call in ActionProxy?
The explicit edit path is available to one authorized reviewer. ActionProxy retains both payload identities and evaluates the edited input again; multi-reviewer approvals currently reject edits because votes cannot span payload versions safely.
Does ActionProxy include production SaaS connectors?
No. Community's built-in registry is a deterministic demo surface. A downstream MCP server or external runner performs real effects and remains responsible for provider credentials and reporting the result.


