Compile with interrupt_before=["execute"] and the graph halts BEFORE the named node. Your application shows the current state to a human reviewer for sign-off; afterwards the app calls update_state(config, {”approved”: True}) and resumes via stream(None, config). No “no-abort-path” footguns.
Sensitive refund flow: pause before the execute node, present draft, await approve/reject.
abort path: rejected update_state sets approved=False and routes to END without execution.
Audit: every review stores thread_id + checkpoint_id + reviewer so the decision is traceable.
user_q -> draft -> INTERRUPT -> review -> approve? -> execute (or abort)
Anything that moves money, deletes data, or sends externally must be human-gated by default.