04 HITL approval intro
Before you start
Complete 02 Server API first run. HITL (human-in-the-loop) requires arcflow-server with Postgres and recovery_enabled: true on the run. Embedded SDK runs without the server cannot persist interrupt state across restarts in production.
03 External callbacks intro also ends in Interrupted status, but external callbacks wait for integrator HTTP posts. HITL waits for a human approver on a dedicated approve route.
Concept
HITL pauses a workflow at a designated step until a human approves or rejects the pending action. ArcFlow treats the pause as a first-class run state (Interrupted), not an error. After the gated step completes its agent work, the runtime stores interrupt metadata in Postgres and waits for:
If the approver sends approved: true, the engine resumes and runs downstream steps. If approved: false, the run fails with error code HumanRejected. If timeout_seconds elapses with no decision, the run fails with HumanTimeout.
Attach HITL per step, not on the workflow root. Each gate declares a stable approval_key used in the approve URL.
State machine (HITL branch):
Python SDK callers may catch WorkflowInterruptedError with run_id and approval_key when targeting the HTTP server with recovery enabled.
Example
Three-step expense flow matching examples/hitl/expense_approval.py:
When interrupted, poll run status:
The response includes an interrupt object with approval_key and expires_at (metadata only, no full conversation text).
Approve to resume:
Or use the helper script:
Poll again until status is Completed and read result.output.
Verify
| Check | Expected |
|---|---|
| Run stops after manager step | status is Interrupted |
| Accounting step before approve | Does not run |
Approve with approved: true | Run completes; accounting step runs |
Reject with approved: false | Failed with HumanRejected |
Wrong approval_key | ApprovalNotFound (404) |
Trace exports remain metadata-only trace only. You see step lifecycle events, not approver notes, in trace storage.
Next
| Goal | Document |
|---|---|
| Step-level HITL fields | Configuring interrupts |
| Approve API detail | Approve and reject |
| Full tutorial | Track E: HITL and external |
| Static browser client | Static site chatbot |
When external binding recovery sets on_fatal: hitl_escalate, failed external work can route into the same HITL approve flow. See External callbacks.