Human Approval Is a Runtime Checkpoint, Not a Button

Jul 31 2026 · 9 min · Sieon

Human approval should not be bolted onto an agent as a modal dialog. It should be modeled as a persisted runtime checkpoint: the agent stops, saves the proposed action, exposes enough context for review, resumes only with a decision receipt, and leaves an audit trail that later systems can test.

Most agent systems start with the same comforting sentence: "a human approves the risky step." That sounds safe until you ask where the approval actually lives. If it lives only in the frontend, chat transcript, or tool wrapper, it is not a control point. It is a moment in the user interface.

The more durable framing is this: approval is a runtime checkpoint. The checkpoint owns state, policy, identity, replay behavior, and observability. The button is only one way a reviewer sends a decision back to that checkpoint.

That distinction matters because production-oriented agent failures rarely happen at the button. They happen around it. The agent proposes a tool call, context changes while a reviewer is away, a retry replays the same action, a guardrail runs at the wrong time, or an audit asks why a particular shell command, email, deploy, refund, database update, or file deletion was allowed. If the system cannot reconstruct that boundary, approval becomes theater.

flowchart LR
    A["Agent proposes action"] --> B["Validate tool input"]
    B --> C["Persist checkpoint"]
    C --> D["Ask reviewer"]
    D --> E{"Decision"}
    E -->|Approve| F["Resume with receipt"]
    E -->|Edit| G["Resume with patched input"]
    E -->|Reject| H["Stop and record reason"]
    F --> I["Execute tool"]
    G --> I
    H --> J["Audit trail"]
    I --> J

The approval button is too late

A UI button can answer one question: did somebody click approve? A runtime checkpoint has to answer a harder set of questions:

Question Why it matters
What exact action was proposed? Reviewers approve concrete state, not vibes.
Which policy required approval? The system needs to explain why this stopped.
What context did the reviewer see? Later audits need the same evidence boundary.
Did the tool input change after review? Approval should not silently drift.
Was the action retried? Retries must not duplicate side effects.
Who resumed execution, and with what decision? Accountability belongs in the runtime record.

If those answers are unavailable, the system may still have a useful human workflow, but it does not have an operational approval boundary.

LangGraph's interrupt model shows the shape of the boundary. Its documentation describes interrupts that pause graph execution, save state through a checkpointer, and later resume by reinvoking the graph with a command value from the caller. The same page calls out durable checkpointers for production use and thread identifiers so the runtime knows which state to resume. That is not just a convenience API. It is the beginning of an approval architecture because the pause is part of execution state, not a loose message outside the runtime.

A checkpoint has four contracts

A serious approval checkpoint needs four contracts.

First, it needs a state contract. The proposed action should be serialized in a stable shape before review. For a tool call, that means tool name, arguments, target resource, expected side effect, policy trigger, user-visible explanation, and a hash of the exact payload. If the payload changes, the approval should be invalidated or reissued.

Second, it needs a policy contract. The system should know why this action stopped. Examples include external network write, destructive file operation, high spend, personal data access, production deploy, customer-visible message, or low confidence result. A reviewer should not have to infer policy from a wall of agent text.

Third, it needs a resume contract. Approval should resume the exact suspended execution with an explicit decision: approve, reject, edit, ask for more information, or expire. "Continue the chat" is not precise enough. The resume path should be typed enough that the runtime can distinguish an approval from a new user request.

Fourth, it needs an observability contract. The checkpoint should emit trace or log data that connects the proposed action, reviewer decision, resumed execution, and final side effect. OpenTelemetry describes traces as a way to represent a request path through a distributed system using spans. Agent approval deserves the same treatment because the reviewer is now part of the execution path.

These contracts make human approval less magical and more boring. Boring is good. Boring systems can be tested.

Current agent systems already expose the seam

This is not a theoretical purity argument. Current agent platforms are already separating review, validation, and execution.

OpenAI's Agents SDK guardrails documentation describes input, output, and tool guardrails, including tool input checks that can run before a pending approval interruption is emitted and again after approval before the tool executes. That detail matters. If validation can happen both before and after approval, then approval is not the only safety mechanism. It is one boundary in a larger runtime sequence.

MCP's elicitation feature exposes another piece of the same model. The MCP specification lets servers request structured information from users through the client. It also says servers must not use elicitation to request sensitive information, and it recommends clear user controls, review and modification before sending, decline and cancel options, schema validation, and rate limiting. That is a reminder that human interaction inside an agent protocol is not just a text prompt. It has capability negotiation, schemas, privacy rules, and abuse controls.

Taken together, these systems point toward the same design principle: human input should be protocol-shaped when it affects execution. Approval is too important to remain an unstructured chat convention.

The trace needs the reviewer decision

Agent traces often show model calls, tool calls, token counts, latency, and errors. That is useful, but incomplete when a human is in the loop. If a reviewer changes the outcome, the reviewer decision is part of the execution path.

A useful approval trace should show:

  • the span where the agent proposed the action
  • the policy span that required review
  • the checkpoint span that persisted the suspended state
  • the reviewer decision, including approve, reject, edit, or expire
  • any changed payload after review
  • the resumed tool execution span
  • the final side effect or refusal

Without this trace, incident review becomes guesswork. A team might know that a risky tool ran, and it might know that someone clicked approve, but it cannot prove that the approved payload is the payload that executed. That gap is exactly where agent systems become hard to operate.

The right mental model is closer to a workflow engine than a chatbot. A workflow engine treats suspension and resumption as first-class execution events. An agent runtime should do the same when a human decision gates side effects.

A minimal approval receipt

The approval receipt does not need to be complicated. It needs to be explicit.

{
  "approval_id": "appr_2026_07_31_001",
  "thread_id": "thr_42",
  "checkpoint_id": "chk_91d2",
  "policy": "external_write",
  "tool": "send_email",
  "tool_input_hash": "sha256:3a7f...",
  "decision": "approved",
  "reviewer": "user_17",
  "reviewed_at": "2026-07-31T13:00:00Z",
  "expires_at": "2026-07-31T13:10:00Z",
  "resume_mode": "execute_original_payload"
}

This receipt gives the runtime something concrete to validate. Before execution, the runtime can check that the checkpoint still exists, the payload hash still matches, the approval has not expired, the reviewer had authority, and the requested resume mode matches the decision.

For edited approvals, store both the original payload hash and the edited payload hash. For rejected approvals, store the reason and stop the execution path. For timeouts, mark the checkpoint expired and require a new decision. These choices are not bureaucracy. They prevent old approvals from becoming reusable permission slips.

Common failure modes

The first failure mode is approving summaries instead of payloads. The agent says, "I will update the configuration," and the reviewer approves without seeing the exact diff, command, endpoint, or record. That approval is weak because the object under review is ambiguous.

The second failure mode is approving before validation. If the tool input is malformed, unsafe, or outside schema, the reviewer may be asked to approve something the runtime should have rejected first. Run deterministic validation before review, then run it again after review if the payload can be edited.

The third failure mode is losing idempotency around interrupts. LangGraph's interrupt documentation warns that side effects called before an interrupt must be idempotent. The broader lesson applies to any agent runtime: if a node can be resumed, replayed, or retried, side effects near the checkpoint need stable identifiers and duplicate protection.

The fourth failure mode is treating decline as an error. MCP's elicitation model includes accept, decline, and cancel response paths. Approval systems need the same respect for negative decisions. A rejection is not a failed workflow. It is a valid safety outcome that should be observable and recoverable.

The fifth failure mode is hiding the reviewer from the trace. If the human decision is not attached to the execution trace, teams cannot later separate model behavior from policy behavior. That makes evaluations weaker because the system cannot tell whether it succeeded because the model was safe or because a reviewer intervened.

What to build first

Start with the smallest checkpoint that can survive an audit.

  1. Define the actions that require approval.
  2. Serialize the exact proposed action before review.
  3. Persist the checkpoint in durable storage.
  4. Show the reviewer the payload, policy reason, and expected side effect.
  5. Resume with a typed decision receipt.
  6. Validate the receipt before execution.
  7. Emit trace spans for proposal, checkpoint, decision, resume, and side effect.

This is enough to make approval measurable. Once measurable, it can be improved. You can ask how often policies trigger, which actions are rejected, which tools produce edited approvals, which checkpoints expire, and which reviewer decisions correlate with later failures.

That feedback loop is impossible when approval is only a button in a chat UI.

FAQ

Is human approval the same as a guardrail?

No. A guardrail is a policy or validation mechanism. Human approval is a decision checkpoint that may be triggered by a guardrail. The two should cooperate, but they should not be collapsed into one concept.

Where should the checkpoint live?

It should live in the runtime or workflow layer that owns execution state. If it lives only in the frontend, the system cannot reliably resume, replay, validate, or audit the approved action.

What should be stored in an approval receipt?

Store the checkpoint identifier, policy reason, exact proposed action, payload hash, reviewer identity, decision, timestamp, expiration, and resume mode. If the reviewer edits the action, store both the original and final payload hashes.

Can this be added after an agent is already deployed?

Yes, but it is harder. Start by wrapping the highest-risk tools with a checkpoint contract, then move approval state into durable storage and add trace events. Do not try to retrofit every tool at once.

The decision rule

Use human approval when the system needs human judgment, not when the runtime lacks engineering discipline. If the action has meaningful side effects, approval must be represented as persisted execution state with a decision receipt. If you cannot replay the question "what exactly was approved and what exactly ran?" without asking the model again, you do not have an approval boundary. You have a button.

References

  1. LangGraph Interrupts documentation
  2. OpenAI Agents SDK Guardrails documentation
  3. MCP Elicitation specification
  4. OpenTelemetry Traces concepts