Human review
A hold pauses one proposed tool call while a person approves or rejects it. The original tool executes only when the same waiting runtime receives a valid approval before expiry.
Review lifecycle
The review record contains tool identity, value-free reasons, a redacted proposed-effect preview, timestamps, and optional reviewer metadata. Raw tool arguments stay in the waiting agent process.
What can create a hold
- a deterministic policy violation;
- a grounding check configured with
on_fail: hold; - a Source error configured with
retry.on_error: hold.
Use hold for an intentional exception process. Do not use it as the default for failures that should never be approved, such as cross-customer ownership mismatch.
Runtime behavior
Console-managed enforce() creates a ReviewClient automatically. A held synchronous tool call waits on its request thread. A held async tool runs the wait outside the event loop.
Defaults:
agent = enforce(
agent,
agent_id=agent_id,
api_key=agent_key,
review_timeout=300,
review_poll=2,
)
An approval releases the original call and executes the tool with the arguments already held in that process. A rejection, expiry, timeout, or unavailable review service leaves the tool unexecuted.
Local config= mode without a control plane cannot park a remote review. It returns a held result immediately.
Result codes
| Code | Meaning | Tool executed? |
|---|---|---|
ACTIONRAIL_REJECTED | A person rejected the review. | No. |
ACTIONRAIL_REVIEW_UNAVAILABLE | The review could not be opened, or connectivity was unavailable at the deadline. | No. |
ACTIONRAIL_HELD | The review timed out, expired, or remains an unresolved hold without remote review. | No. |
These codes let application logic distinguish human rejection from infrastructure failure without exposing private decision values to the model.
Console outage behavior
Review is the intentional exception to local-only enforcement because a person must communicate a decision to the waiting runtime.
- If the review cannot be opened, the runtime fails closed immediately.
- A transient polling failure after creation does not discard the review; the runtime keeps waiting.
- If connectivity is still unavailable at the deadline, the runtime returns
ACTIONRAIL_REVIEW_UNAVAILABLE. - Server-side expiry prevents a late approval from releasing a call after the runtime deadline.
Process lifetime
The proposed call is held in runtime memory. It is not a durable workflow job.
If the agent process restarts or the request is cancelled, that exact call cannot safely resume from the Console record alone. The review expires and a new agent action must be proposed and evaluated again.
Do not design multi-hour or offline approval workflows around the current synchronous review mechanism.
Capacity planning
Each pending review consumes a waiting request/thread context and retains proposed arguments in process memory. Set review_timeout according to:
- normal operator response time;
- application request deadlines;
- worker/thread capacity;
- deployment termination and autoscaling behavior;
- the risk of executing an action after facts have become stale.
For high-volume exception workflows, keep rules narrow enough that holds remain exceptional. A surge in pending reviews is an operational issue, not normal throughput.
Reviewer guidance
Reviewers should see enough redacted context to understand the proposed effect without needing raw Source records. If a decision cannot be made safely from the approved metadata, reject it and investigate in an authorized system rather than adding broad values to report_args by default.