<Branch> + <Approval> into a single component. When when is true, the workflow pauses for human approval. When false, a static task auto-approves immediately so downstream nodes can proceed without delay.
Import
Props
| Prop | Type | Default | Description |
|---|---|---|---|
id | string | (required) | Unique node id within the workflow. |
output | z.ZodObject | Table | string | (required) | Where to persist the approval decision. |
request | { title: string; summary?: string; metadata?: Record<string, unknown> } | (required) | Human-facing approval request. |
when | boolean | (required) | When true, approval is required. When false, auto-approves. |
onDeny | "fail" | "continue" | "skip" | "fail" | Behavior after denial. |
skipIf | boolean | false | Skip this node entirely. |
timeoutMs | number | undefined | Max wait in ms. Node fails on timeout. |
retries | number | 0 | Retry attempts before failure. |
retryPolicy | RetryPolicy | undefined | { backoff?: "fixed" | "linear" | "exponential", initialDelayMs?: number } |
continueOnFail | boolean | false | Workflow continues even if this node fails. |
Basic usage
Gate production deploys on a risk score. Low-risk changes sail through; high-risk changes require a human sign-off.Auto-approve on dry run
dryRun is true, when is false and the gate emits { approved: true, note: "auto-approved" } without pausing.
With timeout and retry
How it works
<ApprovalGate> renders a <Branch>:
whenistrue— mounts an<Approval>node that pauses for human review.whenisfalse— mounts a static<Task>that resolves immediately with{ approved: true, note: "auto-approved", decidedBy: null, decidedAt: null }.
output, so downstream nodes can branch on decision.approved without caring which path was taken.
Notes
- The auto-approve path produces a valid
ApprovalDecisionshape, so downstream logic remains uniform. - Auto-approve timing lives in Smithers’ internal approval/event records, not in the durable task output.
onDenyonly applies to the human-approval path. The auto-approve path always succeeds.- Combine with
skipIfto disable the gate entirely during development.