Human Approval (HITL)¶
The Human Approval node is a control flow node (not a tool) that pauses workflow execution and waits for a human to approve or reject an action before the workflow continues. It implements the Human-in-the-Loop (HITL) pattern, which is essential for gating dangerous or irreversible operations behind manual review.
Quick Reference¶
| Property | Value |
|---|---|
| Node name | control/human-approval |
| Version | 0.1.0 |
| Category | control |
| Library | Built-in (uses FlowForge engine events and checkpointing) |
| Tags | control-flow, hitl, human-in-the-loop, approval, safety |
How It Works¶
The Human Approval node follows a three-phase lifecycle:
-
Emit: The node emits a
human-approval.requestedevent containing the action description, details payload, urgency level, and timeout. External systems (Slack bots, dashboards, email integrations) listen for this event and present the approval request to a human reviewer. -
Checkpoint: The node calls
ctx.checkpoint()to persist the workflow state. This makes the workflow crash-safe -- if the process restarts while waiting for approval, execution resumes from the checkpoint. -
Wait: The node calls
ctx.wait('human-approval.response', ...)and blocks until a matching response event arrives or the timeout expires.
Workflow --> [human-approval] --emit--> External System
| |
checkpoint Human reviews
| |
wait <--- response event ---+
|
approved? --> continue / abort
Input Schema¶
| Parameter | Type | Required | Description |
|---|---|---|---|
action |
string | Yes | Description of the action that needs approval |
details |
unknown | No | Detailed payload for the reviewer to inspect |
urgency |
enum | No | low, normal, high, critical (default: normal) |
timeout |
integer | No | Override timeout in milliseconds |
Output Schema¶
| Field | Type | Description |
|---|---|---|
approved |
boolean | Whether the action was approved |
approvedBy |
string | Identifier of who approved/rejected (e.g. user ID, "system:auto-approve") |
reason |
string | Optional reason provided by the reviewer |
respondedAt |
string | ISO 8601 timestamp of the response |
timedOut |
boolean | true if the approval timed out (treated as rejection) |
originalAction |
string | The original action description |
details |
unknown | The original details payload |
Configuration Reference¶
| Property | Type | Default | Description |
|---|---|---|---|
defaultTimeout |
integer | 3600000 (1 hour) |
Default approval timeout in milliseconds. |
autoApprove |
boolean | false |
If true, skip the approval flow and auto-approve immediately. For development and testing. |
autoReject |
boolean | false |
If true, skip the approval flow and auto-reject immediately. For CI and headless environments. |
Urgency Levels¶
| Level | Intended Use |
|---|---|
low |
Informational approval requests that can wait indefinitely |
normal |
Standard operations requiring human sign-off |
high |
Time-sensitive operations that should be reviewed promptly |
critical |
Operations that require immediate attention -- external systems should escalate (e.g. page on-call) |
The urgency level is included in the emitted event and can be used by external systems to determine notification priority (e.g. Slack DM vs. channel post vs. PagerDuty alert).
Emitted Event¶
The human-approval.requested event contains:
| Field | Type | Description |
|---|---|---|
runId |
string | The current workflow run ID |
workflowId |
string | The workflow definition ID |
action |
string | Action description |
details |
unknown | Action details |
urgency |
string | Urgency level |
requestedAt |
string | ISO 8601 timestamp |
timeoutMs |
number | Timeout in milliseconds |
Expected Response Event¶
The node waits for a human-approval.response event matching { runId }:
| Field | Type | Required | Description |
|---|---|---|---|
approved |
boolean | Yes | Whether the request is approved |
approvedBy |
string | No | Who approved or rejected |
reason |
string | No | Explanation |
Integration with External Systems¶
Slack Bot¶
Listen for human-approval.requested events and post an interactive message with Approve/Reject buttons. When a user clicks a button, emit a human-approval.response event back to the engine.
Dashboard¶
The FlowForge dashboard can display pending approval requests with the action description, details, and urgency. Reviewers can approve or reject directly from the UI.
Email¶
Send an email with the action description and one-click approve/reject links. The links hit an API endpoint that emits the response event.
Timeout behavior¶
If no response is received within the timeout period, the node treats the request as rejected with timedOut: true. The workflow can then branch on this outcome.
Safety¶
- Timeout as rejection: Unanswered requests are always treated as rejection, never approval. This is a safe default.
- Checkpoint persistence: The workflow state is checkpointed before waiting, so a process crash does not lose the approval request.
- Auto-modes for non-interactive environments:
autoApproveandautoRejectprevent the node from blocking indefinitely in environments where no human is available.
Warning
Never use autoApprove: true in production. It exists solely for development and testing. In production, always require genuine human review.
Usage Example: Gating a Dangerous Operation¶
import { humanApprovalNode } from '@flowforgejs/nodes';
import { gitNode } from '@flowforgejs/nodes';
const workflow = {
nodes: [
{
id: 'request-approval',
node: humanApprovalNode,
config: {
defaultTimeout: 1_800_000, // 30 minutes
},
input: {
action: 'Push release v3.0.0 to production',
details: {
commits: 47,
filesChanged: 132,
targetBranch: 'main',
targetRemote: 'origin',
},
urgency: 'high',
},
},
{
id: 'push-if-approved',
node: gitNode,
// Only runs if approval.approved === true
config: {
allowedDirectories: ['/workspace'],
allowPush: true,
},
input: {
action: 'push',
repoPath: '/workspace/my-app',
remote: 'origin',
branch: 'main',
},
},
],
};
Usage Example: CI Mode (Auto-Reject)¶
const workflow = {
nodes: [
{
id: 'safety-gate',
node: humanApprovalNode,
config: {
autoReject: true, // In CI, always reject operations requiring approval
},
input: {
action: 'Delete all staging data',
urgency: 'critical',
},
},
],
};
// Output: { approved: false, approvedBy: "system:auto-reject", timedOut: false }
Tip
Combine Human Approval with the Shell or Git tools to create workflows where dangerous operations (deployments, data migrations, destructive commands) always require human sign-off before execution.