> Source: https://builder.ema.ai/v2/core-concepts/human-in-the-loop
> Title: Human in the Loop

# 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](/builder/v2/core-concepts/agents) node. The block has three modes:

Mode

What the person does

Best for

`conversation`

Answers a question, picks a choice button, or types free text

Clarifying questions and approvals mid-conversation

`form`

Fills in a structured form you define with a JSON Schema

Collecting specific fields before the run continues

`external_form`

Completes a form hosted in an embedded iframe

Bringing an external system's form into the flow

A minimal conversation-mode block looks like this:

```json
{
  "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:

Endpoint

Purpose

`GET /api/v1/workflow/hitl/pending`

List the requests waiting on you.

`GET /api/v1/workflow/hitl/{request_id}`

Read a single request.

`POST /api/v1/workflow/hitl/{request_id}/claim`

Claim a role-assigned request so you can respond to it.

`POST /api/v1/workflow/hitl/{request_id}/respond`

Submit your response and resume the run.

`POST /api/v1/workflow/hitl/{request_id}/cancel`

Cancel a pending request.

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

```http
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.

> [TIP]
> **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](/builder/v2/core-concepts/workflows) — where HITL fits in the run lifecycle.
-   [Agents](/builder/v2/core-concepts/agents) — attaching HITL to an agent node and the `ask_human` capability.
-   [API reference](/builder/v2/api-reference) — the full HITL API.
