human node

Pause the workflow for a manual decision.

Pauses the run and waits for an external party to choose one of the configured transitions. In the web UI the transitions render as buttons; via MCP and the REST API they appear as a pendingStep that an operator (or another tool) resolves explicitly.

Purpose#

Use human whenever the next step requires judgement, sign-off, or context that isn't available to a script or a model: release approvals, sensitive deletes, manual data review, "did the email go out?" gates. The run state is durable: paused workflows survive process restarts and can be resumed later from any client.

YAML schema#

states:
  approve:
    type: human # discriminator
    label: Approve refund over $500 # required, shown as the pause's heading
    prompt: | # optional, free text shown to the human
      Review the refund request and approve or reject it.
    on: # required — at least one transition (schema-enforced)
      approve: process
      reject: cancel

Configuration#

Field Type Required Default Meaning
type 'human' yes Discriminator.
label string yes Heading shown in the pause UI / pendingStep payload.
prompt string no Optional context shown to the human. Surfaced as output.prompt.
on transition map yes At least one key (schema-enforced); each becomes an option.

There is no validator: routing is decided by whichever transition the human picks. There is no machine-side timeout; a paused run sits in the paused state indefinitely until something resumes it.

Outputs#

human records the prompt that was shown but does not generate any machine-derived output:

Key Type Notes
prompt string | null The configured prompt, or null if none.

Downstream nodes typically don't read from a human node directly: the information they need came from earlier nodes. The transition itself is the signal.

Transitions#

The transition keys are entirely user-defined. Whatever appears in on becomes a button in the web UI and a valid resume token everywhere else. Common patterns:

on:
  approve: process
  reject: cancel
on:
  approve: process
  hold: notify
  deny: done

Resuming a paused run#

Any of the following resume a paused human step with a chosen transition:

Client How
Web UI Click the transition button on the run's pause card.
CLI roscoe resume <runId> <transition>
REST POST /api/runs/:id/resume with { "transition": "approve" }
MCP The resume_run tool.

Claude Code, or any autonomous agent, should not call resume_run on its own initiative. The entire point of a human step is that a person made the choice, so wait for explicit user input before picking a transition.

Worked example#

name: refund-approval
version: 1
description: Demonstrates a human approval pause/resume between two script steps.
initial: prepare
states:
  prepare:
    type: script
    label: Draft the refund decision
    script: |
      console.log('Refund request is 3 days past the 30-day window, amount $640');
      export default true;
    validator:
      kind: boolean
    on:
      'true': review
      'false': done

  review:
    type: human
    label: Approve refund over $500
    prompt: Review the refund request and approve or reject it.
    on:
      approve: process
      reject: done

  process:
    type: script
    label: Process refund
    script: |
      console.log('Refund processed');
      export default true;
    validator:
      kind: boolean
    on:
      'true': done
      'false': done

  done:
    type: end
    label: Done
    outcome: success

Common pitfalls#

  • Empty on map. Schema validation rejects a human node with no transitions. There would be no way to ever resume it. At minimum, give it one option.
  • Transition keys that look like booleans without quoting. YAML parses unquoted yes / no / true / false as booleans. Quote them ('yes': ...) or pick non-boolean names (approve / reject).
  • MCP agents resuming themselves. An autonomous tool that calls resume_run defeats the purpose of the pause. Make a human step mean "stop and wait for the user" in every entrypoint, including MCP.
  • Long-lived prompts that lose context. A human step might be resumed hours later. Put any context the operator needs into the prompt field, since they may not have the upstream node output handy.
  • Confusing human with ai_judge. If you want a model to make the call, use ai_judge. human is for actual people.

View this page as Markdown

Predictable workflows from unpredictable AI