Key Features
Deterministic execution. The workflow tree is rendered, tasks are identified, executed, and their outputs are persisted. Then the tree re-renders with updated context, revealing newly unblocked tasks. The same inputs always produce the same execution graph. Durable SQLite state. Every task output is written to SQLite (via Drizzle ORM) keyed by(runId, nodeId, iteration). There is no in-memory state to lose. If the process crashes, resume exactly where you left off.
Resumable runs. Call runWorkflow with resume: true and the same runId. Smithers skips completed tasks and picks up from the last checkpoint.
Human-in-the-loop approvals. Mark any task with needsApproval. The workflow pauses with status "waiting-approval" until a human approves or denies the node via the CLI or REST API.
Parallel execution. Wrap tasks in <Parallel> to run them concurrently, with optional maxConcurrency limits per group and globally.
Loops with Ralph. The <Ralph> component re-executes its children until a condition is met. Each iteration is tracked separately in the database. Set maxIterations and onMaxReached to control termination.
Automatic retries. Set retries={N} on any <Task>. Failed attempts are recorded and the task re-runs up to N additional times.
Tool sandbox. Built-in tools (read, edit, bash, grep, write) are sandboxed to the workflow root directory. Network access and output size are configurable.
Event streaming. Subscribe to fine-grained lifecycle events (NodeStarted, NodeFinished, NodeFailed, ApprovalRequested, ToolCallStarted, and more) via the onProgress callback.
Schema validation. Every task output is validated against its Zod schema. If the agent returns invalid JSON, Smithers automatically retries with the validation errors appended to the prompt so the agent can self-correct.
REST API and CLI. Run, resume, approve, deny, list, and inspect workflows from the command line (bunx smithers) or via the built-in HTTP server (smithers-orchestrator/server).
Architecture
| Layer | What it does |
|---|---|
| JSX Components | <Workflow>, <Task>, <Sequence>, <Parallel>, <Branch>, <Ralph> define the execution graph declaratively. Standard React composition and conditionals work. |
| React Renderer | A custom React reconciler converts the JSX tree into an internal XML representation and extracts an ordered list of TaskDescriptor objects. |
| Engine | The core loop: render the tree, compute task states, schedule runnable tasks respecting dependencies and concurrency limits, execute them, persist results, and re-render. Manages Ralph iteration, approval gates, retries, and cancellation. |
| Tools | Sandboxed filesystem and shell tools (read, edit, bash, grep, write) provided to AI agents. Configurable timeouts, output limits, and network policy. |
| Database | SQLite via Drizzle ORM. Stores workflow runs, render frames, task attempts, outputs, approvals, Ralph state, events, and cache entries. Schema-driven mode auto-creates tables from Zod schemas. |
| Events | A typed event bus that persists every lifecycle event to the database and optionally streams to log files and the onProgress callback. |
How It Works
- Define — You declare Zod schemas for each task output.
createSmithersauto-creates a SQLite database and Drizzle tables. - Render — Smithers renders your JSX tree using a custom React reconciler, producing an ordered list of tasks with their dependencies.
- Schedule — The engine walks the plan tree (depth-first, left-to-right within sequences; all children within parallels) and determines which tasks are runnable.
- Execute — Runnable tasks are dispatched concurrently up to
maxConcurrency. Each task calls its agent, validates the output against the Zod schema, and writes the result to SQLite. - Re-render — The tree re-renders with updated context (completed outputs now available via
ctx.output()). Newly unblocked tasks become runnable. - Repeat — The loop continues until no runnable tasks remain. The final status is
"finished","failed","waiting-approval", or"cancelled".
Requirements
- Bun >= 1.3 (Smithers uses Bun’s native SQLite driver and runtime APIs)
- TypeScript >= 5
- An AI provider API key (e.g.,
ANTHROPIC_API_KEYfor Claude models)
Next Steps
- Installation — Install Smithers and configure your project.
- Quickstart — Build and run your first workflow in under 5 minutes.
- Execution Model — Understand the render-execute-persist loop in depth.
- Components — Reference for all JSX components.