Skip to content
Agent Engineering Lab
Pattern

Approval Gate

Human authorization before an irreversible act, with defined timeout behaviour.

Kind
Pattern
Layer
Control
Stage
Design
Status
Restated. Nearest prior descriptions:
  • Human-in-the-Loop, a human approves before an agent proceeds past a checkpoint, Intelligence Patterns
  • Human Reflection, a human reviewer critiques the agent output before it proceeds, Liu et al.
Forces
  • Specifying the gate costs one line; specifying what happens when nobody answers it is where the real design work is
  • A gate on every action trains its own approvers to stop reading, so it must be reserved for what its reversal cost actually justifies
  • An unspecified timeout is not an absence of a decision; it is a decision the runtime makes for you, not the one you would have chosen
Approval Gate pattern diagram

The problem

Ask an engineering team how they stop an agent from executing a wire transfer, closing an account, or taking some other action nobody can undo, and most describe the same shape: before the call runs, a human has to say yes. Framed that way, the design sounds finished.

What that description leaves out is the part that decides whether any of it does anything: what happens when the human does not answer.

Ask that follow-up and the room usually answers with a shrug: it just waits. A request with no stated limit has not been designed, only sketched. ARCH-004 names this directly: human approval is the action most often specified and least often designed. The gap shows the moment a synchronous request blocks on a person: it times out at the gateway, loudly, in front of the user, because a gateway has its own patience and was never told about the approval workflow’s.

The gate itself is not the missing piece. Putting a person in the path of an irreversible action is one of the oldest ideas in this catalogue, described already under other names. What is missing is the rest of the sentence: not “wait for approval,” but “wait for approval, for this long, and then do this.”

Forces

Specifying the gate costs one line; specifying what happens when nobody answers it is where the real design work is. “Require human approval before this executes” reads as a complete requirement and survives a design review unchanged, because a review is not where anyone tests what a stalled queue does at hour six. The other half, a bounded wait and an owned branch for the end of it, stays invisible in a spec that stops at “require approval.”

A gate on every action trains its own approvers to stop reading, so it must be reserved for what its reversal cost actually justifies. A queue that receives every borderline case, reversible ones next to irreversible ones, teaches whoever staffs it that most tickets are safe to wave through, because most of them are. That habit does not stay confined to the safe majority; it applies at the same speed to the rare request that needed real attention.

An unspecified timeout is not an absence of a decision; it is a decision the runtime makes for you, not the one you would have chosen. A queue with no stated bound does not sit undecided until a person rules on it. Code runs: a framework default fires, or an operator does something ad hoc under pressure, and “we never decided” describes the design process, not the system, which already picked something.

The pattern

State the rule plainly: a human approval step is not a control until the system specifies what happens when the human does not respond. Everything else about approval gates is well trodden ground. The timeout is where real systems fail.

The mechanism is not new, and the honest thing is to say so. Human-in-the-Loop, described by Intelligence Patterns, names a human approving before an agent proceeds past a checkpoint. Human Reflection, one of the patterns Liu et al. catalogue, names a human reviewer critiquing an agent’s output before it proceeds. Both describe the gate correctly, a person in the path who must say yes before the agent continues. Neither specifies what happens when that person never answers, and that omission is what this pattern names.

ARCH-004 names three branches for the clock running out, and treats the choice as configuration, because a branch written down gets reviewed and tested, and one that isn’t does not:

  timeout: 4h
  on_timeout: expire      the task fails, the user is told
                            correct for irreversible actions

  on_timeout: escalate      route to a second approver group
                          correct where the action is required

  on_timeout: proceed       NEVER for an irreversible action.
                          this turns your approval gate into a delay

Leave that block unwritten and a system still does one of these three things, without anyone choosing which. No stated bound: the request sits indefinitely, and the consequence moves elsewhere, a manual override that gets the transfer done anyway, exactly the path the gate existed to prevent, now taken with its knowledge but not its authorization. Silent auto-approve: an exception swallowed into a default resolves the request as though a human said yes when none looked at it, authorizing nothing, because it was never in the path of anything that mattered. Silent auto-reject: the task expires and nobody is told, and work that should have gone through dies undiscovered.

None of the three is wrong in every context, which is why leaving the choice unstated is the failure, not any one branch. Escalate suits an action that needs sign-off where one approver’s absence should not stop the business. Expire, with its notification intact, suits the irreversible actions this pattern gates: better a transfer visibly fails than executes because a clock ran out. Proceed suits only an action already judged cheap to reverse, which means it was never this pattern’s case; wire it to an irreversible call and the gate describes something that no longer exists.

Reserve the gate for what its reversal cost justifies: the queue only works if its volume stays low enough for whoever staffs it to keep reading each case. Where an action should never have a human path at all, that decision belongs to Capability Gate, made once against a registry entry rather than re-litigated on every call. Approval Gate is the narrower case: an action legitimate in general and irreversible here, decided by a person with standing authority to accept the risk, distinct from whoever requested it.

Worked example

Take the transfer_funds tool ARCH-004 uses as its own registry example: reversal cost impossible, exposure external, default action on flag require_approval. An agent at a regulated institution proposes a transfer a detector flags near the confidence threshold, landing in the one row the action grid reserves for a person: require approval. A task enters the queue carrying the request, the policy version behind the routing, and a role, whoever holds standing authority to accept this risk, distinct from whoever initiated the transfer.

Run the same request with no timeout configured, then through each of ARCH-004’s three named branches, and see what “require approval” means every time.

No timeout at all. The task sits until the case-worker, unable to wait, escalates by phone to a colleague with standing wire authority who processes the transfer manually, outside the system built to gate it. The gate is still configured correctly, on paper, in a queue that will never resolve on its own, and the override that replaced it carries none of the decision record this pattern exists to leave behind.

on_timeout: proceed, copied from a template built for a cheaper, reversible action. At hour four the transfer executes, unreviewed, and the decision record shows an allow, indistinguishable from a genuine one unless its decision_source field names timeout rather than human. Decision Record carries that field for this reason; without it, the gate’s defeat is invisible in its own audit trail.

on_timeout: expire, correctly matched to the reversal cost, but built without the notification ARCH-004 pairs it with. At hour four the task closes, the queue no longer shows it, and a legitimate transfer never happens; nothing surfaces the failure until the customer calls asking where the money went. Correct branch, badly built: silent expiry is the same failure as proceed, on the other side of the ledger.

on_timeout: escalate, to a second named role rather than the same unavailable approver. At hour four the task moves to a colleague holding equal authority, costing a delay against the escalation’s own service target, not an outcome nobody chose. This is the branch Escalation Path exists to specify: where a blocked case goes next, and who owns it there, is a second design problem this pattern’s timeout line only points at.

Three of these four runs share a label, human approval was configured for this action. Only the fourth, and half of the third, describe a control that did something.

When not to use it

The temptation this pattern warns against is not skipping the gate. It is placing it wherever a detector produces uncertainty, which feels like caution and behaves like the opposite. ARCH-004’s action grid reserves the human-approval row for impossible reversal cost paired with a genuinely uncertain band, nowhere else. Route a reversible, contained action there anyway, a draft that can be deleted, a query touching nothing external, and the queue fills with cases that were never the reason it exists, training whoever answers it to stop weighing each case on its merits. Rubber-Stamp Verifier is what that role becomes once genuinely risky requests are rare enough: a person clicking approve at the speed the queue demands, no different in effect from no gate, and worse in one respect, since the record still claims a human reviewed it.

Some actions do not belong here for a different reason: no approval should authorize them, from anyone, ever. That decision belongs to Capability Gate, made once against a registry entry rather than re-decided by a tired approver on every call. Sending a structurally forbidden action to a human queue only gives it a chance at a rubber stamp it should never have been offered. If an action needs a person’s judgment on this case, that is an approval gate’s job; if no judgment should ever authorize it, that is a capability gate’s.

A short, single-team workflow with a genuinely cheap undo, a draft saved and discarded inside one session, has nothing this pattern protects. The queue, the timeout policy, and the decision record all add friction to a case that was never going to cost anyone anything. Build the machinery where the reversal cost earns it.

Capability Gate is the mechanism for an action that should never be authorized at all, rather than one authorized case by case. Escalation Path owns what an on_timeout: escalate branch hands off to: where a blocked case goes next and who is accountable for it there. Rubber-Stamp Verifier is the failure a gate collapses into once volume, or an unexamined timeout, has trained its approver to stop reading each case on its own terms. Decision Record’s decision_source field is what has to distinguish a request a human genuinely reviewed from one a clock resolved on its own, or the two become indistinguishable to an auditor later. Attenuating Delegation governs how authority narrows hop by hop through a delegation chain; Approval Gate is where that narrowing stops being an agent’s problem and becomes a person’s, because no depth of narrowing substitutes for a human accepting risk the system could not resolve.

Specified in

Sources

  1. Human-in-the-Loop
  2. Liu Y., Lo S.K., Lu Q. (2025) Agent Design Pattern Catalogue: A Collection of Architectural Patterns for Foundation Model based Agents

Used in