Skip to main content

Documentation Index

Fetch the complete documentation index at: https://smithers.sh/llms.txt

Use this file to discover all available pages before exploring further.

import { runWorkflow } from "smithers-orchestrator";
import { Effect } from "effect";

const result = await Effect.runPromise(runWorkflow(workflow, {
  input: { task: "fix bug" },
}));

result.runId;     // string
result.status;    // "finished" | "failed" | "cancelled" | "continued" | "waiting-approval" | "waiting-event" | "waiting-timer"
result.output;    // populated only if your schema has a key literally named `output`
result.error;     // serialized SmithersError on failure
Signature:
function runWorkflow<Schema>(
  workflow: SmithersWorkflow<Schema>,
  opts: RunOptions,                 // see Types
): Effect.Effect<RunResult, SmithersError>;
Both RunOptions and RunResult are defined in Types.

Resume

Pass the original runId plus resume: true. State loads from SQLite, completed tasks are skipped, in-progress attempts older than 15 minutes are abandoned and retried.
await Effect.runPromise(runWorkflow(workflow, { input: {}, runId: "my-run-123", resume: true }));
The original input row is loaded from the DB; pass {} for input. The workflow file hash and VCS revision must match the original run.

Cancel via AbortSignal

const controller = new AbortController();
setTimeout(() => controller.abort(), 5 * 60 * 1000);

const result = await Effect.runPromise(runWorkflow(workflow, { input: {...}, signal: controller.signal }));
// result.status === "cancelled"
All in-flight attempts are marked cancelled and NodeCancelled events are emitted.

Hijack handoff

If a CLI hijack happens mid-run (bunx smithers-orchestrator hijack <id>), the run ends "cancelled" and the latest attempt metadata stores hijackHandoff. On resume: true, Smithers waits for a safe handoff point and continues with the persisted CLI session id (Claude/Codex/Gemini/Pi/Kimi/Forge/Amp) or the persisted message history (SDK agents).

result.output

Populated only when the schema passed to createSmithers() has a key literally named output. Other schema rows live in their own SQLite tables — query them directly:
import { Database } from "bun:sqlite";
const db = new Database("smithers.db", { readonly: true });
const rows = db.query("SELECT * FROM page WHERE run_id = ? ORDER BY iteration DESC").all(result.runId);

Notes

  • On macOS, runWorkflow acquires a caffeinate lock to prevent idle sleep; released on completion. No-op elsewhere.
  • Set SMITHERS_DEBUG=1 to print engine errors to stderr.
  • For lifecycle events, pass onProgress (see Events).