Build reliable AI systems
What Should AI Need Before It Can Change the Real World?
A human yes is not a force field. Bind approval to one exact target, operation, payload, cost, permission scope, and set of preconditions, then prove what happened.

An AI agent drafts a customer update. You read it, check the recipient and message, and approve the send.
Thirty seconds later the workflow retries. The recipient changed from the test account to the customer list. The message picked up a new link. The tool still has the same broad permission. The approval record still says yes.
What, exactly, did you approve?
This is where most human-in-the-loop designs get mushy. They ask a person for permission, save a decision, and treat that decision as a reusable glow around whatever the agent does next. That is approval theater.
An approval should authorize one canonical action: one operation, one target, one payload, one cost ceiling, one permission scope, and one set of material preconditions. Change any of those and the approval expires. The workflow stops and asks again.
I learned the hard edge of that rule while building WarpOS, my agentic operating-system project. Its frozen approval guards could require an approval record before a release or outside-service transition. The same frozen evidence also contains a release YAML that says deployed and a report that says not deployed. A permission record and a status label are not the outside world.
The decision here is narrower than a general autonomy policy. Which actions may run automatically? Which exact action needs a person? Which action should remain blocked? Once approved, what proves that the authorized action happened and can be recovered from?
TL;DR
- Bind approval to one canonical action fingerprint, not a broad capability or a chat message.
- Choose APPROVE, REQUIRE_HUMAN, or BLOCK from impact, recoverability, sensitivity, cost, permissions, and verifiability.
- Invalidate approval when the target, operation, payload, cost, permission, material precondition, or expiry changes.
- Treat the execution receipt and independent postcondition as separate evidence.
- Preserve unknown outcomes, exception state, and rollback evidence so a retry cannot quietly repeat the action.
01 / GuideWhat changes when an AI agent can act?
Drafting is cheap to undo. Sending, purchasing, publishing, deleting, deploying, or changing a customer record creates a second system whose state may outlive the agent session.
That outside state introduces four separate moments: proposal, approval, execution, and verification. Collapsing them into one approved flag is how drift hides.
The target can change after review. A payload can be regenerated. A price can move. A permission can become broader. A precondition can expire. A retry can repeat an action that already succeeded. The agent can also report success when the downstream system timed out, rejected the request, or accepted only part of it.
The operating rule is simple: approval must match the action. Execution must produce a receipt. The target must prove the postcondition.
Human approval handles judgment. It does not replace authorization enforcement, transaction integrity, idempotency, downstream receipts, or rollback.
02 / GuideWhich actions should run automatically, require a person, or stay blocked?
Start with impact and recoverability, then account for data sensitivity, permissions, cost, scope, and whether the result can be verified.
Do not turn REQUIRE_HUMAN into the default for every tool call. That creates a queue of low-context prompts until people click yes on instinct. Automate the safe class with narrow policy. Reserve attention for actions where human judgment changes the risk.
Also keep the decision action-level. Allow email is a capability grant. Send this digest to these three recipients with this subject and body before 5 p.m. is an action.
03 / GuideWhat should an action-level approval contract contain?
The contract needs enough information to reconstruct what was proposed, what was authorized, what executed, and what happened next.
Canonicalization matters. Two equivalent JSON objects should not produce different fingerprints because their keys were reordered. Two materially different recipient lists should not produce the same fingerprint because the approval display hid the recipients.
Use the significant data a reviewer actually needs. OWASP calls this what you see is what you sign in transaction authorization. The target and amount of a transfer are the classic example. For an AI action, significant data may include recipients, public visibility, revision, environment, price, permissions, or deletion scope.
Recompute the fingerprint at the final control gate. Do not trust the proposal-time hash if the executor rebuilt the payload later.
04 / GuideWhat does the local mutation experiment prove?
I built a side-effect-free Node.js fixture around one temporary local JSON file. No account, API, customer, deployment, purchase, message, or remote system was touched.
The starting file is an internal-review draft. The proposed action replaces it with an internal-review published record. Its fingerprint covers the target, operation, payload digest, zero-dollar cost ceiling, starting file digest, local environment, and narrow write permission.
The fixture approves that fingerprint, then changes one field: audience becomes public. The changed action is rejected as BLOCKED_ACTION_MISMATCH. The target digest remains unchanged.
The fixture then submits the exact approved action, rechecks the starting digest immediately before execution, writes the file, records a receipt, reads the target independently, verifies the after-digest, restores the original bytes, and verifies the starting digest.
That result proves a narrow mechanism. It does not prove production safety, distributed rollback, credential security, downstream idempotency, concurrent-write handling, or approver identity. Those controls must exist at the real boundary.
The useful part is the failure shape. A one-field material change invalidates the old approval before the write. That is the behavior to plant in a test.
05 / GuideWhat do current agent tools provide, and what still belongs to you?
Current agent products expose useful approval and permission surfaces. They do not remove the need for your application contract.
The OpenAI Agents SDK can pause a run when a tool call needs approval. Its documented interruption contains the tool name and arguments, and approval is scoped to a specific call ID unless a developer deliberately chooses a sticky decision. The SDK also supports serializing run state across a long approval wait. That is valuable orchestration. Your application still decides which arguments are significant, how they are canonicalized, when approval expires, what downstream credential is used, and what receipt proves success.
Claude Code's current permission model separates allow, ask, and deny rules, with deny taking precedence. Its documentation says the runtime enforces those rules rather than relying on the model. That is a real boundary. A shell permission rule still describes a class of commands. It is not a business approval for one deployment target, revision, cost, and rollback plan.
OWASP's Excessive Agency guidance recommends minimizing tool functionality and permissions, executing in the user's context, requiring human approval for high-impact actions, and enforcing authorization in downstream systems. Its transaction authorization guidance says significant data should be visible to the approver, changed data should invalidate authorization, the final execution gate should recheck authorization, and authorization should be unique and time-limited.
06 / GuideWhat did frozen WarpOS evidence teach me about approval?
WarpOS had sensible hard ceilings. The frozen autonomy document reserved remote pushes, paid-service signups, production deploys, destructive migrations, and secrets sent to remote systems for an operator decision.
Its external-service gate blocked a descriptor that required approval unless the recorded state was approved or waived. Its approval hook also checked that a release had an approval reference pointing to an approved or waived record before deploy.
Those controls were better than asking the model to be careful. They also exposed the next problem.
The approval hook checked a pointer and state. It did not bind target, operation, payload, cost, permission, preconditions, expiry, receipt, or rollback. Its own header said parse errors failed open, and an environment variable could disable it.
The frozen release records made the evidence problem concrete. RL-20260611-045.yaml says deployed to internal-canary, names an approval reference, timestamp, and actor. Its companion report says preparing, not deployed, no approval recorded, and deployment not performed.
I cannot infer the real deployment state from that disagreement. The YAML may be newer. The report may be stale. The external target may tell a third story. That is precisely the point.
A release record is not a deployment receipt. A rendered report is not a target postcondition. If two internal artifacts disagree, stop pretending a status label settles reality. Query the deployment target, bind the receipt to the action, regenerate or invalidate stale reports, and keep the mismatch visible until reconciled.
07 / GuideWhat should happen after approval?
Approval is the start of controlled execution, not the end of review.
Unknown is a first-class result. If the network times out after a send request, retrying blindly can send twice. The next action is not try again. It is query by idempotency key or receipt, determine whether the first action happened, then decide.
08 / GuideHow do you implement the first exact-action gate this week?
Pick one reversible action with a real consequence but a contained blast radius. Do not start with money movement, broad deletion, or an irreversible production migration.
Write its canonical schema. Name the significant fields. Create the fingerprint. Display those same fields at approval. Make any material change invalidate the decision. Use a credential that can perform only that operation on that target. Capture the downstream receipt. Query the target. Exercise rollback in a safe environment.
Then plant three failures: change the target after approval, change one significant payload field, and let the approval expire before execution. All three should block before the outside call.
09 / Key takeawayConclusion
A human yes is not a force field.
Bind it to one action. Recompute the match at the execution gate. Use the smallest permission. Keep the receipt. Ask the target what happened. Preserve the exception and rollback state for whoever has to recover the workflow later.
Approval must match the action.
Quick answersCommon questions
What actions should always require human approval from an AI agent?
Require a person when an action has meaningful impact on another person or system and human judgment can contain the risk. Common cases include sensitive messages, public publishing, spending money, changing permissions, production deploys, durable deletion, and regulated or customer records. Block the action when the result cannot be understood, verified, contained, or recovered from.
Is a tool permission prompt enough approval?
No. A permission prompt can authorize a capability or one tool call. The application still needs to bind significant target, operation, payload, cost, permission, and precondition data to the decision, enforce it at execution time, and verify the downstream result.
What should invalidate an AI action approval?
Invalidate approval when the target, operation, significant payload data, cost ceiling, permission scope, material precondition, environment, or expiry changes. High-impact actions should also invalidate after a failed or unknown execution until the target state is reconciled.
What is the difference between a receipt and a postcondition?
A receipt records what the execution path says it attempted or accepted. A postcondition is an independent observation of the target state you intended to create. A deployment command can return success while the wrong revision is live, so you need both.
Should an AI agent retry a timed-out outside action?
Not automatically when the first outcome is unknown. Query the target by receipt or idempotency key first. Retry only after proving the first action did not happen or after using a downstream idempotency guarantee that makes the repeat safe.
How should approval survive a long-running AI workflow?
Store the exact proposal, fingerprint, decision, approver, expiry, pending execution state, receipts, and recovery instructions durably. On resume, revalidate the current action and preconditions. Never treat a resumed session as proof that the old approval still matches.
Sources11 references
- OpenAI Agents SDK human-in-the-loop guide (opens in a new tab)
- Claude Code permission documentation (opens in a new tab)
- OWASP LLM06:2025 Excessive Agency (opens in a new tab)
- OWASP Transaction Authorization Cheat Sheet (opens in a new tab)
- WarpOS frozen public source (opens in a new tab)
- WarpOS external-service approval gate (opens in a new tab)
- WarpOS autonomy ceilings (opens in a new tab)
- WarpOS approval guard (opens in a new tab)
- WarpOS release helper (opens in a new tab)
- WarpOS frozen release record (opens in a new tab)
- WarpOS frozen release report (opens in a new tab)
Choose your next move
