Durable Ralphing
Ralphing = continuous agent iteration with verification gates. Run → verify → feedback → run again until done. Durable Ralphing = Smithers’ implementation that makes Ralph loops resumable, inspectable, and controllable.The Execution Model
Smithers uses a reactive render loop powered by React state:- Render: Your JSX components render using React’s state management
- Execute:
<Claude>nodes execute via the Claude Code CLI - Update:
onFinishedcallbacks update React state - Re-render: State changes trigger reactive updates
- Loop: Process repeats until no pending agents remain
Why Smithers for Ralphing
Traditional Ralph loops work great for simple iteration. Smithers lets you build sophisticated Ralph loops while staying reliable:| Simple Ralph Loop | Smithers Ralph Loop |
|---|---|
| Single agent iterating | Multi-phase workflows with parallel agents |
| Linear control flow | Conditional branches, phases, steps |
| Ad-hoc structure | Composable React components |
| Plans in prompts | Plans as reviewable, versionable code |
| Manual orchestration | Declarative - Claude can generate it |
Controlling the Ralph Loop
You can control the Ralph loop using thestopped prop. This is the idiomatic way to stop iteration:
Implicit Stopping
Ralph also stops implicitly when nothing renders for an iteration. If no components mount and register tasks, the loop completes after 500ms. However, using thestopped prop is more explicit and recommended.
Reactive Updates
The power of the Ralph Loop comes from React reactivity:setPhase("implement") is called:
- The database state updates
useQueryValuedetects the change and triggers a re-render- Only the affected branch re-renders
- The new
<Claude>component mounts and executes
Fire-and-Forget Pattern
Components useuseMount to execute when they mount:
- Components execute when they mount
- Results trigger callbacks that update state
- State updates cause re-renders
- New components mount and execute
React Workflow Rules
Smithers uses React as a workflow DSL. Understanding these rules prevents common mistakes.What persists vs what doesn’t
Dos and Don’ts
✅ DO: Store state in SQLite
✅ DO: Store state in SQLite
❌ DON'T: Use useState for workflow state
❌ DON'T: Use useState for workflow state
✅ DO: Register async work with db.tasks
✅ DO: Register async work with db.tasks
❌ DON'T: Run untracked async work
❌ DON'T: Run untracked async work
✅ DO: Use onFinished callbacks to drive state
✅ DO: Use onFinished callbacks to drive state
❌ DON'T: Expect re-renders without state changes
❌ DON'T: Expect re-renders without state changes
What triggers re-renders
- SQLite state changes via
useQueryValueoruseQuery - Task completion detected by orchestration loop
- Phase/Step advancement managed by PhaseRegistryProvider
- Stop conditions met (token limit, pattern match, timeout)
Common anti-patterns
| Anti-Pattern | Problem | Fix |
|---|---|---|
useState for phase | Lost on restart | Use db.state + useQueryValue |
| Untracked promises | Orchestrator advances early | Use db.tasks.start/complete |
No onFinished callback | Workflow stalls | Always update state in onFinished |
Infinite maxIterations | Runaway loops | Set reasonable limits (10-100) |
Orchestration Context
SmithersProvider exposes orchestration context.useRalph is deprecated; use db.tasks for task coordination:
- Active tasks (db.tasks)
- Completed tasks
- Iteration count
- Stop/timeout state
Best Practices for Durable Ralphing
Always set maxIterations
Always set maxIterations
Without a limit, a bug in your state logic could cause infinite loops:
Use SQLite state for durability
Use SQLite state for durability
State in SQLite survives restarts. State in memory doesn’t:
Handle iteration limits gracefully
Handle iteration limits gracefully
Know when you’ve hit the limit:
Add verification gates
Add verification gates
Explicit verification makes loops trustworthy:
SmithersProvider: The Root Ralph Loop
<SmithersProvider> is a special Ralph Wiggum Loop that serves as the root orchestration wrapper. Unlike <Ralph> which is used for specific workflows within your component tree, <SmithersProvider> wraps your entire orchestration and manages the global Ralph loop.
Default Behavior:
By default, <SmithersProvider> runs the Ralph loop for up to 100 iterations. This is sufficient for most workflows.
Infinite Loops:
For long-running orchestrations that need to continue indefinitely (like CI/CD monitors, autonomous agents, or server processes), you can configure it to run forever: