Skip to content

Human Steps

Implemented

Some pipelines need a person in the loop. A human should sign off before a risky deploy; a human should pick which of three draft emails to send; a human should answer a freeform question the model isn't qualified to answer on its own.

JigSpec models these as two first-class actions:

  • human/approve — pause and ask the human to approve or reject before continuing.
  • human/input — pause and collect a value from the human (freeform or multi-choice).

Both actions make the pipeline stop cleanly, collect the human's response, write a structured output file to the step's workspace, and then hand control back to downstream steps as if nothing unusual happened.

Where they run

These actions work in two environments:

  • CLIjigspec run reads from stdin. The pipeline prompts on the terminal. Requires an interactive TTY — if stdin is piped or the process is headless, the step fails with a clear error rather than silently auto-answering.
  • App / viewerjigspec app exposes an approval panel in the UI. The pipeline pauses; the human clicks a button in the browser; execution resumes.

The spec is identical between the two. Where the response is collected (terminal vs. browser) is a property of how the run was launched, not of the step itself.

human/approve

Gate downstream work behind explicit human sign-off.

yaml
- name: confirm_deploy
  action: human/approve
  message: "About to deploy v1.2.3 to production. Proceed?"
  data:
    version: "1.2.3"
    target: "prod-cluster-east"
    breaking_changes: 0
  timeout: 300   # auto-reject after 300 seconds (optional)

Fields:

FieldRequiredDescription
messageyesPrompt shown to the human.
datanoKey/value map displayed alongside the prompt for context.
timeoutnoSeconds before the step auto-rejects. If omitted, the step waits indefinitely.

Output — written to response.json in the step's workspace:

json
{ "approved": true, "feedback": "Looks good, ship it" }

Output references from downstream steps:

  • {{ confirm_deploy.approved }} — boolean (convenient for when: { file, value } gates)
  • {{ confirm_deploy.feedback }} — freeform follow-up text the user optionally provides

Downstream steps can gate on the approval:

yaml
- name: deploy
  action: code
  run: |
    // actually ship it
  when:
    file: "{{ confirm_deploy['response.json'] }}"
    value: '{"approved":true,"feedback":""}'

(For cleaner gating, prefer reading a specific field — confirm_deploy also writes a plain approved.txt containing "true" or "false" that's easier to gate on.)

human/input

Collect a value from the human. Use this when you need text or a choice, not just a yes/no.

yaml
- name: pick_tone
  action: human/input
  message: "What tone should the email use?"
  choices: [formal, friendly, urgent]
  timeout: 120

Omit choices for freeform text:

yaml
- name: name_the_release
  action: human/input
  message: "Give this release a codename:"

Set multi: true to allow multiple selections:

yaml
- name: pick_recipients
  action: human/input
  message: "Who should this alert go to?"
  choices: [ops, oncall, platform, security]
  multi: true

Fields:

FieldRequiredDescription
messageyesPrompt shown to the human.
choicesnoList of allowed values. When present, the response is validated to be one of them (or a subset, with multi: true).
multinoWhen true, the human may select more than one choice from choices. Ignored if choices is absent.
timeoutnoSeconds before the step fails with a timeout error.

Output: value.txt in the step's workspace. With multi: true, the value is a JSON array of selected strings; otherwise it's the raw string.

Reference the value downstream:

yaml
- name: write_email
  action: ai
  prompt: |
    Write a {{ pick_tone.text }}-toned email about the incident.

Agent-initiated approval (advanced)

There is a separate mechanism — the requestApproval tool — that lets an ai agent step pause itself mid-execution to ask a human for approval. That is documented alongside the agent tools in AI Action — Agent mode. human/approve and human/input are the top-level step-scoped version; requestApproval is the inline, model-driven version. Use whichever fits the shape of your pipeline.

TTY required for CLI mode

If you run a pipeline containing human steps with jigspec run and stdin is not a TTY (for example, piping in JSON or running in CI), the step will fail with a clear "requires an interactive terminal" error. This is intentional — better to fail loudly than to let a headless run silently skip a human gate. For automated runs, either remove the human step or drive the pipeline through jigspec app with a browser responder.