# Smithers
> Deterministic, resumable AI workflow orchestration using JSX.
Smithers is a TypeScript framework for building deterministic, resumable AI workflows using JSX. You define your workflow as a tree of React components, and Smithers handles execution ordering, durable state persistence in SQLite, structured output validation, and crash recovery.
- Package: `smithers-orchestrator` on npm
- Runtime: Bun >= 1.3 (uses Bun's native SQLite driver)
- Language: TypeScript with JSX
- AI SDK: Vercel AI SDK (`ai` package) for agent abstraction
## Full Documentation
For the complete documentation with all code examples, API references, and guides, see:
- [llms-full.txt](https://smithers.sh/llms-full.txt): Complete inline documentation (~76k tokens)
## Recommended Models
### Codex (gpt-5.3-codex) -- Primary implementation agent
- **Best for**: Writing code, implementing features, fixing bugs, refactoring
- **Reasoning effort**: `high` (default). Use `xhigh` for especially complex tasks.
- **CLI**: `CodexAgent` -- use if you have a Codex subscription
- **AI SDK**: `openai("gpt-5.3-codex")` via `@ai-sdk/openai` -- use if you prefer API billing
### Claude (claude-opus-4-6) -- Planning, review, and tool calling
- **Best for**: Research, planning, code review, reporting, tool-calling tasks, orchestration logic
- **CLI**: `ClaudeCodeAgent` -- use if you have a Claude Code subscription
- **AI SDK**: `anthropic("claude-opus-4-6")` via `@ai-sdk/anthropic` -- use if you prefer API billing
### Claude Sonnet (claude-sonnet-4-5-20250929) -- Simple tasks
- **Best for**: Simple tool calling, lightweight reviews, report generation, tasks where a cheaper/faster model suffices
- Use Sonnet when the task is straightforward and doesn't need deep reasoning
### When to use which
- **Implementing code** → Codex (strongest at code generation)
- **Reviewing code** → Claude Opus or Codex (run both in parallel for best results)
- **Research & planning** → Claude Opus (strongest at reasoning about architecture)
- **Simple tool calls** → Claude Sonnet (fast, cheap, good enough)
- **Validation (running tests)** → Codex (good at interpreting build output)
### CLI vs AI SDK
Use **CLI agents** (`ClaudeCodeAgent`, `CodexAgent`) when:
- You have a subscription and want to use it
- You want the agent's native tool ecosystem (file editing, shell, etc.)
Use **AI SDK agents** (`ToolLoopAgent` from `ai`) when:
- You want API billing instead of subscription
- You want sandboxed tools from `smithers-orchestrator/tools`
- You need more control over tool definitions
## Quick Start
```bash
bun add smithers-orchestrator ai @ai-sdk/anthropic zod
```
```tsx
import { createSmithers, Task, runWorkflow } from "smithers-orchestrator";
import { ToolLoopAgent as Agent } from "ai";
import { anthropic } from "@ai-sdk/anthropic";
import { z } from "zod";
const { Workflow, smithers } = createSmithers({
analysis: z.object({ summary: z.string(), severity: z.enum(["low", "medium", "high"]) }),
fix: z.object({ patch: z.string(), explanation: z.string() }),
});
const analyst = new Agent({
model: anthropic("claude-sonnet-4-5-20250929"),
instructions: "You are a code analyst. Return structured JSON.",
});
const fixer = new Agent({
model: anthropic("claude-sonnet-4-5-20250929"),
instructions: "You are a senior engineer who writes minimal, correct fixes.",
});
export default smithers((ctx) => (
{`Analyze this bug: ${ctx.input.description}`}
{`Fix this issue: ${ctx.output("analysis", { nodeId: "analyze" }).summary}`}
));
```
```bash
bunx smithers run workflow.tsx --input '{"description": "Auth tokens expire silently"}'
```
## Core Concepts
- **Workflow**: JSX tree defining the execution graph. Re-renders after each task completes.
- **Task**: Single unit of work (AI agent call or static data). Identified by `id` prop.
- **Sequence**: Tasks run top-to-bottom. Default behavior inside ``.
- **Parallel**: Tasks run concurrently with optional `maxConcurrency`.
- **Branch**: Conditional execution based on a boolean (`if`/`then`/`else`).
- **Ralph**: Iterative loop with `until` condition and `maxIterations` safety cap.
- **Context (`ctx`)**: Access `input`, completed `output` rows, `runId`, `iteration`.
- **Resume**: Re-running with same `runId` skips completed tasks automatically.
- **Schema Registry**: Zod schemas passed to `createSmithers()` auto-create SQLite tables.
## Key Exports
```ts
// Core
import { createSmithers, Task, Sequence, Parallel, Branch, Ralph, runWorkflow, renderFrame } from "smithers-orchestrator";
// Tools (sandboxed filesystem + shell)
import { read, write, edit, grep, bash, tools } from "smithers-orchestrator/tools";
// CLI Agents
import { ClaudeCodeAgent, CodexAgent, GeminiAgent } from "smithers-orchestrator/agents/cli";
// HTTP Server
import { startServer } from "smithers-orchestrator/server";
// PI Plugin (HTTP client)
import { runWorkflow, resume, approve, deny, streamEvents, getStatus } from "smithers-orchestrator/pi-plugin";
```
## TSConfig
```json
{
"compilerOptions": {
"jsx": "react-jsx",
"jsxImportSource": "smithers-orchestrator"
}
}
```
## Recommended Project Structure
For non-trivial workflows, we strongly recommend this file structure with **one component per step**, **MDX prompts**, and **Zod schema files**:
```
scripts/my-workflow/
workflow.tsx # Root workflow -- thin, just composition
smithers.ts # createSmithers() + schema registry
agents.ts # Agent definitions (CLI + API SDK)
config.ts # Shared constants (max iterations, etc.)
system-prompt.ts # Build system prompt from MDX + docs
preload.ts # MDX plugin registration
bunfig.toml # preload = ["./preload.ts"]
package.json
tsconfig.json
run.sh # Shell script to launch workflow
components/
index.ts # Re-export all components
Discover.tsx # Component
Discover.schema.ts # Zod schema for output
Discover.mdx # Prompt template (MDX)
Implement.tsx
Implement.schema.ts
Implement.mdx
Validate.tsx
Validate.schema.ts
Validate.mdx
Review.tsx
Review.schema.ts
Review.mdx
ReviewFix.tsx
ReviewFix.schema.ts
ReviewFix.mdx
Report.tsx
Report.schema.ts
Report.mdx
TicketPipeline.tsx # Composed pipeline per ticket
ValidationLoop.tsx # Ralph loop: implement->validate->review->fix
prompts/
system-prompt.mdx # Master system prompt template
*.md # Domain-specific context docs
```
### Why this structure?
- **MDX prompts**: Prompts are `.mdx` files with JSX interpolation (`{props.ticketId}`), keeping prompt engineering separate from orchestration logic
- **Schema files**: Each step has a `.schema.ts` with a Zod schema, ensuring structured output validation and auto-creating SQLite tables
- **One component per step**: Each step (Discover, Implement, Review, etc.) is a React component in its own file, making workflows composable and testable
- **Thin workflow.tsx**: The root file just composes components -- all logic lives in components
### Key files explained
**`smithers.ts`** -- Schema registry and typed exports:
```ts
import { createSmithers } from "smithers";
import { DiscoverOutput } from "./components/Discover.schema";
import { ImplementOutput } from "./components/Implement.schema";
import { ValidateOutput } from "./components/Validate.schema";
import { ReviewOutput } from "./components/Review.schema";
import { ReviewFixOutput } from "./components/ReviewFix.schema";
import { ReportOutput } from "./components/Report.schema";
export const { Workflow, Task, useCtx, smithers, tables } = createSmithers({
discover: DiscoverOutput,
implement: ImplementOutput,
validate: ValidateOutput,
review: ReviewOutput,
reviewFix: ReviewFixOutput,
report: ReportOutput,
}, { dbPath: "./my-workflow.db" });
```
**`agents.ts`** -- Dual CLI/API agent setup:
```ts
import { ToolLoopAgent as Agent, stepCountIs, type ToolSet } from "ai";
import { anthropic } from "@ai-sdk/anthropic";
import { openai } from "@ai-sdk/openai";
import { ClaudeCodeAgent, CodexAgent } from "smithers";
import { tools as smithersTools } from "smithers/tools";
import { SYSTEM_PROMPT } from "./system-prompt";
const tools = smithersTools as ToolSet;
const USE_CLI = process.env.USE_CLI_AGENTS !== "0" && process.env.USE_CLI_AGENTS !== "false";
const UNSAFE = process.env.SMITHERS_UNSAFE === "1";
// --- Codex (implementation agent) ---
const CODEX_MODEL = process.env.CODEX_MODEL ?? "gpt-5.3-codex";
const codexApi = new Agent({
model: openai(CODEX_MODEL),
tools,
instructions: SYSTEM_PROMPT,
stopWhen: stepCountIs(100),
maxOutputTokens: 8192,
});
const codexCli = new CodexAgent({
model: CODEX_MODEL,
systemPrompt: SYSTEM_PROMPT,
yolo: UNSAFE,
config: { model_reasoning_effort: "high" },
timeoutMs: 30 * 60 * 1000,
});
export const codex = USE_CLI ? codexCli : codexApi;
// --- Claude (review/planning agent) ---
const CLAUDE_MODEL = process.env.CLAUDE_MODEL ?? "claude-opus-4-6";
const claudeApi = new Agent({
model: anthropic(CLAUDE_MODEL),
tools,
instructions: SYSTEM_PROMPT,
stopWhen: stepCountIs(100),
maxOutputTokens: 8192,
});
const claudeCli = new ClaudeCodeAgent({
model: CLAUDE_MODEL,
systemPrompt: SYSTEM_PROMPT,
dangerouslySkipPermissions: UNSAFE,
timeoutMs: 30 * 60 * 1000,
});
export const claude = USE_CLI ? claudeCli : claudeApi;
```
**`preload.ts`** + **`bunfig.toml`** -- Enable MDX imports:
```ts
// preload.ts
import { mdxPlugin } from "smithers/mdx-plugin";
mdxPlugin();
```
```toml
# bunfig.toml
preload = ["./preload.ts"]
```
**`system-prompt.ts`** -- Build rich system prompts from MDX with injected docs:
```ts
import { readFileSync } from "node:fs";
import { resolve } from "node:path";
import { renderMdx } from "smithers";
import SystemPromptMdx from "./prompts/system-prompt.mdx";
const ROOT = resolve(new URL("../..", import.meta.url).pathname);
function readDoc(path: string): string {
try { return readFileSync(resolve(ROOT, path), "utf8"); }
catch { return `[Could not read ${path}]`; }
}
const ClaudeMd = () => readDoc("CLAUDE.md");
const Architecture = () => readDoc("docs/architecture.md");
export const SYSTEM_PROMPT = renderMdx(SystemPromptMdx, {
components: { ClaudeMd, Architecture },
});
```
The corresponding `prompts/system-prompt.mdx` uses those components as JSX tags to compose the full system prompt:
```mdx
# My Project
You are building [project description].
## Project Conventions
## Architecture
## JSON Output Requirement
MUST end response with JSON object in code fence. Format specified in task prompt.
```
This pattern lets you:
- Keep domain knowledge in standalone `.md` files (reusable across workflows)
- Compose them into a single system prompt via MDX component injection
- Share the same system prompt across all agents in the workflow
- Add/remove context sections without editing prompt text
For per-step prompts (e.g., `Implement.mdx`, `Review.mdx`), use `{props.*}` interpolation to inject dynamic data from the workflow context:
```mdx
IMPLEMENTATION -- Ticket: {props.ticketId}
{props.ticketDescription}
{props.previousAttempt
? `PREVIOUS ATTEMPT FAILED:\n${props.previousAttempt.failingSummary}\nFix the issues above.`
: ""}
**REQUIRED OUTPUT** -- JSON matching this schema:
{props.schema}
```
The `{props.schema}` variable is auto-injected by Smithers with the Zod schema description for the task's output table, so agents know exactly what JSON structure to produce.
## Common Patterns
### Pattern 1: Dynamic Ticket Discovery
**For large projects (>20 tasks)**, prefer dynamic ticket discovery over hardcoding a task list. An agent explores the codebase, compares current state to specs, and generates tickets at runtime. This lets the project evolve naturally as tickets are completed.
```tsx
// workflow.tsx -- Dynamic discovery
export default smithers((ctx) => {
const discoverOutput = ctx.latest(tables.discover, "discover-codex");
const unfinishedTickets = ctx
.latestArray(discoverOutput?.tickets, Ticket)
.filter((t) => !ctx.latest(tables.report, `${t.id}:report`)) as Ticket[];
return (
} />
{unfinishedTickets.map((ticket) => (
))}
);
});
```
The Discover component runs an agent that analyzes the codebase and generates the next batch of tickets as structured JSON. When all tickets complete, the workflow re-renders, Discover runs again, and finds the next batch. This continues until the agent reports no more work.
**For smaller/well-defined projects (<20 tasks)**, hardcoding tasks is fine:
```tsx
// Hardcoded task list -- good for focused features
const phases = [
{ id: "auth-types", name: "Add auth types" },
{ id: "auth-middleware", name: "Add auth middleware" },
{ id: "auth-routes", name: "Add auth routes" },
{ id: "auth-tests", name: "Add auth tests" },
];
export default smithers((ctx) => (
{phases.map(({ id, name }) => (
{`Implement: ${name}`}
{`Validate: run tests for ${name}`}
))}
));
```
### Pattern 2: Implement-Review Ralph Loop
**Strongly recommended.** Wrap implementation in a Ralph loop with validation and review. This catches issues early and forces agents to fix them before moving on.
```tsx
// ValidationLoop.tsx
import { Ralph, Sequence } from "smithers";
export function ValidationLoop({ ticket }: { ticket: Ticket }) {
const ctx = useCtx();
const ticketId = ticket.id;
const claudeReview = ctx.latest(tables.review, `${ticketId}:review-claude`) as ReviewOutput | undefined;
const codexReview = ctx.latest(tables.review, `${ticketId}:review-codex`) as ReviewOutput | undefined;
const allApproved = !!claudeReview?.approved && !!codexReview?.approved;
return (
);
}
```
The loop runs: implement → validate (run tests) → review (check quality) → fix (address issues). It repeats until both reviewers approve or `maxIterations` is hit.
### Pattern 3: Parallel Multi-Agent Review
Run multiple reviewers in parallel for higher-quality feedback. Use `continueOnFail` so one reviewer timing out doesn't block the other.
```tsx
// Review.tsx
export function Review({ ticket }: { ticket: Ticket }) {
const ctx = useCtx();
const ticketId = ticket.id;
const latestValidate = ctx.latest(tables.validate, `${ticketId}:validate`) as ValidateOutput | undefined;
if (!latestValidate?.allPassed) return null; // Skip review if tests fail
return (
);
}
```
### Pattern 4: Pipeline per Ticket
Compose steps into a per-ticket pipeline, with `skipIf` for completed tickets so resume works correctly.
```tsx
// TicketPipeline.tsx
export function TicketPipeline({ ticket }: { ticket: Ticket }) {
const ctx = useCtx();
const latestReport = ctx.latest(tables.report, `${ticket.id}:report`) as ReportOutput | undefined;
const ticketComplete = latestReport != null;
return (
);
}
```
### Pattern 5: MDX Prompt with Props
Use MDX files for prompts with interpolated props. This keeps prompts readable and separates prompt engineering from orchestration logic.
```
// Implement.mdx
IMPLEMENTATION -- Ticket: {props.ticketId} -- {props.ticketTitle}
TICKET DESCRIPTION:
{props.ticketDescription}
ACCEPTANCE CRITERIA:
- {props.acceptanceCriteria}
{props.previousImplementation ? `\nPREVIOUS ATTEMPT:\n${props.previousImplementation.whatWasDone}\nFix issues from previous attempt.` : ""}
{props.reviewFixes ? `\nREVIEW FIXES NEEDED:\n${props.reviewFixes}` : ""}
**REQUIRED OUTPUT** -- JSON matching this schema:
{props.schema}
```
The corresponding component imports the MDX and passes props:
```tsx
// Implement.tsx
import { Task } from "../smithers";
import { codex } from "../agents";
import ImplementPrompt from "./Implement.mdx";
export function Implement({ ticket }: { ticket: Ticket }) {
const ctx = useCtx();
const ticketId = ticket.id;
const latestValidate = ctx.latest(tables.validate, `${ticketId}:validate`) as ValidateOutput | undefined;
return (
);
}
```
### Pattern 6: Zod Schema per Step
Every step gets a dedicated schema file. Schemas auto-create SQLite tables and validate agent output.
```ts
// Implement.schema.ts
import { z } from "zod";
export const ImplementOutput = z.object({
filesCreated: z.array(z.string()).nullable().describe("Files created"),
filesModified: z.array(z.string()).nullable().describe("Files modified"),
commitMessages: z.array(z.string()).describe("Git commit messages made"),
whatWasDone: z.string().describe("Detailed description of what was implemented"),
testsWritten: z.array(z.string()).describe("Test files written"),
allTestsPassing: z.boolean().describe("Whether all tests pass"),
testOutput: z.string().describe("Output from running tests"),
});
export type ImplementOutput = z.infer;
```
### Pattern 7: Multi-Pass Refinement with Sprint Tracking
For very large projects, wrap the entire workflow in a Ralph loop with a pass tracker. Each pass discovers new work, implements it, and advances a counter.
```tsx
export default smithers((ctx) => {
const passTracker = ctx.latest(tables.output, "sprint-tracker") as { sprintsCompleted?: number } | undefined;
const currentSprint = passTracker?.sprintsCompleted ?? 0;
const projectComplete = /* check completion condition */;
return (
{/* Sprint work here -- discover, implement, test, review */}
{{ sprintsCompleted: currentSprint + 1, summary: `Sprint ${currentSprint + 1} complete.` }}
);
});
```
## Monitoring & Debugging
### SQLite Inspection
All workflow state is persisted in SQLite. Query it directly to monitor progress:
```bash
# See all completed tasks
sqlite3 my-workflow.db "SELECT node_id, status, created_at FROM smithers_attempts ORDER BY created_at DESC"
# Check outputs for a specific step
sqlite3 my-workflow.db "SELECT * FROM implement WHERE node_id LIKE '%:implement' ORDER BY created_at DESC LIMIT 5"
# Count iterations per task (useful for Ralph loops)
sqlite3 my-workflow.db "SELECT node_id, COUNT(*) as iterations FROM smithers_attempts WHERE status='completed' GROUP BY node_id"
# See review approval status
sqlite3 my-workflow.db "SELECT node_id, json_extract(data, '$.approved') as approved, json_extract(data, '$.feedback') as feedback FROM review"
```
### JJ (Jujutsu) VCS Integration
Smithers auto-snapshots the workspace with JJ before each task executes. This enables:
- **Reverting** to any previous task's state: `bunx smithers revert --to `
- **Diffing** between task attempts to see what an agent actually changed
- **Crash recovery** -- if an agent corrupts the workspace, revert and retry
```bash
# See JJ snapshots created by smithers
jj log --no-pager | head -40
# Diff what an agent changed during a specific task
jj diff -r
# Revert workspace to state before a task ran
bunx smithers revert --to
```
### CLI Status Commands
```bash
# Check workflow status
bunx smithers status workflow.tsx
# See execution frames (what the workflow graph looks like at each render)
bunx smithers frames workflow.tsx
# List all runs
bunx smithers list workflow.tsx
# Visualize the execution graph
bunx smithers graph workflow.tsx
```
### NDJSON Logs
Smithers writes NDJSON event logs to `.smithers/logs/`. Each line is a JSON event:
```bash
# Tail live events
tail -f .smithers/logs/*.ndjson | jq .
# Filter to task completions
cat .smithers/logs/*.ndjson | jq 'select(.type == "task:completed")'
# See errors
cat .smithers/logs/*.ndjson | jq 'select(.type == "task:failed")'
```
### Programmatic Monitoring
Use the `onProgress` callback for real-time monitoring:
```ts
await runWorkflow(workflow, {
input: {},
onProgress: (event) => {
if (event.type === "task:completed") {
console.log(`Completed: ${event.nodeId}`);
}
if (event.type === "task:failed") {
console.error(`Failed: ${event.nodeId}`, event.error);
}
},
});
```
## Source Code Reference
Raw source files on GitHub for reading implementation details. Use these when docs aren't enough.
Base URL: `https://github.com/evmts/smithers/blob/main/`
### Core
| File | Description |
|------|-------------|
| [src/index.ts](https://github.com/evmts/smithers/blob/main/src/index.ts) | Main entry point. `createSmithers()`, `smithers()`, `runWorkflow()`, `renderFrame()` |
| [src/types.ts](https://github.com/evmts/smithers/blob/main/src/types.ts) | All core types: `SmithersWorkflow`, `SmithersCtx`, `TaskDescriptor`, `RunOptions`, `RunResult`, `AgentLike`, `GraphSnapshot` |
| [src/components.ts](https://github.com/evmts/smithers/blob/main/src/components.ts) | JSX components: `Workflow`, `Task`, `Sequence`, `Parallel`, `Branch`, `Ralph` |
| [src/context.ts](https://github.com/evmts/smithers/blob/main/src/context.ts) | `SmithersContext` React context and `useCtx()` hook |
| [src/events.ts](https://github.com/evmts/smithers/blob/main/src/events.ts) | Event types and lifecycle event definitions |
| [src/jsx-runtime.ts](https://github.com/evmts/smithers/blob/main/src/jsx-runtime.ts) | Custom JSX runtime for `jsxImportSource: "smithers-orchestrator"` |
### Engine
| File | Description |
|------|-------------|
| [src/engine/index.ts](https://github.com/evmts/smithers/blob/main/src/engine/index.ts) | Core execution engine: render-schedule-execute-persist loop, agent invocation, retry logic |
| [src/engine/scheduler.ts](https://github.com/evmts/smithers/blob/main/src/engine/scheduler.ts) | Task scheduling: determines which tasks are ready, handles Sequence/Parallel/Ralph ordering |
| [src/engine/approvals.ts](https://github.com/evmts/smithers/blob/main/src/engine/approvals.ts) | Human-in-the-loop approval/denial operations |
### DOM / Renderer
| File | Description |
|------|-------------|
| [src/dom/renderer.ts](https://github.com/evmts/smithers/blob/main/src/dom/renderer.ts) | Custom React reconciler: renders JSX workflow tree into `TaskDescriptor[]` and XML snapshots |
| [src/dom/extract.ts](https://github.com/evmts/smithers/blob/main/src/dom/extract.ts) | Walks reconciler host nodes to extract `TaskDescriptor[]` for the scheduler |
### Database
| File | Description |
|------|-------------|
| [src/db/adapter.ts](https://github.com/evmts/smithers/blob/main/src/db/adapter.ts) | Drizzle ORM database adapter wrapping Bun SQLite |
| [src/db/ensure.ts](https://github.com/evmts/smithers/blob/main/src/db/ensure.ts) | Auto-creates internal tables (`smithers_attempts`, `smithers_cache`, etc.) |
| [src/db/snapshot.ts](https://github.com/evmts/smithers/blob/main/src/db/snapshot.ts) | Loads persisted outputs for workflow re-rendering |
| [src/db/output.ts](https://github.com/evmts/smithers/blob/main/src/db/output.ts) | Writes task outputs to schema-driven tables |
| [src/db/internal-schema.ts](https://github.com/evmts/smithers/blob/main/src/db/internal-schema.ts) | Drizzle schema for internal tables (attempts, cache, tool calls) |
| [src/db/input.ts](https://github.com/evmts/smithers/blob/main/src/db/input.ts) | Loads workflow input from database |
| [src/db/schema-signature.ts](https://github.com/evmts/smithers/blob/main/src/db/schema-signature.ts) | Schema hashing for cache invalidation |
### Schema Utilities
| File | Description |
|------|-------------|
| [src/zod-to-table.ts](https://github.com/evmts/smithers/blob/main/src/zod-to-table.ts) | Converts Zod schemas to Drizzle table definitions + raw `CREATE TABLE` SQL |
| [src/zod-to-example.ts](https://github.com/evmts/smithers/blob/main/src/zod-to-example.ts) | Converts Zod schemas to example JSON (injected as `{props.schema}` in prompts) |
### Agents
| File | Description |
|------|-------------|
| [src/agents/cli.ts](https://github.com/evmts/smithers/blob/main/src/agents/cli.ts) | CLI agent wrappers: `ClaudeCodeAgent`, `CodexAgent`, `GeminiAgent` |
### Tools
| File | Description |
|------|-------------|
| [src/tools/index.ts](https://github.com/evmts/smithers/blob/main/src/tools/index.ts) | Sandboxed tools: `read`, `write`, `edit`, `grep`, `bash` |
| [src/tools/context.ts](https://github.com/evmts/smithers/blob/main/src/tools/context.ts) | Tool execution context (rootDir sandboxing, audit logging) |
| [src/tools/utils.ts](https://github.com/evmts/smithers/blob/main/src/tools/utils.ts) | Tool utility functions |
### VCS
| File | Description |
|------|-------------|
| [src/vcs/jj.ts](https://github.com/evmts/smithers/blob/main/src/vcs/jj.ts) | Jujutsu VCS adapter: workspace snapshots, diffs, revert operations |
### MDX
| File | Description |
|------|-------------|
| [src/mdx-plugin.ts](https://github.com/evmts/smithers/blob/main/src/mdx-plugin.ts) | Bun preload plugin for `.mdx` imports |
| [src/mdx-components.ts](https://github.com/evmts/smithers/blob/main/src/mdx-components.ts) | Default MDX components and `renderMdx()` utility |
### Server & PI Plugin
| File | Description |
|------|-------------|
| [src/server/index.ts](https://github.com/evmts/smithers/blob/main/src/server/index.ts) | HTTP server: REST API for runs, SSE event streaming, approval endpoints |
| [src/pi-plugin/index.ts](https://github.com/evmts/smithers/blob/main/src/pi-plugin/index.ts) | Lightweight HTTP client for remote Smithers interaction |
### CLI
| File | Description |
|------|-------------|
| [src/cli/index.ts](https://github.com/evmts/smithers/blob/main/src/cli/index.ts) | CLI binary: `smithers run`, `resume`, `approve`, `deny`, `status`, `frames`, `list`, `graph`, `revert` |
### Revert
| File | Description |
|------|-------------|
| [src/revert.ts](https://github.com/evmts/smithers/blob/main/src/revert.ts) | Workspace revert logic using JJ snapshots |
### Utilities
| File | Description |
|------|-------------|
| [src/utils/errors.ts](https://github.com/evmts/smithers/blob/main/src/utils/errors.ts) | Error types and handling |
| [src/utils/hash.ts](https://github.com/evmts/smithers/blob/main/src/utils/hash.ts) | SHA-256 hashing for content-addressed caching |
| [src/utils/ids.ts](https://github.com/evmts/smithers/blob/main/src/utils/ids.ts) | Run ID and attempt ID generation |
| [src/utils/tree-ids.ts](https://github.com/evmts/smithers/blob/main/src/utils/tree-ids.ts) | Deterministic node ID computation from JSX tree position |
| [src/utils/time.ts](https://github.com/evmts/smithers/blob/main/src/utils/time.ts) | Time utilities |
| [src/utils/xml.ts](https://github.com/evmts/smithers/blob/main/src/utils/xml.ts) | XML serialization for graph snapshots |
### Tests
| File | Description |
|------|-------------|
| [tests/engine.test.tsx](https://github.com/evmts/smithers/blob/main/tests/engine.test.tsx) | Engine tests: Ralph iteration, Sequence/Parallel execution, resume, skipIf, timeouts, approvals |
| [tests/renderer.test.tsx](https://github.com/evmts/smithers/blob/main/tests/renderer.test.tsx) | Renderer tests: reconciler updates, prop changes |
| [tests/docs-examples.test.tsx](https://github.com/evmts/smithers/blob/main/tests/docs-examples.test.tsx) | Documentation examples as runnable tests: Branch, Parallel, `createSmithers()`, context API |
| [tests/cli.test.ts](https://github.com/evmts/smithers/blob/main/tests/cli.test.ts) | CLI command tests |
| [tests/server.test.ts](https://github.com/evmts/smithers/blob/main/tests/server.test.ts) | HTTP server tests |
| [tests/tools.test.ts](https://github.com/evmts/smithers/blob/main/tests/tools.test.ts) | Sandboxed tools tests: read, grep, bash, symlink protection |
| [tests/pi-plugin.test.ts](https://github.com/evmts/smithers/blob/main/tests/pi-plugin.test.ts) | PI plugin client tests |
| [tests/jj-workspace.test.ts](https://github.com/evmts/smithers/blob/main/tests/jj-workspace.test.ts) | JJ VCS workspace integration tests |
| [tests/revert.test.ts](https://github.com/evmts/smithers/blob/main/tests/revert.test.ts) | Workflow revert tests |
| [tests/helpers.ts](https://github.com/evmts/smithers/blob/main/tests/helpers.ts) | Test utilities: `createTestDb()`, `sleep()` |
| [tests/schema.ts](https://github.com/evmts/smithers/blob/main/tests/schema.ts) | Shared test schema and DDL |
| [tests/fixtures/test-workflow.tsx](https://github.com/evmts/smithers/blob/main/tests/fixtures/test-workflow.tsx) | Test workflow fixture |
| [tests/fixtures/approval-workflow.tsx](https://github.com/evmts/smithers/blob/main/tests/fixtures/approval-workflow.tsx) | Approval workflow test fixture |
### Examples
| File | Description |
|------|-------------|
| [examples/simple-workflow.tsx](https://github.com/evmts/smithers/blob/main/examples/simple-workflow.tsx) | Minimal two-step workflow: research → write article (uses old Drizzle API) |
| [examples/code-review-loop.tsx](https://github.com/evmts/smithers/blob/main/examples/code-review-loop.tsx) | Review-fix Ralph loop with sandboxed tools (uses old Drizzle API) |
### Config
| File | Description |
|------|-------------|
| [package.json](https://github.com/evmts/smithers/blob/main/package.json) | Package config, exports map, dependencies |
| [tsconfig.json](https://github.com/evmts/smithers/blob/main/tsconfig.json) | TypeScript configuration |
## Docs
### Getting Started
- [Introduction](https://smithers.sh/introduction): Overview, architecture, and how the render-execute-persist loop works.
- [Installation](https://smithers.sh/installation): Install Smithers, configure TypeScript, verify setup.
- [Quickstart](https://smithers.sh/quickstart): Build a two-step research workflow in 5 minutes.
### Core Concepts
- [Execution Model](https://smithers.sh/concepts/execution-model): The four-phase render-schedule-execute-persist loop, node states, deterministic ordering.
- [Data Model](https://smithers.sh/concepts/data-model): Schema-driven vs manual API, SQLite tables, output validation, internal tables.
- [Context API](https://smithers.sh/concepts/context): `SmithersCtx` interface -- `output()`, `outputMaybe()`, `latest()`, `latestArray()`, `iterationCount()`.
- [Approvals](https://smithers.sh/concepts/approvals): Human-in-the-loop gates with `needsApproval`, CLI approve/deny, events.
- [Caching](https://smithers.sh/concepts/caching): Content-addressed cache with SHA-256 keys, automatic invalidation on schema/prompt/model changes.
- [Renderer Internals](https://smithers.sh/concepts/renderer-internals): Custom React reconciler pipeline from JSX to TaskDescriptor[] and XML snapshots.
### Components
- [Workflow](https://smithers.sh/components/workflow): Root container with implicit sequencing and optional caching.
- [Task](https://smithers.sh/components/task): Agent mode (prompt -> AI -> structured output) or static mode (direct data).
- [Sequence](https://smithers.sh/components/sequence): Sequential execution of children.
- [Parallel](https://smithers.sh/components/parallel): Concurrent execution with optional `maxConcurrency`.
- [Branch](https://smithers.sh/components/branch): Conditional `if`/`then`/`else` routing.
- [Ralph](https://smithers.sh/components/ralph): Iterative loop with `until`, `maxIterations`, `onMaxReached`.
### Guides
- [Tutorial: Build a Workflow](https://smithers.sh/guides/tutorial-workflow): End-to-end three-step code review workflow.
- [Production Project Structure](https://smithers.sh/guides/project-structure): Recommended file layout with MDX prompts, component-per-step, and Zod schemas.
- [Model Selection](https://smithers.sh/guides/model-selection): Which models to use (Codex, Claude Opus, Sonnet), CLI vs API agents, dual-agent setup.
- [Implement-Review Loop](https://smithers.sh/guides/review-loop): The recommended implement-validate-review-fix Ralph loop pattern.
- [Dynamic Tickets](https://smithers.sh/guides/dynamic-tickets): Agent-driven ticket discovery for large projects vs hardcoded task lists.
- [MDX Prompts](https://smithers.sh/guides/mdx-prompts): Using MDX for per-step prompts and system prompt composition from docs.
- [Structured Output](https://smithers.sh/guides/structured-output): Schema validation flow, auto-retry, outputSchema prop.
- [Error Handling](https://smithers.sh/guides/error-handling): Retries, timeouts, continueOnFail, skipIf, Branch fallbacks.
- [Workflow Patterns](https://smithers.sh/guides/patterns): Project structure, schema organization, MDX prompts, naming conventions.
- [Resumability](https://smithers.sh/guides/resumability): Crash recovery, stale attempt cleanup, deterministic node IDs.
- [Debugging](https://smithers.sh/guides/debugging): CLI inspection, NDJSON logs, SQLite queries.
- [Monitoring & Logs](https://smithers.sh/guides/monitoring-logs): onProgress callback, NDJSON files, SSE streaming, event types.
- [Best Practices](https://smithers.sh/guides/best-practices): Big coherent tasks, measurable stop conditions, structured reports.
- [VCS Integration](https://smithers.sh/guides/vcs): JJ (Jujutsu) snapshots for filesystem revert support.
### Runtime API
- [runWorkflow](https://smithers.sh/runtime/run-workflow): Execute a workflow programmatically. RunOptions and RunResult types.
- [renderFrame](https://smithers.sh/runtime/render-frame): Preview the execution graph without running tasks.
- [Events](https://smithers.sh/runtime/events): All 20+ lifecycle event types with full type definitions.
- [Revert](https://smithers.sh/runtime/revert): Restore workspace to a previous attempt's state via JJ.
### CLI
- [CLI Reference](https://smithers.sh/cli/overview): run, resume, approve, deny, status, frames, list, graph, revert commands.
### Integrations
- [Built-in Tools](https://smithers.sh/integrations/tools): Sandboxed read, write, edit, grep, bash tools with security policies.
- [CLI Agents](https://smithers.sh/integrations/cli-agents): ClaudeCodeAgent, CodexAgent, GeminiAgent wrappers.
- [HTTP Server](https://smithers.sh/integrations/server): REST API for run management, SSE event streaming, approval endpoints.
- [PI Plugin Client](https://smithers.sh/integrations/pi-plugin): Lightweight HTTP client for remote Smithers interaction.
### Examples
- [Hello World](https://smithers.sh/examples/hello-world): Minimal single-task workflow.
- [Dynamic Plan](https://smithers.sh/examples/dynamic-plan): Branch between simple and complex execution paths.
- [Ralph Loop](https://smithers.sh/examples/ralph-loop): Write-then-review iterative refinement loop.
- [Multi-Agent Review](https://smithers.sh/examples/multi-agent-review): Parallel reviewers with aggregation.
- [Approval Gate](https://smithers.sh/examples/approval-gate): Human-in-the-loop publish workflow.
- [Tools Agent](https://smithers.sh/examples/tools-agent): Codebase search with sandboxed tools.
### Reference
- [Type Reference](https://smithers.sh/reference/types): All exported types including SmithersWorkflow, SmithersCtx, RunOptions, RunResult, TaskDescriptor, SmithersEvent, and component props.