Step 1: Define the Workflow
Create a file calledworkflow.tsx:
- Zod schemas define the shape of each task’s output. Smithers validates agent responses against these schemas and auto-retries on validation failures.
createSmithers()takes a record of named schemas and returns aWorkflowcomponent, asmithers()builder function, and a configured database. You never touch SQLite or Drizzle directly.smithers()wraps your JSX build function into aSmithersWorkflowobject that the engine can execute. Thectxparameter provides access to the workflow input and completed task outputs.ctx.inputis the input object you pass at run time. Here it expects{ topic: string }.ctx.output("research", { nodeId: "research" })retrieves the persisted output of theresearchtask. This call throws if the task has not completed yet, which is safe because<Workflow>sequences its children by default —reportonly runs afterresearchfinishes.
Step 2: Create the Runner
Create a file calledmain.ts:
onProgress callback receives typed events as each task starts, finishes, fails, or retries. This is useful for logging, progress bars, or streaming updates to a UI.
Step 3: Run It
Make sure your API key is set:main.ts needed):
smithers.db) is created in your project directory. It contains the full execution history: inputs, outputs, attempts, events, and render frames.
What Happened
When you calledrunWorkflow, Smithers executed the following loop:
-
Render — The JSX tree is rendered using a custom React reconciler. Smithers identifies two tasks:
research(ordinal 0) andreport(ordinal 1). Since they are direct children of<Workflow>, they form an implicit sequence. -
Schedule — The engine walks the plan tree and determines that
researchis runnable (no dependencies) andreportis blocked (it depends onresearchcompleting because it readsctx.output("research", ...)). -
Execute
research— The researcher agent is called with the prompt. Its response is parsed as JSON, validated againstresearchSchema, and written to theresearchtable in SQLite. -
Re-render — The tree re-renders. This time
ctx.output("research", { nodeId: "research" })returns the persisted row, so thereporttask’s prompt is fully resolved. -
Execute
report— The writer agent is called. Its output is validated againstreportSchemaand persisted. -
Re-render — Both tasks are now finished. No runnable tasks remain. The engine returns
{ status: "finished" }.
research already has a valid output row, skip it, and continue from report.
Key Concepts
| Concept | Description |
|---|---|
| Workflow | A JSX tree that defines the execution graph. Re-renders after each task completes. |
| Task | A single unit of work (AI agent call or static data). Identified by its id prop. |
| Output | A Zod-validated JSON object persisted to SQLite. Keyed by (runId, nodeId, iteration). |
Context (ctx) | Provides access to input, completed output rows, runId, and iteration. Passed to the smithers() build function. |
| Sequence | Default within <Workflow>. Tasks run top-to-bottom. Use <Sequence> explicitly for nested groups. |
| Parallel | Tasks inside <Parallel> run concurrently up to maxConcurrency. |
| Ralph | A loop component. Re-runs its children with an incrementing iteration until until is true or maxIterations is reached. |
| Resume | Re-running a workflow with the same runId. Completed tasks are skipped automatically. |
| Schema Registry | When you pass Zod schemas to createSmithers(), the framework auto-creates SQLite tables and resolves string output keys (e.g., output="research") to their backing tables. |
Next Steps
- Execution Model — Deep dive into the render-schedule-execute loop.
- Task Component — All
<Task>props:retries,needsApproval,skipIf,timeoutMs,continueOnFail. - Ralph Component — Iteration loops with
until,maxIterations, andonMaxReached. - Context — Full
SmithersCtxAPI:output,outputMaybe,latest,latestArray,iterationCount. - Tools — Built-in sandboxed tools (
read,edit,bash,grep,write) for code-editing agents. - Examples — More workflow patterns: dynamic plans, approval gates, multi-agent review, and Ralph loops.