Human in the Loop

Human in the loop (HITL) lets a workflow pause and wait for a person before continuing. When a run reaches a node configured for HITL, the platform creates a request, assigns it to a user or a role, pauses the run, and notifies the assignee. The run resumes — picking up exactly where it left off — once that person responds. Use it for approvals on a sensitive action, for collecting structured input mid-run, or for asking a clarifying question.

HITL is first-class in the run model: a paused run has the paused status, and the waiting step has the paused step status, so paused work is fully visible in the run history.

How HITL is configured

HITL is not a separate node type. You attach a hitl_config block to an agent node. The block has three modes:

ModeWhat the person doesBest for
conversationAnswers a question, picks a choice button, or types free textClarifying questions and approvals mid-conversation
formFills in a structured form you define with a JSON SchemaCollecting specific fields before the run continues
external_formCompletes a form hosted in an embedded iframeBringing an external system's form into the flow

A minimal conversation-mode block looks like this:

{
  "mode": "conversation",
  "prompt": "This refund exceeds $500. Approve?",
  "assign_to": "triggering_user",
  "timeout": "1h",
  "timeout_behavior": "fail_run",
  "channels": ["in_app"]
}

Assigning the request

assign_to decides who can respond. It is always required and takes one of three forms:

  • "triggering_user" — the user who started the run. Resolved to that user's ID at run time.
  • A user UUID — a specific, named user. Validated at publish time, so a non-existent user fails the publish with HITL_INVALID_ASSIGNEE.
  • "role:<name>" — anyone holding that role (for example "role:builder_admin"). The request is then claimable: an eligible user claims it before responding, so two people don't act on the same request.

Other settings

  • prompt — the question or instruction shown to the assignee.
  • form_schema — for form mode, the JSON Schema that defines the fields to collect.
  • timeout and timeout_behavior — how long to wait (a Go duration string such as "15m" or "1h") and what to do if no one responds in time: fail_run, skip_node, or auto_approve.
  • channels — where to notify the assignee; defaults to ["in_app"].
  • max_hitl_interactions — caps the number of back-and-forth rounds for a conversation request (default 5).
  • summarize_on_exit — when true, the agent summarizes the HITL exchange before the run continues.

The pause-and-resume cycle

Two distinct mechanisms can pause a run for a human. Both end in the same resume path.

Node-level HITL

When the executor reaches an agent node whose hitl_config requires a response, it:

  1. Creates a HITL request (with the prompt, the assignee, and the captured run state).
  2. Sets the step to paused and the run to paused.
  3. Notifies the assignee on the configured channels.

The run stays paused — consuming no compute — until a response arrives. Other independent branches of the DAG that don't depend on the paused node keep running in parallel.

Mid-execution ask_human

An agent can also pause itself mid-reasoning by calling the built-in ask_human capability — for example, when it realizes it needs a missing detail to proceed. The agent serializes its state, the workflow creates a HITL request, and the run pauses. When the person answers, the response is folded back into the agent's context and the same agent resumes its reasoning. Multiple ask_human rounds are supported within one step.

In both cases, resuming re-resolves any captured {{...}} references against the current run state, so the agent continues with correct, up-to-date data.

Responding to a request

Assignees act on HITL requests through the in-app inbox or the API:

EndpointPurpose
GET /api/v1/workflow/hitl/pendingList the requests waiting on you.
GET /api/v1/workflow/hitl/{request_id}Read a single request.
POST /api/v1/workflow/hitl/{request_id}/claimClaim a role-assigned request so you can respond to it.
POST /api/v1/workflow/hitl/{request_id}/respondSubmit your response and resume the run.
POST /api/v1/workflow/hitl/{request_id}/cancelCancel a pending request.

The shape of the response depends on the mode. A conversation request expects a choice or free-text answer:

POST /api/v1/workflow/hitl/{request_id}/respond
Content-Type: application/json

{ "response": { "type": "freetext", "value": "Approved — proceed with the refund." } }

A choice response sends { "type": "choice", "value": "<one of the offered choices>" }. Form requests submit the collected field values. On a valid response, the run leaves paused, the step completes, and execution continues down the DAG.

Plan for the wait. A paused run can sit for as long as your timeout allows. Set timeout_behavior deliberately: auto_approve keeps throughput high for low-risk steps, while fail_run is the safe default for anything that must not proceed without a human.

Where to go next

  • Workflows — where HITL fits in the run lifecycle.
  • Agents — attaching HITL to an agent node and the ask_human capability.
  • API reference — the full HITL API.

Last updated: Jul 3, 2026