All systems operational--:--:-- UTC

Approval gates: deciding what an agent may do unattended

A policy model for agent actions that scales from one refund to a hundred thousand runs a day, and what we learned rolling it out.

Hannah Lindqvist

Product Lead, AI

Published
Reading time
4 min read

The first version of agents in ConsciousLab had one setting for autonomy: on or off. Customers turned it off. Not because the agents were bad at the work, but because the only alternative to "approve everything" was "approve nothing," and nobody in a regulated business can sign off on approve nothing.

This post describes the model we replaced it with, approval gates, and what we learned from the first six months of running it across 184,000 agent runs a day.

Autonomy is a property of an action, not an agent

The question "do you trust this agent?" is the wrong question. The useful question is "do you trust this agent to take this action, with these arguments, in this context?" A support agent looking up an order is harmless. The same agent issuing a €40 refund is low risk. Issuing a €4,000 refund to a customer whose account is three days old is not.

So gates attach to tools, not agents. Every tool an agent can call has a policy, and a policy is a list of rules evaluated against the call's arguments and context:

tool: refund.issue
rules:
  - when: amount_eur <= 50
    decide: allow
  - when: amount_eur <= 250 and customer.age_days >= 30
    decide: allow
  - when: amount_eur <= 2500
    decide: require_approval
    approvers: role:support-lead
    sla: 30m
  - decide: deny

Rules are evaluated top to bottom. The first match wins. If nothing matches, the call is denied. That last line matters: a policy that forgets a case fails closed.

What the approver sees

An approval request is only as good as the context it carries. Early on we sent approvers a one-line summary ("Refund €182.40 to Halvorsen Logistics?") and approval latency was terrible. People did not have enough to decide, so they went digging in three other tools first.

Now an approval carries the full run trace up to the gate. The approver sees which tickets the agent read, which order it looked up, the scan record that confirmed the damage, the agent's stated reasoning, and the exact arguments of the call it wants to make. Median time to decision dropped from 14 minutes to 2 minutes 40 seconds when we made that change, and the rejection rate went up slightly, which we read as people actually reading.

Approvals can be given in the console, in Slack, or through the API. All three write the same event to the audit log, with the approver's identity and the policy version that required the approval.

Confidence is an input, not a gate

We are often asked whether gates should use the model's confidence. We let policies read it, but we discourage using it alone. Model confidence is a useful signal for routing, for instance sending low-confidence classifications to a human queue, but it is not calibrated well enough to be the only thing standing between an agent and a payout. Policies that combine confidence with an amount limit work well. Policies that rely on confidence alone tend to drift as models change.

Rollout: shadow mode first

Every new policy can run in shadow mode for a period you choose. In shadow mode the policy is evaluated on every call and its decision is recorded, but the previous policy is still enforced. At the end of the period you get a report:

OutcomeCallsShare
Same decision as current policy41,20893.4%
New policy stricter2,6115.9%
New policy more permissive3090.7%

You can open any of the 309 more permissive cases and read the trace before you promote the policy. Teams that use shadow mode for at least a week roll back new policies 80% less often than teams that promote immediately.

What we got wrong

Two things.

First, we initially let approvals time out into an "allow." The idea was to avoid blocking customers when approvers were asleep. In practice it meant an unreviewed action executed at 03:00 with nobody watching. Timeouts now resolve to the policy's configured fallback, which defaults to deny, and the agent tells the customer what will happen next.

Second, we underestimated how much approvers wanted to edit rather than accept or reject. A support lead often agrees a refund is owed but wants it to be €150, not €182.40. Approvers can now amend the arguments within limits the policy defines, and the amendment is recorded alongside the original.

Numbers from the first six months

Across all workspaces, 87% of agent tool calls are allowed by policy without a human. 12.7% require approval, and 0.3% are denied outright. Of the calls that require approval, 93.5% are approved, 4.1% are amended, and 2.4% are rejected. The median approval takes under three minutes.

The number we watch most closely is a different one: how often an action that was allowed without approval is later reversed by a person. That is currently 0.04%. When it moves, we look at which policy allowed the action and why.

Approval gates are available on every plan. Trace replay, which lets you test a policy change against your recorded history before shadow mode, is on Pro and Enterprise. The agents documentation covers the policy syntax in full.