Skip to main content

workflows/approval.tsx

Ghost doc — This is a real script found at workflows/approval.tsx in the Smithers repository. It demonstrates the needsApproval prop for human-in-the-loop workflows.

Source

// workflows/approval.tsx
import { createSmithers, Sequence, Task, Workflow } from "smithers-orchestrator";
import { z } from "zod";

const { smithers, outputs } = createSmithers({
  output: z.object({
    message: z.string(),
    length: z.number(),
  }),
});

export default smithers((ctx) => (
  <Workflow name="approval">
    <Sequence>
      <Task id="approve" output={outputs.output} needsApproval>
        {{
          message: `Approved: ${ctx.input.name}`,
          length: String(ctx.input.name).length,
        }}
      </Task>
      <Task id="final" output={outputs.output}>
        {{
          message: `Done: ${ctx.input.name}`,
          length: String(ctx.input.name).length,
        }}
      </Task>
    </Sequence>
  </Workflow>
));

Running

smithers run workflows/approval.tsx --input '{"name": "Deploy v2"}'
The workflow pauses at the approval gate:
[approval] Starting run mno345
[approve] Waiting for approval...
[approval] Paused — run `smithers approve` or `smithers deny` to continue.
After approving:
smithers approve workflows/approval.tsx --run-id mno345 --node-id approve
[approve] Approved. Running...
[approve] Done -> { message: "Approved: Deploy v2", length: 9 }
[final] Done -> { message: "Done: Deploy v2", length: 9 }
[approval] Completed

What This Demonstrates

  • needsApproval — The first task pauses execution and waits for human approval before the workflow continues. This is the core human-in-the-loop primitive.
  • Sequence — Ensures the final task only runs after approve completes (and is approved).
  • Resumable approval — The workflow state is persisted to SQLite. After approval, smithers approve resumes from exactly where it left off.