← Blog

Approvals & policy · · 9 min read

Designing approvals operators actually read

The failure mode every agent-approval system hits is rubber-stamp clickwrap. Design moves that delay it: signal selection, payload composition, deadlines, audit, and the hand-off problem.

Jonathan Haas

The policy gate that decides require-approval instead of allow or deny is doing the right thing — there are classes of action that need human judgment because the policy cannot encode the full context. The wrong thing happens next. The approval lands in the operator's notifications. The operator is in the middle of three other things. They glance at the notification, recognize the agent name, and approve. They didn't read the payload. Two weeks later, the approved action turned out to be the wrong one, and the post-incident review concludes that approval became a click-through.

This is the rubber-stamp problem, and it's the dominant failure mode of approval systems in production. Adding more friction doesn't fix it — operators route around friction. Adding more documentation doesn't either — operators don't read documentation in the middle of their day. The fix is designing the approval surface to make rubber-stamping harder than reading, and limiting the set of approvals an operator sees to the ones that need their judgment.

Three signals that a policy needs require-approval#

The first design move is to not return require-approval for actions that should be either allow or deny. Approval cost is real: it interrupts the operator and trains them toward the click-through behavior. A policy that returns require-approval on too broad a class of actions accelerates the failure mode.

Three signals worth conditioning the require-approval decision on:

  • Consequence is bounded and reversible. Actions that can be undone inside the run, with no external side effect, should be allowed without approval; actions that produce external side effects (sends, deletes, money movement) are reasonable candidates for approval. Actions that are irreversibly destructive at the system level might be denied entirely.
  • Run context is ambiguous. When the run context the policy uses to scope the action is uncertain — the customer id is inferred rather than provided, the resource match is partial, the operator's authority is being delegated through a sub-agent — approval is the right outcome. When the run context is explicit and unambiguous, the policy can decide on its own.
  • Action class is outside the operator's authority. When the agent is acting in a context the operator routinely owns, approval is busywork. When the agent attempts something the operator wouldn't normally do — a write to a system they don't usually touch, a delete during a time window they don't usually operate in — approval is appropriate.

A policy designed against these three signals returns require-approval rarely, and when it does, the operator's attention is the right resource to spend.

What the approval payload should show#

When the operator looks at the approval, what they see is the deciding factor for whether they read or click through. A payload that buries the decision-relevant information makes click-through the path of least resistance. A payload that surfaces it makes reading shorter than approving.

Three things the payload should show at the top:

  • What the agent is about to do, in operator language. Not "POST /v1/repos/evalops/proto-docs". The translation to "Delete the repo evalops/proto-docs" is the operator's mental model. The technical detail can be one click away.
  • Why the policy returned require-approval, in one sentence. "Destructive operation in production scope." "Cross-tenant resource match." "Sub-agent acting outside its narrowed scope." The reason is what tells the operator whether the action is one of the legitimate edge cases or one of the early-warning signals.
  • What the agent's run is about, in operator language. "Customer support agent for ticket T-1042." "Code review agent on PR #318." "Posture sweep run for 2026-06-09." The run context lets the operator decide whether the action makes sense in the broader narrative of what the agent is supposed to be doing.

Below these three, the full structured action — arguments, resources, policy version evaluated, sub-agent graph if relevant — for the operator who wants to read deeper.

The approve-with-conditions pattern#

A binary approve/deny is sometimes the wrong shape for the decision the operator needs to make. The operator might approve the action in principle but want to constrain the arguments, or approve only the next N actions of this type, or approve only within a time window.

A richer approval response covers:

  • Approve as proposed. The exact action runs.
  • Approve with modifications. The operator edits the arguments before approval. The agent receives the modified action.
  • Approve N more of this type. The next N actions matching this pattern auto-approve. The cap prevents the operator from accidentally blanket-approving an entire class.
  • Approve within window. Approvals are valid for a stated time window; after the window, the agent's next matching action requires fresh approval.
  • Deny with rationale. The operator denies and provides a one-line reason. The reason is recorded in the audit row and is information the agent's loop can use to decide what to do next.

The conditional patterns are friction in the right direction — they ask the operator to think about scope rather than to think about each individual action.

Notification surface: Slack, web, email, mobile#

Where the approval reaches the operator matters more than is usually appreciated. Each notification surface has different properties.

Slack is good when the operator is already in Slack — engineering teams during work hours, support teams during a customer interaction. The approval can be inline with the conversation that triggered the agent, and the action can be approved without leaving the conversation. Slack is bad outside business hours; messages stack up, and the urgency signal is lost in the noise of unrelated conversation.

Web is good for operators who oversee many agents at once. A web inbox lets the operator filter, batch-approve, and see context. It's bad for urgency: the operator has to go to the inbox to see it; the approval doesn't push.

Email is the universal fallback. Every operator has email. Email is reliable for delivery but bad for interaction: approving from email usually means clicking through to a web page anyway. Useful as a backup channel and a record of what was sent.

Mobile push is good for high-urgency, low-volume approvals: production deploys, customer-impacting decisions. It's bad for routine approval volume; operators learn to ignore push notifications when they fire constantly.

The right approval system supports more than one channel and routes based on the action's properties. A routine read-with-approval might surface on the web inbox; a destructive production action might go to mobile push and Slack simultaneously.

Deadlines and auto-deny#

An action waiting for approval is an action that is no longer the action that should run. Agent runs move on; the world changes; the operator's attention is elsewhere. A policy that emits require-approval should also emit a deadline.

Reasonable defaults:

  • Interactive runs: 5 to 15 minutes. The operator is in the loop; if they don't respond, the action has lost its window.
  • Background runs: 30 to 120 minutes. The operator has more time; the action is less time-sensitive.
  • Posture sweeps and scheduled tasks: hours to a day. The operator is being asked at their convenience; the action can wait.

After the deadline, the default is auto-deny. The agent receives a denial and continues without the action. Auto-approve is the wrong default: an unattended approval is not consent.

The deadline is also useful as an audit signal. An action that was auto-denied after a long deadline is a signal that the approval queue is mis-sized — either the operator pool is too small, the deadline is too short, or the policy is returning require-approval too often.

Auditing the approval#

The approval itself is an action in the audit log, just like the agent's action. The row should carry:

  • The action being approved (the agent's run_id and the action's parameters).
  • The operator who approved (the operator's identity from the IdP).
  • The decision (approve, modify, conditional approve, deny).
  • The reason (free text the operator can provide, especially on deny).
  • The time the approval was issued.
  • The policy version that triggered the approval requirement.

Investigation cases use these rows to reconstruct: who allowed what, on what evidence. An approval row that lacks the rationale is operationally fine but evidentially weak; six months later, the investigator has the operator's name but not the operator's reasoning.

A useful additional control is approval review: a sampling of approvals is surfaced to a second operator (or the security team) for after-the-fact review. The reviewer doesn't change the outcome — the action has already run — but the review pattern keeps operators aware that their approvals are being looked at. This is the documented countermeasure for click-through behavior in mature operations.

The hand-off problem#

The operator who approves is sometimes not available — out of office, on vacation, asleep in another timezone. The approval queue stops, and the agent's runs back up. The naive answer is to delegate approval authority to a backup operator; the careful answer is to think about what delegation does to the audit chain.

Three patterns:

  • Static delegation. The primary operator has named a backup. While the primary is unavailable, the backup approves. The audit row records both: the primary as the authority, the backup as the acting operator.
  • Role-based fallback. The approval routes to a role rather than a person. Anyone in the role can approve. The audit row records the role and the specific person who approved.
  • Escalation queue. The approval ages for a defined window with the primary operator; if no response, it escalates to a manager or an on-call. The audit row records the escalation path.

The right choice depends on the operator's organization. For engineering teams with rotating on-call, role-based fallback with escalation is common. For business operations with fixed approver hierarchies, static delegation is the cleaner pattern.

Article 14 and approval design#

The EU AI Act's Article 14, covered in What the EU AI Act means for the agent runtime, requires that high-risk AI systems be designed so that natural persons can effectively oversee them. The approval surface is the operational form of this requirement: the operator's oversight is the form Article 14 requires the system to enable.

The Article specifies that the natural person must be able to remain aware of the tendency of automation bias. Approval design is the place where automation bias most concretely manifests as rubber-stamp click-through. A system that returns require-approval for every action trains operators to approve unconditionally; the regulator and the post-incident reviewer will both see this as a failure of the oversight surface.

The design moves in this post — selective use of require-approval, payload that surfaces the decision, conditional approval shapes, deadlines, audit of approvals, hand-off rules — are the load-bearing components of the Article 14 oversight requirement. A conformity assessment will check for exactly these: whether require-approval fires only on the actions that need judgment, whether the payload surfaces the reason, and whether approvals themselves are audited and periodically reviewed.

Deixic's approval surface is designed against these patterns. See Trust for the oversight posture and What you can do for the action-time gate that produces the approval requests.