Skip to main content

Welcome to Smithers

JSX workflow engine for coding agents—phases, parallelism, and persistent state for long-running repo automation. Run CI recovery, PR finalization, stacked merges, release smoketests, and review processing as resumable workflows—not fragile scripts.
import { SmithersProvider, Phase, Claude, Parallel, createSmithersDB } from 'smithers-orchestrator'

function FeatureWorkflow({ featureSpec }) {
  const db = createSmithersDB({ path: '.smithers/workflow' })
  const executionId = db.execution.start('feature-workflow', 'feature.tsx')

  return (
    <SmithersProvider db={db} executionId={executionId} maxIterations={20}>
      <Phase name="Plan">
        <Claude model="sonnet">
          Analyze the codebase and create an implementation plan for: {featureSpec}
        </Claude>
      </Phase>

      <Phase name="Implement">
        <Parallel>
          <Claude model="sonnet">Implement the backend changes from the plan</Claude>
          <Claude model="sonnet">Implement the frontend changes from the plan</Claude>
        </Parallel>
      </Phase>

      <Phase name="Verify">
        <Claude
          model="sonnet"
          onFinished={(result) => {
            if (result.output.includes('All tests pass')) {
              db.state.set('status', 'complete')
            }
          }}
        >
          Run the test suite. If any tests fail, fix them and re-run.
        </Claude>
      </Phase>
    </SmithersProvider>
  )
}

Why Smithers?

The Problem

Simple Ralph loops work great for basic iteration. But as workflows grow complex:
  • Multi-phase orchestration becomes hard to manage
  • Parallel agents need coordination
  • Plans live in prompts, not reviewable code
  • Manual orchestration doesn’t scale

The Solution

  • Agent-native syntax - Easy for Claude Code to generate, easy for humans to review
  • Sophisticated Ralph loops - Multi-phase, parallel agents, conditional branches
  • Composable components - Build complex workflows from simple pieces
  • One syntax for humans and agents - You can read it, Claude can generate it, Git can version it

Key Features

Sophisticated Ralph Loops

Smithers lets you build complex Ralph loops with structure:
<SmithersProvider db={db} executionId={executionId} maxIterations={50}>
  <Phase name="Implement">
    <Parallel>
      <Claude model="sonnet">Fix auth module</Claude>
      <Claude model="sonnet">Fix database module</Claude>
    </Parallel>
  </Phase>

  <Phase name="Verify">
    <Claude
      model="sonnet"
      onFinished={(result) => {
        if (result.output.includes("All tests pass")) {
          db.state.set("complete", "true");
        }
      }}
    >
      Run tests. If any fail, go back to Implement phase.
    </Claude>
  </Phase>
</SmithersProvider>
What Smithers adds:
  • Multi-phase workflows with conditional transitions
  • Parallel agent execution with coordination
  • Composable, reusable components
  • Optional persistence for long-running workflows

Claude Component

The core agent component that executes Claude with full tool access:
<Claude
  model="sonnet"           // opus | sonnet | haiku
  maxTurns={10}            // Limit agentic loops
  permissionMode="acceptEdits"  // Auto-accept file edits
  onFinished={(result) => handleResult(result)}
>
  Your prompt here
</Claude>

Structured Output with Zod

Get typed, validated responses with automatic retry:
const UserSchema = z.object({
  name: z.string(),
  email: z.string().email(),
})

<Claude schema={UserSchema} schemaRetries={2}>
  Extract user info from: John Doe ([email protected])
</Claude>
// result.structured: { name: string, email: string }

Database Persistence (Flight Recorder)

Every run persists in SQLite - your workflow’s audit trail:
// Set state (survives restarts)
db.state.set("phase", "review");

// Resume incomplete executions
const incomplete = db.execution.findIncomplete();
if (incomplete) {
  executionId = incomplete.id; // Pick up where you left off
}

// Query history - see how state evolved
const history = db.state.getHistory("phase");

MCP Tool Integration

Give Claude access to external tools via Model Context Protocol:
<Claude model="sonnet" maxTurns={5}>
  <Sqlite path="./analytics.db">
    The database contains user_events and sessions tables.
  </Sqlite>
  What are the top 10 most common user actions this week?
</Claude>

Component Naming

ComponentPurpose
<SmithersProvider>Root orchestration context (required)
<Subagent>Named grouping boundary for organizing agent tasks
<Smithers>Nested orchestration - spawns planner + executor
See component docs for details. <Smithers> is the only component that spawns a separate planning model.

How It Works

┌──────────┐    ┌─────────┐    ┌──────────────────┐
│  Render  │───▶│ Execute │───▶│ Update State     │
│   JSX    │    │ Claude  │    │ (onFinished)     │
└──────────┘    └─────────┘    └──────────────────┘
     ▲                                   │
     │                                   │
     └───────────────────────────────────┘
              (re-render on state change)
  1. Render: Your JSX components render
  2. Execute: <Claude> nodes execute via Claude Code CLI
  3. Update: onFinished callbacks update state (persisted to SQLite)
  4. Re-render: State changes trigger reactive updates
  5. Loop: Repeat until no pending agents remain

Installation

bun add smithers-orchestrator

FAQ

Is this actually React? Do I need to run a UI?

No UI. React is a component model + markup-like syntax. People already use it to render to non-DOM targets (CLI, PDFs, native). Smithers renders to execution, not DOM.

Why not YAML/JSON for workflows?

Because you want:
  • Composition and reuse
  • Version control diffs that make sense
  • Something your coding agent can generate AND you can review like normal code

How does this relate to Ralphing?

Ralphing is the outer loop (iterate until verification passes). Smithers gives it structure, persistence, and inspectability.

Do I have to use Bun?

Yes. Smithers uses Bun-specific features (bun:sqlite, Bun.spawn). Node.js support is not currently available.

What do I need for Claude to work?

  1. Claude Code CLI installed globally
  2. Active Claude subscription (Smithers uses Claude Code’s subscription, no separate API key)
  3. claude command available in PATH

Is Ralph deprecated?

The <Ralph> component is deprecated. Use <SmithersProvider> instead - it includes the Ralph loop internally. Pass maxIterations, onIteration, and onComplete props to SmithersProvider.

How do I resume a crashed run?

const incomplete = await db.execution.findIncomplete();
if (incomplete) {
  executionId = incomplete.id; // Resume from here
} else {
  executionId = await db.execution.start("My Workflow", "workflow.tsx");
}
State in SQLite survives restarts. State in useState does not.

What’s the difference between Task component and db.tasks?

  • <Task> is a presentational component (renders a checkbox-like display)
  • db.tasks is the orchestration API for tracking async work
Use db.tasks.start/complete to coordinate async work with the Ralph loop.

Next Steps