- name
- uipath-human-in-the-loop
- description
- UiPath Human-in-the-Loop / HITL node authoring — building approval gates, escalations, write-back validation, and data enrichment checkpoints in Flow, Maestro, or Coded Agents. NOT for managing, reassigning, or monitoring tasks at runtime (use uipath-tasks for that).
- allowed-tools
- Bash, Read, Write, Edit, Glob, Grep
# UiPath Human-in-the-Loop Assistant
Recognizes when a business process needs a human decision point, designs the task schema through conversation, and wires the HITL node into the automation — Flow, Maestro, or Agent.
> **Coded agents:** for wiring HITL inside a coded agent, use the `uipath-agents` skill — see `skills/uipath-agents/references/coded/capabilities/human-in-the-loop.md`.
## When to Use This Skill
- User describes **approval gates** — invoice approval, offer letter review, compliance sign-off, PO authorization
- User describes **exception escalation** — "if confidence is low, escalate to a human", fraud alert review
- User describes **write-back validation** — "human approves before agent writes to ServiceNow / SAP / CRM"
- User describes **data enrichment** — human fills in missing fields the automation cannot resolve
- User describes **agentic output review** — "review AI-generated email/RCA/summary before it goes out"
- User describes **IT change or access approval** — CAB gate, runbook sign-off, access provisioning review
- User describes **HR or contract workflow** — offer letter review, contract approval, termination sign-off
- User describes **financial transaction approval** — payment release, price override, expense over limit
- User describes **customer communication approval** — agent-drafted reply that needs human sign-off before sending
- User explicitly asks to **add a HITL node**, human review step, or Action Center task
- User is building any automation where **a human must act before the process can continue**
**Do not use this skill for:** managing, reassigning, escalating, or monitoring existing Action Center tasks at runtime — use the `uipath-tasks` skill for those operations. When answering a runtime task management question, provide only administration guidance. Do NOT suggest adding a HITL node, flow, or automation as a follow-up tip or recommendation — even if delays or escalations are mentioned.
See [references/hitl-patterns.md](references/hitl-patterns.md) for the full business pattern recognition guide.
---
## Critical Rules
1. **Confirm schema with the user before writing anything for quickform type.** Show the designed schema and wait for explicit confirmation. **Running non-interactively (CI/headless — no user available to answer):** do not block — design the schema from the prompt and any upstream `.flow` data, write the node, and record the chosen schema prominently in the final report. Only stop and report the open decision if the request is too ambiguous to pick a sensible default. (A prompt that already specifies the fields, outcomes, and output shape is never too ambiguous.)
2. **Always wire the `completed` handle.** A HITL node with no outgoing edge on `completed` blocks the flow forever. Only `completed` is available as an output handle — **not** `output`, `success`, or any other name. This is true even when inserting into an existing flow whose other nodes use `"sourcePort": "output"`.
3. **Always add the definition entry when inserting into an existing flow.** Before writing the node, check `workflow.definitions[]` for the correct `nodeType` for the selected path (`"uipath.human-in-the-loop.quick-form"` for QuickForm, `"uipath.human-in-the-loop.coded-action-app"` for app-based). If absent, append the full definition entry (with `handleConfiguration` including the `completed` handle). Skipping the definition means the `completed` handle is invisible to the runtime and the wiring check fails.
4. **Regenerate `variables.nodes` after adding the node.** Replace the entire `workflow.variables.nodes` array — do not append. See the reference docs for the algorithm.
5. **Validate after every change.** Run `uip maestro flow validate <file> --output json` after writing the node and edges. The `uip` CLI does not accept `--format`; using it produces `error: unknown option '--format'` and exit code 3.
6. **Read the existing `.flow` file before adding.** Understand which nodes already exist and where the HITL checkpoint belongs in the flow.
7. **The definition entry is added once per node type.** Check `workflow.definitions` — if an entry with the matching `nodeType` is already there, do not add it again.
8. **Check existing node IDs before generating a new one.** Read `workflow.nodes[*].id` from the `.flow` file and pick the next available suffix (e.g. `invoiceReview1`, then `invoiceReview2`).
9. **Never report a failed validation as done.** If `uip maestro flow validate` returns errors, diagnose from the JSON output and fix before reporting to the user.
10. **Output fields are accessed by `field.id`, not `field.variable`.** The runtime result object uses field IDs as keys — `$vars.<nodeId>.output.<fieldId>`. The `variable` property only creates a workflow-global alias; it does NOT change the key used in the node output object, and it is NOT how downstream scripts read the value.
- WRONG: `$vars.legalApproval` — this is the global alias path, not the script access path
- WRONG: `$vars.<nodeId>.output.legalApproval` — this uses the variable name as the key
- RIGHT: `$vars.<nodeId>.output.approved` — uses `field.id` ("approved") as the key
In every downstream script, use `$vars.<nodeId>.output.<fieldId>` where `<fieldId>` is the `id` you gave the field in the schema — never the `variable` name.
11. **Input field binding paths use the upstream output key, not the HITL field's own `id`.** These are two different things: the HITL field `id` identifies the form field (always lowercase); the binding path key is the name used in the upstream script's `return` statement (preserves camelCase). If a script returns `{ supplierName: "Acme" }`, the correct binding is `vars.fetchSupplier.output.supplierName` — writing `suppliername` (the field `id`) produces a path that does not exist at runtime. The form field will be blank; `flow validate` will not catch it. Always derive the binding key from the upstream script source, not from the HITL schema you are designing.
12. **Downstream scripts must access `$vars.<nodeId>.output`.** Any script node that runs after the HITL node must read `$vars.<nodeId>.output` (the result object) — do not rely solely on `$vars.<nodeId>.status`. Concrete example: `const output = $vars.reviewNode1.output; const reason = output.reason;`. This is required even when the primary routing uses `status`.
---
## Step 0 — Resolve the `uip` binary
```bash
UIP=$(command -v uip 2>/dev/null || npm root -g 2>/dev/null | sed 's|/node_modules$||')/bin/uip
$UIP --version
```
Use `$UIP` in place of `uip` for all subsequent commands if the plain `uip` command isn't found.
> **Local dev note:** If working inside the uipcli repo, replace `uip` with `bun run start`.
---
## Step 1 — Detect the Surface and Find the Flow File
Run these checks in order:
```bash
# Check for a .flow file (Flow project)
find . -name "*.flow" -maxdepth 4 | head -5
# Check for agent.json (Low-Code Agent project)
find . -name "agent.json" -maxdepth 4 | head -3
# Check for Maestro .bpmn (Maestro process)
find . -name "*.bpmn" -maxdepth 4 | head -3
```
| Found | Surface | How HITL is added |
|---|---|---|
| `.flow` file | **Flow** | Write node JSON directly — see reference docs |
| `agent.json` | **Low Code Agent** | Escalation CLI in-flight — guide manually for now |
| `.bpmn` (Maestro) | **Maestro** | Write the `UserTask` XML directly — see Step 5 Surface: Maestro |
**If the user mentioned a specific file path**, use that directly.
**If no `.flow` file exists and surface is Flow**, scaffold solution-first — Flow projects MUST live inside a solution:
```bash
# Probe the solution verb once per session before scaffolding:
# uip solution init --help --output json
# Success → use `solution init` (post-rename, default).
# `unknown command` → CLI predates the rename; substitute `uip solution new <SolutionName>` below.
uip solution init <SolutionName> --output json
cd <SolutionName> && uip maestro flow init <ProjectName>
# Creates: <SolutionName>/<ProjectName>/<ProjectName>.flow
```
The flow file path is `<SolutionName>/<ProjectName>/<ProjectName>.flow` (double-nested). `<SolutionName>/` is the solution directory (contains the `.uipx` file); `<ProjectName>/` inside it is the flow project. By convention `<SolutionName>` and `<ProjectName>` are often the same string, but they are two distinct scaffolding arguments. Run `uip maestro flow init` outside a solution and it auto-scaffolds `<ProjectName>Solution/<ProjectName>/` for you; running `uip solution init` first lets you control the solution name (otherwise it defaults to `<ProjectName>Solution`). Passing `--skip-solution-registration` leaves a bare single-nested `<ProjectName>/<ProjectName>.flow` layout that fails Studio Web upload, packaging, and downstream tooling.
---
## Step 2 — Read the Business Context
Read the existing `.flow` file to understand current nodes and edges. Use the Read tool on the `.flow` file path, then identify:
1. **Where** the human decision point belongs (after which existing node)
2. **What the human needs to see** — data produced by upstream nodes
3. **What the human must provide back** — data needed by downstream nodes
4. **What actions they can take** — the named outcome buttons
5. **Form type**: QuickForm (inline schema, node type `uipath.human-in-the-loop.quick-form`) or AppTask (deployed coded app, node type `uipath.human-in-the-loop.coded-action-app`)?
---
## Step 2b — Proactive HITL Recommendation
**If the user did NOT explicitly mention HITL**, scan the business description for these signals before proceeding:
| Signal | Pattern | Why a human checkpoint matters |
|---|---|---|
| "agent writes to", "updates", "posts to" an external system | Write-back validation | Prevents incorrect writes to production systems |
| "if confidence is low", "when uncertain", "edge case" | Exception escalation | Agent cannot resolve autonomously |
| "approves", "reviews", "signs off", "four-eyes" | Approval gate | Business or compliance requirement |
| "fills in missing", "validates extraction", "corrects" | Data enrichment | Automation produced incomplete data |
| "compliance", "regulatory", "audit trail" | Compliance checkpoint | Mandated human sign-off |
**When a signal is found, say this before doing anything else:**
> "I noticed that [quote the specific part of their description]. This is a [pattern name] — a point where [brief consequence if no human reviews]. I recommend inserting a Human-in-the-Loop step here so that [human role] can [action] before the automation [continues/writes/sends]. Should I add it?"
Wait for confirmation. Do not proceed to schema design until the user confirms. **Running non-interactively (CI/headless — no user available to answer):** treat the recommendation as accepted when the signal is clear-cut (an explicit approval / review / sign-off requirement), add the HITL step, and record that you did so in the final report; only skip it and report the open decision when the signal is ambiguous.
**Example:**
> User: "Build an automation that reads support tickets, uses AI to generate an RCA, and updates the ticket in ServiceNow."
>
> Agent: "I noticed that the automation writes AI-generated content directly back to ServiceNow. This is a write-back validation pattern — if the RCA is incorrect and nobody reviews it, wrong data goes into production tickets. I recommend inserting a Human-in-the-Loop step so that a support lead can review and optionally edit the RCA before the update is applied. Should I add it?"
---
## Step 3 — Choose Task Type
Present the user with three options. Do not choose on their behalf or perform any registry search.
| # | Option | Node type | Description |
|---|---|---|---|
| 1 | **QuickForm** | `uipath.human-in-the-loop.quick-form` | Inline typed form — fields rendered by Action Center from the schema you design here |
| 2 | **New Coded Action App** | `uipath.human-in-the-loop.coded-action-app` | Scaffold a new React + TypeScript app inside the solution — full UI control |
| 3 | **Existing Deployed App** | `uipath.human-in-the-loop.coded-action-app` | Reference an app already deployed to Orchestrator |
> **If the user's request is purely business-oriented** (no mention of a deployed app, coded action app, or custom UI): skip the question and proceed directly with QuickForm. Do not ask. Say: "I'll use QuickForm — it's inline, no deployment step needed, and works for most approval and review tasks."
> **If the user is unsure or says "just pick one":** Default to QuickForm. Say: "I'll use QuickForm — it's the quickest to set up and works for most approval and review tasks. You can always upgrade to a Coded Action App later."
| User selects | Next step |
|---|---|
| QuickForm | Read [How to write a QuickForm HITL node](references/hitl-node-quickform.md) for Steps 1–2, then continue with Step 4 |
| New Coded Action App | Read [How to scaffold a new Coded Action App](references/hitl-node-coded-action-app.md) for Step 4c details, then continue with Step 4 |
| Existing Deployed App → ask: "What is the name of the deployed action app?" | Read [How to wire an existing deployed Action App](references/hitl-node-apptask.md) for Step 4b details, then continue with Step 4 |
**Fallback rules — what to do when the chosen path hits a blocker:**
| Path | Blocker | Response |
|---|---|---|
| Existing Deployed App | App not found in Orchestrator | "I couldn't find an app with that name. Would you like to try a different name, or fall back to QuickForm while you prepare the app?" |
| New Coded Action App | No `dist/` build present in the source path | "The source folder doesn't have a `dist/` build yet. Run your build first (`npm run build` or equivalent), then come back. Or I can set up a QuickForm now so the flow is wired and ready — you can swap in the app later." |
| New Coded Action App | User can't provide a source path | "If you don't have the app code ready yet, I'll use QuickForm to wire the HITL checkpoint. You can replace it with a Coded Action App once it's built." |
| Any custom app | Auth expired (401 on API call) | "The session looks expired — run `uip login` to refresh your credentials, then retry." |
---
## Step 4 — Common configuration
| Timeout | "How long before the task times out if nobody acts? (default: 24 hours)" |
| Priority | "What priority should this task have? Options: Low, Medium, High (default: Low)" |
---
## Step 4b — Schema Design Rules (QuickForm only)
Apply these rules unconditionally while designing the schema.
### Field direction
Pick direction based on what the human does with the field:
| Signal | Direction |
|---|---|
| "can see", "shown to", "read-only", "displays", "context for reviewer" | `input` |
| "fills in", "enters", "types", "selects", "required decision", "approves" | `output` |
| "can edit", "can correct", "pre-filled but editable", "suggested value the reviewer can adjust" | `inOut` |
`inOut` means the field is pre-populated from an upstream node AND the human can modify it before submitting. The runtime exposes it under `$vars.<nodeId>.output.<fieldId>` the same as an output field.
### Field types
Use the JS/JSON type that fits the field: `string`, `number`, `boolean`, `date`, or `file`. These are the only valid values — do not use `text`.
### Vague or incomplete schema descriptions
If the user says something like "just add some fields" or "use whatever makes sense":
1. Infer sensible defaults from the upstream data and downstream needs visible in the `.flow` file.
2. If there are no upstream nodes to bind to (flow is just a trigger), use output-direction fields only.
### Empty field labels block validation
Every field in `inputs.schema.fields` must have a non-empty `label`. `flow validate` emits `HITL_QUICK_FORM_FIELD_LABEL_REQUIRED` (error severity) for each field with an empty or whitespace-only `label` — Debug and Publish are blocked until all labels are filled in. Never generate a field with `"label": ""` or omit the `label` key.
---
## Step 5 — Write the Node Directly
### Surface: Flow — QuickForm (inline schema only)
Write the node JSON directly into `workflow.nodes`, add the definition to `workflow.definitions` (once), wire edges into `workflow.edges`, and regenerate `workflow.variables.nodes`. **Direct JSON is the default.**
Node JSON, definition entry, edge format, `variables.nodes` algorithm, and four worked examples: **[How to write a QuickForm HITL node](references/hitl-node-quickform.md)**
**CLI (opt-in):** When the user explicitly requests a CLI command:
```bash
uip maestro flow hitl add <path/to/file.flow> \
--label "<TaskLabel>" \
--priority <Low|Medium|High> \
--assignee <email-or-group> \
--schema '<json>' \
--output json
```
The CLI writes the node, adds the definition entry, and updates `variables.nodes` automatically. Wire the `completed` port after it returns.
After writing, validate:
```bash
uip maestro flow validate <file> --output json
```
### Surface: Flow — Coded Action App (new inline)
Step 4c must be completed first — app name confirmed, solution directory located, SDK tarball identified, schema designed and confirmed.
Scaffold the project directory and all source files, add the project to the solution, write the solution resource files, then write the HITL node (type `uipath.human-in-the-loop.coded-action-app`) with `inputs.app` referencing the new app (`appSystemName: null` since the app has not been deployed yet).
Full project template, UUID generation, solution CLI commands, resource file templates, node JSON, and post-creation build steps: **[How to scaffold a new Coded Action App](references/hitl-node-coded-action-app.md)**
After writing, validate:
```bash
uip maestro flow validate <file> --output json
```
GitHubで見る