Basic Usage
Set theneedsApproval prop on a <Task> to gate it:
waiting-approval state instead of executing immediately.
Approval Flow
The lifecycle of an approval-gated task:waiting-approval, the entire run transitions to waiting-approval status and returns. The run can be resumed after an approval decision is made.
Events
The approval system emits these events, all available through theonProgress callback:
| Event | When |
|---|---|
ApprovalRequested | A task enters waiting-approval for the first time. Contains runId, nodeId, iteration, and timestampMs. |
NodeWaitingApproval | Emitted alongside ApprovalRequested to update the node state. |
ApprovalGranted | An approval decision of “approved” is recorded. |
ApprovalDenied | An approval decision of “denied” is recorded. |
CLI Commands
Approve or deny tasks using the Smithers CLI:What Happens on Approve
When a task is approved:- The
_smithers_approvalsrow is updated withstatus: "approved",decidedAtMs,note, anddecidedBy. - An
ApprovalGrantedevent is persisted. - The node state is reset to
pending. - On the next
runWorkflowcall with--resume, the task proceeds through normal execution.
What Happens on Deny
When a task is denied:- The
_smithers_approvalsrow is updated withstatus: "denied",decidedAtMs,note, anddecidedBy. - An
ApprovalDeniedevent is persisted. - The node state is set to
failed. - On the next
runWorkflowcall with--resume:- If
continueOnFailis set on the task, it is treated asskippedand the workflow continues. - If
continueOnFailis not set (the default), the failed task blocks the workflow and the run finishes with statusfailed.
- If
Database Storage
Approval state is stored in the_smithers_approvals table:
| Column | Type | Description |
|---|---|---|
run_id | TEXT | The workflow run ID. |
node_id | TEXT | The task node ID. |
iteration | INTEGER | The Ralph loop iteration (0 for non-loop tasks). |
status | TEXT | One of: requested, approved, denied. |
requested_at_ms | INTEGER | Timestamp when the approval was first requested. |
decided_at_ms | INTEGER | Timestamp when the approval or denial was recorded. |
note | TEXT | Optional free-text note from the reviewer. |
decided_by | TEXT | Optional identifier of who made the decision. |
(run_id, node_id, iteration), so each task in each iteration can have exactly one approval record.
Approval with Ralph Loops
When a task inside a<Ralph> loop has needsApproval, the approval is scoped to the current iteration. Each iteration requires its own approval:
Patterns
Approval Gate Before Destructive Action
Optional Approval with Continue-on-Fail
skipped rather than failing the entire run.