A human approval boundary belongs immediately before the action whose
consequences matter. The agent may prepare the work, explain it, and collect
evidence. It may not cross that boundary with a general "approved" flag.

This tutorial uses a customer-facing status update as the example. The same
shape applies to merging code, issuing a refund, changing access, or starting a
deployment. The risk and reviewer will differ, but the boundary should still
authorize one exact action.

## 1. Name the action that needs approval

Write the boundary as a verb and object:

```text
publish status update STATUS-218 to the public status page
```

Avoid broad boundaries such as "approve the run" or "allow production." They
do not say what the person is permitting. If a workflow has several
consequential actions, give each one a separate boundary.

For the example, the agent may:

- read incident notes supplied to the run;
- draft the status update in a private workspace;
- identify which claims are supported by which note;
- request approval to publish the saved draft.

The agent may not publish, edit the approval record, choose the approver, or
change the draft after approval and reuse the same authorization.

Expected outcome: you can point to one operation that cannot occur without a
valid approval.

## 2. Separate preparation from execution

Expose two operations with different permissions:

```text
prepare(input) -> proposal
commit(proposal_ref, approval_token) -> action_result
```

`prepare` must be safe to run without approval. It writes only to a private or
reversible location. `commit` is the narrow operation that can affect the live
system.

Do not hide both operations behind one agent tool that pauses for a click and
then continues with its existing authority. The commit operation should verify
the approval itself. That way, bypassing the user interface does not bypass the
boundary.

Expected outcome: a prepared draft can wait, expire, or be rejected without
publishing anything.

## 3. Build the approval request

The reviewer needs the proposed action, its consequences, and enough evidence
to make a decision. They should not have to infer the action from a long agent
transcript.

Use a compact approval request:

```text
request_id: APR-551
run_id: RUN-8860
action: publish status update STATUS-218
target: public status page
proposal_ref: sha256:...
summary: report delayed imports and the active mitigation
evidence_refs:
  - incident/observation-14
  - checks/claim-support.json
known_limits:
  - recovery time is not yet confirmed
requested_by: agent-runner
expires_at: 2026-08-13T15:30:00Z
```

Render the actual content or diff beside this metadata. A hash proves which
content was reviewed, but a person cannot review a hash.

Do not mark the request approved by default. The allowed states should make
waiting and rejection explicit, for example `PENDING`, `APPROVED`, `REJECTED`,
`EXPIRED`, and `CANCELLED`.

## 4. Ask a person to make the decision

The reviewer should see three controls:

- approve this exact action;
- reject it with a reason;
- return it for revision without authorizing execution.

The screen or message should show the target, visible proposal, evidence,
known limits, and expiry. It should also state what will happen after approval.
For example: "Approval permits one attempt to publish this exact draft before
15:30 UTC."

The reviewer must not rely on the agent's confidence as evidence. If the draft
says service is restored, the request should point to the observation that
supports that claim. If there is no supporting observation, the reviewer can
reject the request or revise the claim.

Expected outcome: approval is an informed decision about a concrete action,
not a reward for a persuasive explanation.

## 5. Issue a narrow, single-use token

After approval, the approval authority issues a token or signed record bound to
the decision:

```text
approval_id: APPROVAL-992
request_id: APR-551
action: publish
target: status-page/STATUS-218
proposal_ref: sha256:...
expires_at: 2026-08-13T15:30:00Z
max_uses: 1
approved_by: operator-17
```

The approval authority should not share signing credentials with the agent.
The commit operation validates the action, target, proposal reference, expiry,
and use count. A token for a status update must not authorize a deployment. A
token for one draft must not authorize a later revision.

If a signed token is not appropriate for your environment, store the approval
in a protected service and let `commit` query it. The important property is
the same: the agent cannot create or widen the permission it consumes.

## 6. Commit the action and record the result

Before execution, `commit` should check:

1. The approval is valid and unused.
2. The current proposal still matches `proposal_ref`.
3. The action and target match the approved scope.
4. The approval has not expired or been cancelled.
5. Required evidence is still within its validity window.

Consume the approval at the point where the action starts, or use an atomic
reservation if the target supports retries. Record both the attempt and the
result. A timeout after the target accepted the action is not safe to retry
blindly.

```text
approval_id: APPROVAL-992
action_attempt_id: ACTION-4401
proposal_ref: sha256:...
started_at: ...
result: succeeded
target_ref: status-page/event-781
```

Expected outcome: the record connects the reviewed proposal to the action that
actually occurred.

## Check the boundary

Test refusal paths as seriously as the happy path:

- Call `commit` without approval and confirm no live action occurs.
- Change one character in the proposal after approval and confirm the token is
  rejected.
- Reuse a consumed token and confirm the second action is refused.
- Present an expired or cancelled approval and confirm the workflow returns to
  a non-executing state.
- Change the target while keeping the proposal unchanged and confirm the token
  cannot authorize the new target.
- Approve a request, make the supporting evidence stale, and confirm execution
  pauses for a new review when freshness matters.

## Handle failures

If the request expires while waiting, create a new request from the current
proposal. Do not extend the old authorization silently.

If the reviewer asks for changes, produce a new proposal reference and a new
approval request. Keep the rejected request so the history explains why the
work changed.

If execution fails before the target accepts the action, record the failure and
request a new token for a retry. If acceptance is uncertain, reconcile against
the target first. Retrying an uncertain payment, publication, or permission
change can duplicate the consequence.

If the approval service is unavailable, wait. A human approval boundary that
defaults to execution during an outage is not an approval boundary.

## Next steps

- [Trace a failed agent run](/guides/tutorial/trace-a-failed-agent-run)
- [Read the trust rule behind independent review](/notes/control-loop/your-agent-should-not-be-its-own-reviewer)
- [Review the closure test](/reference/closure-test)