Automation · AI operations
How to build human approval for agent actions
An agent is about to email four hundred customers and the only thing between it and them is somebody noticing. Here is the model behind an approval step, the prompts that build it, and what it takes to run in production.
Built with Tray Headless
- System Agent
- Step Classify blast radius
- Step Below threshold: act
- Step Above: request approval
- System Slack
The threshold is blast radius instead of confidence, and an approval request that expires defaults to not acting.
The short answer
What is agent action approval?
Agent action approval is four parts: a threshold based on blast radius rather than on model confidence, a request that shows the approver exactly what will happen, an expiry that defaults to not acting, and a record of who approved what. The part that goes wrong most often is using confidence as the trigger. A model is often most confident when it has misunderstood, so confidence decides nothing useful and reversibility decides everything.
What matters here
- Trigger on blast radius, not model confidence. A model is frequently most confident when it has misunderstood.
- Show what will actually happen: the records, the recipients, the amounts. Not a summary the model wrote of its own plan.
- Expire to no action. An approval nobody answers must never default to proceeding.
- Route to whoever owns the consequence, not whoever is nearest. The approver has to be able to judge it.
- If approval rates sit near 100%, the threshold is wrong and everybody is rubber-stamping.
Who this is for
You run AI operations or platform engineering. Agents are doing useful work and the question of what they may do without asking has not been answered.
How it works in practice
What happens between an agent deciding to act and the action happening.
- 1
The action is classified by blast radius
How many records, is it reversible, does it reach a customer, does it move money.
- 2
Below the threshold it proceeds and is logged
Approval for everything trains people to approve without reading.
- 3
Above it, a request goes to whoever owns the consequence
With the actual effect shown, not a summary the model wrote.
- 4
The approver sees the real payload
Records, recipients, amounts and a diff where something is being changed.
- 5
No answer means no action
The request expires and the agent is told it was not approved, never that it timed out into proceeding.
- 6
The decision is recorded either way
Who, when, what was shown, and what happened afterwards.
What an approval step is made of
Four pieces, and the first is a judgement about reversibility.
A blast radius threshold
Record count, reversibility, whether it is customer-facing and whether money moves. Confidence is not on that list for good reason.
A request showing the real effect
The payload, the recipients, the diff. An approver reading a model summary of its own plan is not reviewing anything.
A safe expiry
Unanswered means not approved. Anything that defaults to proceeding turns approval into a delay, not a control.
A decision record
Who approved, what they were shown, and what happened. That record is what makes the whole arrangement defensible.
The Tray Headless prompts
Paste these into Claude Code or Codex with the Tray Headless plugin installed. Each stage runs on its own. The systems named in them are the worked example rather than a requirement, and every prompt says so.
Once per project, run
/tray-workflows:set-workspace
to pick the workspace these build in. Point it at a sandbox first.
- 1
First, define blast radius, not confidence
The trigger is the design, and confidence is the wrong one.
Headless skills
build-workflowUse build-workflow. Classify every agent action before it executes: Record count: how many things change Reversibility: can this be undone, and how easily Customer-facing: does anything reach somebody outside the company Financial: does money or an entitlement move Destructive: does anything get deleted or overwritten irrecoverably Then set the threshold on those, never on model confidence. A model is frequently at its most confident when it has misunderstood the request, so confidence tells you about the model instead of about the risk. Start conservative: anything customer-facing, anything financial, anything touching more than a handful of records, and anything irreversible.
Reversibility is the most useful of the five. An action you can undo in a minute rarely needs a gate; one you cannot always does.
- 2
Show the approver what will actually happen
A model summarising its own plan is not a review.
Build the approval request to show the real effect, not a description: The exact records that will change, with a before and after diff For anything outgoing, the full recipient list and the actual message For anything financial, the amounts and the accounts What triggered the agent, and the instruction it was given Never show only the model's own summary of its plan. If it misunderstood the task, its summary will be a confident description of the wrong thing, and an approver reading it will approve. Cap the display and say so: showing the first twenty of four hundred records with the count is honest. Showing four hundred is unreadable, and unreadable is the same as unreviewed.
- 3
Route to whoever owns the consequence
An approver who cannot judge it will approve it.
Route by what the action touches, not by who is available: Customer-facing goes to the account owner Financial goes to the budget owner or finance Data changes go to the system owner Anything above a higher threshold goes to two approvers Send it where they already work, not to a queue they would have to remember to open. Include enough context to decide without going elsewhere: the account, the amount, the history, the instruction. An approver who has to open three tabs will approve on the summary, which is the failure this whole step exists to prevent.
- 4
Expire to no action, always
Anything that defaults to proceeding is a delay, not a control.
Headless skills
tray-gotchasUse tray-gotchas, then set an expiry on every request, and expire to not approved. An unanswered approval must never proceed on a timeout. If that is unacceptable for a given action, the action does not need approval, and pretending otherwise gives everybody the reassurance of a gate without the gate. Tell the agent it was refused, in a form it can act on: not approved, expired without an answer, and what it should do instead. Handle these: an approver who is away, which routes to a deputy rather than waiting; a request superseded because the agent has moved on; and approval arriving after the underlying data changed, which should re-validate rather than execute a stale plan.
- 5
Record it, and watch the approval rate
A 99% approval rate means nobody is reading.
Record every decision: who, when, exactly what was shown, the outcome, and what happened after it executed. Then report: approval rate by action type, median time to decision, expiries, and how often an approved action later needed correcting. If approval rates sit near 100%, the threshold is wrong. Either the agent is being gated on things that do not need it, in which case people are rubber-stamping and the real ones will be rubber-stamped too, or the requests are unreadable and everybody is approving on trust. Both of those look like a working process and neither one is.
- 6
Test it, then hand the thresholds over
Because what needs approving is a risk decision that will change.
Run the per-step schema checks and the whole-workflow audit before this touches production. Run it in observe mode first: classify every action and request approval for nothing, then read a week of what would have been gated. Then open the same workflow in Tray Build so the team owning the agents can adjust thresholds and routing in the visual canvas as trust in a given agent grows.
What it connects to
The agent proposes, a person decides, and the record outlives both.
Slack
Send the request where the approver already works, with the real payload rather than a link to it.
Writes
Okta
Resolve the owning group from the ownership register to the people currently in it, so approval never depends on one named individual.
Reads
Snowflake
Land every decision with what was shown, which is what makes the arrangement defensible afterwards.
Writes
Jira
Raise a record for anything refused, so a refusal is a conversation instead of a dead end.
Writes
Same build, other stacks
The design does not change if you run something else in one of these seats. The same prompts build it against Microsoft Dynamics 365, Google BigQuery, Microsoft Teams, Azure Active Directory, ServiceNow or HubSpot.
Named systems are the ones most teams run, not the only ones that work. Each is an authentication in your Tray workspace, referenced by name, so the workflow never holds a credential. Where we have a connector page, the name links to it.
Running it in production
This is the control between an agent and an irreversible action. It has to fail safe.
The platform runs it, not a laptop under a desk
Requests, expiries and re-validation run on the same engine, so an approval at 2am behaves exactly like one at midday.
Every decision is evidence
Who approved, precisely what they were shown, and what happened next. Showing a summary and recording a payload is not the same thing.
Credentials are managed, never in code
The approval step reads records to build the diff. Read-only, scoped, and held in your workspace instead of alongside the agent.
The agent team owns the thresholds
Blast radius rules and routing open in Tray Build, so a gate can be relaxed as trust in an agent is earned instead of assumed.
Expiry never proceeds
Unanswered is refused. Any action that cannot tolerate that does not need approval, and pretending otherwise is worse than having no gate.
Questions people ask
Why not trigger on model confidence?
Because a model is frequently most confident when it has misunderstood the request. Confidence tells you about the model, and reversibility tells you about the risk.
What should the approver see?
The actual effect: the records changing with a diff, the full recipient list, the amounts. Never only the model summary of its own plan, which will confidently describe the wrong thing if it misread the task.
What happens if nobody answers?
It expires as not approved. Anything that proceeds on a timeout is a delay rather than a control, and it gives everybody the reassurance of a gate without one.
Who should approve?
Whoever owns the consequence: the account owner for customer-facing actions, finance for money, the system owner for data. An approver who cannot judge it will approve it.
What does a 99% approval rate mean?
That the threshold is wrong. Either trivial actions are being gated, so people rubber-stamp and will rubber-stamp the real ones too, or the requests are unreadable and everybody is approving on trust.
Related guides
AI operations
How to expose an internal system as an MCP tool
Scope the tool to a job rather than an API, resolve identity per call, make writes idempotent, and log every invocation. The Headless prompts that build it.
AI operations
How to build LLM cost and usage tracking
Attribute spend to a team and a feature, alert on the rate rather than the total, and catch the loop before the invoice does. The prompts that build it.
AI operations
How to build an agent observability pipeline
Capture whole agent runs instead of single calls, join each one to the outcome it produced, and alert on the failures that return an answer anyway. The prompts.
Last reviewed September 2026.