Approvals — human-in-the-loop

Some steps should not be automatic: shipping an order over a threshold, sending the customer email, deleting production data. The Approval node parks the run until a person decides — and every pending gate across your whole fleet lands in one inbox in the Nucleus header.

The gate

Drop Approval (Logic group) where the decision belongs. Its config:

PropertyMeaning
titleThe question, verbatim, on the approval card — “Approve order?”
descriptionContext for the decider
decisionsThe options the decider picks from — default Approve, Reject. Each becomes its own output port, so add your own (Decline, Defer, Retry) for a multi-way human gate
timeoutMs0 = wait indefinitely; otherwise the gate expires after this long
onTimeoutWhat expiry does: approve, reject, or error (fail the run into its recovery lane)

With the default decisions the node has two outputs — approved and rejected — so both outcomes are wires, not status codes. Every decision you add is another wire, and the decide endpoint (and the inbox) accepts any configured option, not just the classic pair.

A real example

The shipped Approval Gate demo gates an HTTP-triggered order flow with four nodes:

  1. an HTTP Trigger listening for POST /orders,
  2. an Approval gate titled “Approve order?”, its description written for the human (“A new order needs a human decision before it ships”), no timeout,
  3. an HTTP Response with status 202 wired to the gate’s approved port, and
  4. an HTTP Response with status 403 wired to rejected.

The two outcomes are two visibly different wires on the canvas — the Approval node reference shows the wired capture and a real approved run’s data.

POST an order to /orders and the caller waits while the run parks at the gate. Approve → the caller gets 202; reject → 403. (An HTTP Response node does not release the caller earlier: on a deployed host the reply is built from that node’s recorded output once the run reaches a terminal state, so a workflow containing one holds the connection through the park. To not make the caller wait for a human, leave the response node out and take the async receipt instead.)

Here is the live loop, recorded end to end — an order arrives, the inbox bell lights up, Approve, and the parked run resumes:

A real pending gate decided from the Nucleus approvals inbox.

The host’s own dashboard shows the same gate in its Pending approvals panel — see the capture in the Hosts guide.

The fleet-wide inbox

The bell in the Nucleus header polls every pending gate across every authorized host. Each card shows the gate’s title and description, the workflow and app, the host, how long it has waited, and a live countdown when a timeout is set. Approve / Reject (with an optional note) resumes the parked run immediately — the deciding user’s name is recorded with the decision.

Deciding requires the executor role; viewers see the inbox read-only. Hosts also show their own apps’ pending gates in a panel on the host dashboard.

Where the run actually waits

On a deployed host the parked run lives in the host’s embedded engine; the host serves its pending-gate listing and decisions.

Pending gates don’t survive a host restart. A restarted host starts clean and the parked run is gone — the gate cannot be rebuilt, because a run is only written to the durable record once it reaches a terminal state. What the caller sees depends on how the webhook answers:

  • The default (async) webhook isn’t holding a connection at all — it was handed 202 { runId, status, statusUrl } before the gate was ever reached. After a restart its status URL returns 404: the run neither succeeded nor failed, it stopped existing.
  • A workflow with an HTTP Response node is on the synchronous contract, and the host only builds that reply once the run reaches a terminal state — so a caller parked at a gate is still holding the connection. A restart drops it, and there is no reply and no run left to collect. The synchronous contract is the worse one to be on here, not the better one.

If a gate may stay open across a deploy or a restart, don’t rely on the run surviving it: have the workflow record its own state (a database row, a queue message) before parking, so the decision has something durable to land on.

In the editor

Approval gates work in test runs too — the run pauses, Studio surfaces the gate, and you decide it inline. Same node, same semantics, before anything is deployed.

Agent tool calls can wait for you too

The gate pattern extends to AI: the AI Agent node’s approval property (off / write / all) parks the agent’s tool calls for a human decision through the same machinery — an agent can research freely but needs a sign-off before it writes. The pending call surfaces like any other gate, with its own timeout policy.