---
title: Core Type Reference
description: Reference for the core exported Smithers runtime, component, server, and error types.
---

The types on this page are the core JSX/runtime types most Smithers users work with directly. They are exported from `smithers-orchestrator` unless noted otherwise.

Additional public type families are also exported for adjacent surfaces:

| Family | Exports |
|---|---|
| Workflow builder | `CreateSmithersApi` |
| Serve app | `ServeOptions` |
| Observability | `ResolvedSmithersObservabilityOptions`, `SmithersLogFormat`, `SmithersObservabilityOptions`, `SmithersObservabilityService` |
| Agents | `AnthropicAgentOptions`, `OpenAIAgentOptions`, `PiAgentOptions`, `PiExtensionUiRequest`, `PiExtensionUiResponse` |
| Scorers | `ScoreResult`, `ScorerInput`, `ScorerFn`, `Scorer`, `SamplingConfig`, `ScorerBinding`, `ScorersMap`, `ScoreRow`, `AggregateScore`, `ScorerContext`, `CreateScorerConfig`, `LlmJudgeConfig`, `AggregateOptions` from `smithers-orchestrator/scorers` |
| Renderer / builder internals | `HostContainer`, `SmithersSqliteOptions` |
| VCS helpers | `RunJjOptions`, `RunJjResult`, `JjRevertResult`, `WorkspaceAddOptions`, `WorkspaceResult`, `WorkspaceInfo` |

## Workflow Types

### SmithersWorkflow\<Schema\>

```ts
type SmithersWorkflow<Schema> = {
  db: unknown;
  build: (ctx: SmithersCtx<Schema>) => React.ReactElement;
  opts: SmithersWorkflowOptions;
  schemaRegistry?: Map<string, SchemaRegistryEntry>;
};
```

| Field | Type | Description |
|---|---|---|
| `db` | `unknown` | Drizzle ORM database instance |
| `build` | `(ctx: SmithersCtx<Schema>) => ReactElement` | Renders the workflow JSX tree |
| `opts` | `SmithersWorkflowOptions` | Workflow-level options |
| `schemaRegistry` | `Map<string, SchemaRegistryEntry>` | Output table names to schema entries |

---

### SmithersWorkflowOptions

```ts
type SmithersWorkflowOptions = {
  cache?: boolean;
};
```

| Field | Type | Default | Description |
|---|---|---|---|
| `cache` | `boolean` | `undefined` | Enable task output caching across runs |

---

### SchemaRegistryEntry

```ts
type SchemaRegistryEntry = {
  table: any;
  zodSchema: import("zod").ZodObject<any>;
};
```

| Field | Type | Description |
|---|---|---|
| `table` | `any` | Drizzle ORM table definition |
| `zodSchema` | `ZodObject<any>` | Zod schema for output validation |

---

## Context Types

### SmithersCtx\<Schema\>

```ts
interface SmithersCtx<Schema> {
  runId: string;
  iteration: number;
  iterations?: Record<string, number>;
  input: Schema extends { input: infer T } ? T : any;
  auth: RunAuthContext | null;
  outputs: OutputAccessor<Schema>;

  output<T extends keyof Schema>(
    table: Schema[T],
    key: OutputKey,
  ): InferRow<Schema[T]>;

  outputMaybe<T extends keyof Schema>(
    table: Schema[T],
    key: OutputKey,
  ): InferRow<Schema[T]> | undefined;

  latest(table: any, nodeId: string): any;

  latestArray(value: unknown, schema: import("zod").ZodType): any[];

  iterationCount(table: any, nodeId: string): number;
}
```

| Field / Method | Type | Description |
|---|---|---|
| `runId` | `string` | Current run ID |
| `iteration` | `number` | Current Loop iteration (0 outside loops) |
| `iterations` | `Record<string, number>` | Loop ID to current iteration count |
| `input` | Inferred from Schema | Typed input data |
| `auth` | `RunAuthContext \| null` | Authentication context passed via `RunOptions.auth`. `null` when no auth context is configured. |
| `outputs` | `OutputAccessor<Schema>` | Accessor for all output rows |
| `output(table, key)` | `InferRow<T>` | Get output row. Throws if missing. The `table` parameter accepts a Zod schema from `outputs`, a Drizzle table, or a string schema key. |
| `outputMaybe(table, key)` | `InferRow<T> \| undefined` | Get output row or `undefined`. Same table resolution as `output()`. |
| `latest(table, nodeId)` | `any` | Latest output row (highest iteration). Same table resolution as `output()`. |
| `latestArray(value, schema)` | `any[]` | JSON-parse `value` if it is a string, coerce to array, then validate each element against `schema` (Zod). Invalid items are silently dropped. |
| `iterationCount(table, nodeId)` | `number` | Distinct iteration count for a node |

---

### OutputKey

```ts
type OutputKey = {
  nodeId: string;
  iteration?: number;
};
```

| Field | Type | Default | Description |
|---|---|---|---|
| `nodeId` | `string` | -- | Task node ID |
| `iteration` | `number` | `0` | Loop iteration |

---

### OutputAccessor\<Schema\>

Callable object that retrieves output rows. Can be called as a function or accessed as a property.

```ts
type OutputAccessor<Schema> = ((table: any) => any[]) & Record<string, any[]>;
```

---

### InferRow\<TTable\>

Extracts the select row type from a Drizzle table.

```ts
type InferRow<TTable> = TTable extends { $inferSelect: infer R } ? R : never;
```

---

## Run Types

### RunOptions

```ts
type RunOptions = {
  runId?: string;
  parentRunId?: string;
  input: Record<string, unknown>;
  maxConcurrency?: number;
  onProgress?: (e: SmithersEvent) => void;
  signal?: AbortSignal;
  resume?: boolean;
  force?: boolean;
  workflowPath?: string;
  rootDir?: string;
  logDir?: string | null;
  allowNetwork?: boolean;
  maxOutputBytes?: number;
  toolTimeoutMs?: number;
  hot?: boolean | HotReloadOptions;
  auth?: RunAuthContext;
  cliAgentToolsDefault?: "all" | "explicit-only";
};
```

| Field | Type | Default | Description |
|---|---|---|---|
| `runId` | `string` | Auto-generated | Custom run identifier. Falls back to `randomUUID()` when omitted. |
| `parentRunId` | `string` | `undefined` | Parent run ID for child workflow / subflow tracking. |
| `input` | `Record<string, unknown>` | -- | Input data (required) |
| `maxConcurrency` | `number` | `4` | Max parallel tasks |
| `onProgress` | `(e: SmithersEvent) => void` | `undefined` | Lifecycle event callback |
| `signal` | `AbortSignal` | `undefined` | Cancellation signal |
| `resume` | `boolean` | `false` | Resume from last checkpoint |
| `force` | `boolean` | `false` | Allow resume even if the run is still active (overrides liveness check) |
| `workflowPath` | `string` | `undefined` | Workflow file path (for tool context) |
| `rootDir` | `string` | `undefined` | Sandbox root for tools |
| `logDir` | `string \| null` | `undefined` | Event log directory (`null` to disable) |
| `allowNetwork` | `boolean` | `false` | Allow `bash` network access |
| `maxOutputBytes` | `number` | `200000` | Max output bytes per tool call |
| `toolTimeoutMs` | `number` | `60000` | Tool execution timeout (ms) |
| `hot` | `boolean \| HotReloadOptions` | `undefined` | Hot-reload mode |
| `auth` | `RunAuthContext` | `undefined` | Authentication context. Accessible as `ctx.auth` inside the workflow. |
| `cliAgentToolsDefault` | `"all" \| "explicit-only"` | `"all"` | Default tool access policy for CLI-backed agents. `"explicit-only"` restricts agents to tools listed in `allowTools`. |

---

### HotReloadOptions

```ts
type HotReloadOptions = {
  rootDir?: string;
  outDir?: string;
  maxGenerations?: number;
  cancelUnmounted?: boolean;
  debounceMs?: number;
};
```

| Field | Type | Default | Description |
|---|---|---|---|
| `rootDir` | `string` | Auto-detect | Directory to watch |
| `outDir` | `string` | `.smithers/hmr/<runId>` | Generation overlay directory |
| `maxGenerations` | `number` | `3` | Max overlay generations |
| `cancelUnmounted` | `boolean` | `false` | Cancel unmounted tasks after reload |
| `debounceMs` | `number` | `100` | File change debounce (ms) |

---

### RunResult

```ts
type RunResult = {
  runId: string;
  status: "finished" | "failed" | "cancelled" | "continued" | "waiting-approval" | "waiting-event" | "waiting-timer";
  output?: unknown;
  error?: unknown;
};
```

| Field | Type | Description |
|---|---|---|
| `runId` | `string` | Run identifier |
| `status` | `string` | Terminal status |
| `output` | `unknown` | Final output (if finished) |
| `error` | `unknown` | Error details (if failed) |

---

### RunStatus

```ts
type RunStatus =
  | "running"
  | "waiting-approval"
  | "waiting-event"
  | "waiting-timer"
  | "finished"
  | "continued"
  | "failed"
  | "cancelled";
```

| Value | Description |
|---|---|
| `"running"` | Actively executing |
| `"waiting-approval"` | Awaiting human approval |
| `"waiting-event"` | Awaiting an external signal or event |
| `"waiting-timer"` | Suspended until a durable timer fires |
| `"finished"` | All tasks completed |
| `"continued"` | Run ended via `<ContinueAsNew>` and a fresh run has started |
| `"failed"` | Unrecoverable task failure |
| `"cancelled"` | Cancelled via `AbortSignal` or API |

---

## Task Types

### TaskDescriptor

Internal representation of a task extracted from the JSX tree. Scheduled and executed by the engine.

```ts
type TaskDescriptor = {
  nodeId: string;
  ordinal: number;
  iteration: number;
  ralphId?: string;
  dependsOn?: string[];
  needs?: Record<string, string>;
  worktreeId?: string;
  worktreePath?: string;
  worktreeBranch?: string;

  outputTable: Table | null;
  outputTableName: string;
  outputRef?: import("zod").ZodObject<any>;
  outputSchema?: import("zod").ZodObject<any>;

  parallelGroupId?: string;
  parallelMaxConcurrency?: number;

  needsApproval: boolean;
  approvalMode?: "gate" | "decision";
  approvalOnDeny?: "fail" | "continue" | "skip";
  skipIf: boolean;
  retries: number;
  retryPolicy?: RetryPolicy;
  timeoutMs: number | null;
  continueOnFail: boolean;
  cachePolicy?: CachePolicy;

  agent?: AgentLike | AgentLike[];
  prompt?: string;
  staticPayload?: unknown;
  computeFn?: () => unknown | Promise<unknown>;

  label?: string;
  meta?: Record<string, unknown>;
};
```

| Field | Type | Description |
|---|---|---|
| `nodeId` | `string` | Unique task identifier (from `id` prop) |
| `ordinal` | `number` | Execution order position (depth-first) |
| `iteration` | `number` | Current Loop iteration |
| `ralphId` | `string` | Parent Loop ID |
| `dependsOn` | `string[]` | Explicit dependency node IDs |
| `needs` | `Record<string, string>` | Named dependencies (keys = context keys, values = node IDs) |
| `worktreeId` | `string` | Assigned git worktree ID |
| `worktreePath` | `string` | Worktree filesystem path |
| `worktreeBranch` | `string` | Worktree branch name |
| `outputTable` | `Table \| null` | Drizzle table for output persistence |
| `outputTableName` | `string` | Output table name |
| `outputRef` | `ZodObject<any>` | Zod schema reference from `output` prop |
| `outputSchema` | `ZodObject<any>` | Zod schema for validating agent output |
| `parallelGroupId` | `string` | Parent `<Parallel>` group ID |
| `parallelMaxConcurrency` | `number` | Concurrency limit from parent `<Parallel>` |
| `needsApproval` | `boolean` | Requires human approval |
| `approvalMode` | `"gate" \| "decision"` | `"gate"` pauses before execution; `"decision"` records a decision |
| `approvalOnDeny` | `"fail" \| "continue" \| "skip"` | Behavior on denial |
| `skipIf` | `boolean` | Skip this task |
| `retries` | `number` | Retry attempts on failure |
| `retryPolicy` | `RetryPolicy` | Backoff configuration |
| `timeoutMs` | `number \| null` | Task timeout (ms) |
| `continueOnFail` | `boolean` | Continue workflow on failure |
| `cachePolicy` | `CachePolicy` | Cache configuration |
| `agent` | `AgentLike \| AgentLike[]` | Agent or fallback chain |
| `prompt` | `string` | Prompt text (from children) |
| `staticPayload` | `unknown` | Pre-computed payload (non-agent tasks) |
| `computeFn` | `() => unknown \| Promise<unknown>` | Compute callback |
| `label` | `string` | Display label |
| `meta` | `Record<string, unknown>` | Arbitrary metadata |

---

### AgentLike

```ts
type AgentLike = Agent<any, any, any>;
```

---

### RetryPolicy

```ts
type RetryBackoff = "fixed" | "linear" | "exponential";

type RetryPolicy = {
  backoff?: RetryBackoff;
  initialDelayMs?: number;
};
```

| Field | Type | Default | Description |
|---|---|---|---|
| `backoff` | `"fixed" \| "linear" \| "exponential"` | `"fixed"` | Backoff strategy. `"fixed"`: constant delay. `"linear"`: delay increases by `initialDelayMs` each attempt. `"exponential"`: delay doubles each attempt. |
| `initialDelayMs` | `number` | `0` | Base delay in milliseconds. When `0`, retries execute immediately with no schedule. |

Backoff delay formulas (attempt 1-indexed):

| Strategy | Delay formula |
|---|---|
| `"fixed"` | `initialDelayMs` every attempt |
| `"linear"` | `initialDelayMs * attempt` |
| `"exponential"` | `initialDelayMs * 2^(attempt - 1)` |

When `retries` is set on a `<Task>` without a `retryPolicy`, the task retries immediately (no delay).

---

### RetryTaskOptions

Options for the programmatic `retryTask()` function, which resets a task and its dependents for re-execution.

```ts
type RetryTaskOptions = {
  runId: string;
  nodeId: string;
  iteration?: number;
  resetDependents?: boolean;
  force?: boolean;
  onProgress?: (event: SmithersEvent) => void;
};
```

| Field | Type | Default | Description |
|---|---|---|---|
| `runId` | `string` | -- | Run ID containing the task to retry |
| `nodeId` | `string` | -- | Node ID of the task to retry |
| `iteration` | `number` | `0` | Loop iteration to retry |
| `resetDependents` | `boolean` | `true` | Also reset downstream tasks that depend on this node |
| `force` | `boolean` | `false` | Allow retry even if the run is still active |
| `onProgress` | `(event: SmithersEvent) => void` | `undefined` | Event callback for `RetryTaskStarted` and `RetryTaskFinished` events |

---

### RetryTaskResult

```ts
type RetryTaskResult = {
  success: boolean;
  resetNodes: string[];
  error?: string;
};
```

| Field | Type | Description |
|---|---|---|
| `success` | `boolean` | Whether the retry operation succeeded |
| `resetNodes` | `string[]` | Node IDs that were reset to `"pending"` |
| `error` | `string` | Error message if the retry operation failed |

---

### CachePolicy

```ts
type CachePolicy<Ctx = any> = {
  by?: (ctx: Ctx) => unknown;
  version?: string;
};
```

| Field | Type | Default | Description |
|---|---|---|---|
| `by` | `(ctx: Ctx) => unknown` | `undefined` | Cache key function. Same key reuses cached output. |
| `version` | `string` | `undefined` | Cache version. Changing it invalidates cached outputs. |

---

## Graph Types

### GraphSnapshot

```ts
type GraphSnapshot = {
  runId: string;
  frameNo: number;
  xml: XmlNode | null;
  tasks: TaskDescriptor[];
};
```

| Field | Type | Description |
|---|---|---|
| `runId` | `string` | Run identifier |
| `frameNo` | `number` | Render frame number (monotonically increasing) |
| `xml` | `XmlNode \| null` | Rendered XML tree |
| `tasks` | `TaskDescriptor[]` | Ordered task list |

---

### XmlNode

```ts
type XmlNode = XmlElement | XmlText;
```

---

### XmlElement

```ts
type XmlElement = {
  kind: "element";
  tag: string;
  props: Record<string, string>;
  children: XmlNode[];
};
```

| Field | Type | Description |
|---|---|---|
| `kind` | `"element"` | Discriminant |
| `tag` | `string` | Tag name (`"Workflow"`, `"Task"`, `"Parallel"`, etc.) |
| `props` | `Record<string, string>` | Attributes |
| `children` | `XmlNode[]` | Child nodes |

---

### XmlText

```ts
type XmlText = {
  kind: "text";
  text: string;
};
```

| Field | Type | Description |
|---|---|---|
| `kind` | `"text"` | Discriminant |
| `text` | `string` | Content |

---

## Event Types

### SmithersEvent

Discriminated union of all lifecycle events. Every event includes `runId` and `timestampMs`.

```ts
type SmithersEvent =
  | RunStarted
  | RunStatusChanged
  | RunFinished
  | RunFailed
  | RunCancelled
  | RunContinuedAsNew
  | RunHijackRequested
  | RunHijacked
  | FrameCommitted
  | NodePending
  | NodeStarted
  | NodeFinished
  | NodeFailed
  | NodeCancelled
  | NodeSkipped
  | NodeRetrying
  | NodeWaitingApproval
  | ApprovalRequested
  | ApprovalGranted
  | ApprovalDenied
  | ToolCallStarted
  | ToolCallFinished
  | NodeOutput
  | AgentEvent
  | RevertStarted
  | RevertFinished
  | WorkflowReloadDetected
  | WorkflowReloaded
  | WorkflowReloadFailed
  | WorkflowReloadUnsafe
  | ScorerStarted
  | ScorerFinished
  | ScorerFailed
  | TokenUsageReported;
```

#### Run Events

| Event | Fields | Description |
|---|---|---|
| `RunStarted` | `runId`, `timestampMs` | Execution began |
| `RunStatusChanged` | `runId`, `status: RunStatus`, `timestampMs` | Status transition |
| `RunFinished` | `runId`, `timestampMs` | All tasks completed |
| `RunFailed` | `runId`, `error: unknown`, `timestampMs` | Failed |
| `RunCancelled` | `runId`, `timestampMs` | Cancelled |
| `RunContinuedAsNew` | `runId`, `newRunId`, `iteration`, `carriedStateSize`, `ancestryDepth?`, `timestampMs` | Continued as new run |
| `RunHijackRequested` | `runId`, `target?`, `timestampMs` | Hijack requested |
| `RunHijacked` | `runId`, `nodeId`, `iteration`, `attempt`, `engine`, `mode`, `resume?`, `cwd`, `timestampMs` | Hijack completed |

#### Frame Events

| Event | Fields | Description |
|---|---|---|
| `FrameCommitted` | `runId`, `frameNo`, `xmlHash`, `timestampMs` | Frame persisted |

#### Node Events

| Event | Fields | Description |
|---|---|---|
| `NodePending` | `runId`, `nodeId`, `iteration`, `timestampMs` | Queued |
| `NodeStarted` | `runId`, `nodeId`, `iteration`, `attempt`, `timestampMs` | Execution began |
| `NodeFinished` | `runId`, `nodeId`, `iteration`, `attempt`, `timestampMs` | Completed |
| `NodeFailed` | `runId`, `nodeId`, `iteration`, `attempt`, `error`, `timestampMs` | Failed |
| `NodeCancelled` | `runId`, `nodeId`, `iteration`, `attempt?`, `reason?`, `timestampMs` | Cancelled |
| `NodeSkipped` | `runId`, `nodeId`, `iteration`, `timestampMs` | Skipped |
| `NodeRetrying` | `runId`, `nodeId`, `iteration`, `attempt`, `timestampMs` | Retrying |

#### Approval Events

| Event | Fields | Description |
|---|---|---|
| `NodeWaitingApproval` | `runId`, `nodeId`, `iteration`, `timestampMs` | Awaiting approval |
| `ApprovalRequested` | `runId`, `nodeId`, `iteration`, `timestampMs` | Approval requested |
| `ApprovalGranted` | `runId`, `nodeId`, `iteration`, `timestampMs` | Approved |
| `ApprovalDenied` | `runId`, `nodeId`, `iteration`, `timestampMs` | Denied |

#### Tool Events

| Event | Fields | Description |
|---|---|---|
| `ToolCallStarted` | `runId`, `nodeId`, `iteration`, `attempt`, `toolName`, `seq`, `timestampMs` | Tool call began |
| `ToolCallFinished` | `runId`, `nodeId`, `iteration`, `attempt`, `toolName`, `seq`, `status`, `timestampMs` | Tool call completed |

#### Output Events

| Event | Fields | Description |
|---|---|---|
| `NodeOutput` | `runId`, `nodeId`, `iteration`, `attempt`, `text`, `stream`, `timestampMs` | Agent output text |

#### Revert Events

| Event | Fields | Description |
|---|---|---|
| `RevertStarted` | `runId`, `nodeId`, `iteration`, `attempt`, `jjPointer`, `timestampMs` | VCS revert started |
| `RevertFinished` | `runId`, `nodeId`, `iteration`, `attempt`, `jjPointer`, `success`, `error?`, `timestampMs` | VCS revert completed |

---

## Component Props

### WorkflowProps

```ts
type WorkflowProps = {
  name: string;
  cache?: boolean;
  children?: React.ReactNode;
};
```

| Prop | Type | Required | Description |
|---|---|---|---|
| `name` | `string` | Yes | Workflow name for logging and database |
| `cache` | `boolean` | No | Enable output caching |
| `children` | `ReactNode` | No | Child components |

---

### TaskProps\<Row, D\>

```ts
type TaskProps<Row, Output, D extends DepsSpec = {}> = {
  key?: string;
  id: string;
  output: Output;
  outputSchema?: import("zod").ZodObject<any>;
  agent?: AgentLike | AgentLike[];
  fallbackAgent?: AgentLike;
  dependsOn?: string[];
  needs?: Record<string, string>;
  deps?: D;
  skipIf?: boolean;
  needsApproval?: boolean;
  timeoutMs?: number;
  retries?: number;
  retryPolicy?: RetryPolicy;
  continueOnFail?: boolean;
  cache?: CachePolicy;
  scorers?: ScorersMap;
  label?: string;
  meta?: Record<string, unknown>;
  children: string | Row | (() => Row | Promise<Row>) | React.ReactNode | ((deps: InferDeps<D>) => Row | React.ReactNode);
};
```

| Prop | Type | Required | Description |
|---|---|---|---|
| `id` | `string` | Yes | Unique task identifier |
| `output` | `ZodObject<any> \| Table \| string` | Yes | Output target: Zod schema from `outputs` (recommended), Drizzle table, or string key |
| `outputSchema` | `ZodObject<any>` | No | Zod schema for agent output validation |
| `agent` | `AgentLike \| AgentLike[]` | No | Agent or fallback chain |
| `fallbackAgent` | `AgentLike` | No | Append one fallback agent |
| `dependsOn` | `string[]` | No | Explicit dependency node IDs |
| `needs` | `Record<string, string>` | No | Named dependencies (keys = context keys, values = node IDs) |
| `deps` | `Record<string, OutputTarget>` | No | Typed render-time dependencies. Keys resolve from task ids or `needs` entries. |
| `skipIf` | `boolean` | No | Skip when true |
| `needsApproval` | `boolean` | No | Pause for human approval |
| `timeoutMs` | `number` | No | Timeout (ms) |
| `retries` | `number` | No | Retry attempts (default: 0) |
| `retryPolicy` | `RetryPolicy` | No | Retry timing |
| `continueOnFail` | `boolean` | No | Continue workflow on failure |
| `cache` | `CachePolicy` | No | Cache configuration |
| `scorers` | `ScorersMap` | No | Scorers to evaluate task output after completion |
| `label` | `string` | No | Display label |
| `meta` | `Record<string, unknown>` | No | Arbitrary metadata |
| `children` | `string \| Row \| (() => Row) \| ReactNode \| ((deps) => Row \| ReactNode)` | Yes | Prompt, compute callback, static payload, deps function, or nested elements |

---

### SequenceProps

```ts
type SequenceProps = {
  skipIf?: boolean;
  children?: React.ReactNode;
};
```

| Prop | Type | Required | Description |
|---|---|---|---|
| `skipIf` | `boolean` | No | Skip entire sequence when true |
| `children` | `ReactNode` | No | Child tasks |

---

### ParallelProps

```ts
type ParallelProps = {
  id?: string;
  maxConcurrency?: number;
  skipIf?: boolean;
  children?: React.ReactNode;
};
```

| Prop | Type | Required | Description |
|---|---|---|---|
| `id` | `string` | No | Group identifier |
| `maxConcurrency` | `number` | No | Max concurrent tasks |
| `skipIf` | `boolean` | No | Skip entire group when true |
| `children` | `ReactNode` | No | Child tasks |

---

### BranchProps

```ts
type BranchProps = {
  if: boolean;
  then: React.ReactElement;
  else?: React.ReactElement;
  skipIf?: boolean;
};
```

| Prop | Type | Required | Description |
|---|---|---|---|
| `if` | `boolean` | Yes | Condition |
| `then` | `ReactElement` | Yes | Rendered when true |
| `else` | `ReactElement` | No | Rendered when false |
| `skipIf` | `boolean` | No | Skip entirely when true |

---

### LoopProps

```ts
type LoopProps = {
  id?: string;
  until: boolean;
  maxIterations?: number;
  onMaxReached?: "fail" | "return-last";
  skipIf?: boolean;
  children?: React.ReactNode;
};
```

| Prop | Type | Required | Description |
|---|---|---|---|
| `id` | `string` | No | Loop identifier (auto-generated if omitted) |
| `until` | `boolean` | Yes | Exit when true |
| `maxIterations` | `number` | No | Max iterations |
| `onMaxReached` | `"fail" \| "return-last"` | No | Behavior on limit: fail or return last output |
| `skipIf` | `boolean` | No | Skip loop when true |
| `children` | `ReactNode` | No | Tasks per iteration |

---

### RalphProps

> **Deprecated:** Use `LoopProps`.

```ts
type RalphProps = LoopProps;
```

---

### ApprovalProps\<Row\>

```ts
type ApprovalProps<Row = ApprovalDecision> = {
  id: string;
  output: ZodObject<any> | Table | string;
  outputSchema?: import("zod").ZodObject<any>;
  request: ApprovalRequest;
  onDeny?: "fail" | "continue" | "skip";
  dependsOn?: string[];
  needs?: Record<string, string>;
  skipIf?: boolean;
  timeoutMs?: number;
  retries?: number;
  retryPolicy?: RetryPolicy;
  continueOnFail?: boolean;
  cache?: CachePolicy;
  label?: string;
  meta?: Record<string, unknown>;
  key?: string;
  children?: React.ReactNode;
};

type ApprovalRequest = {
  title: string;
  summary?: string;
  metadata?: Record<string, unknown>;
};

type ApprovalDecision = {
  approved: boolean;
  note: string | null;
  decidedBy: string | null;
  decidedAt: string | null;
};
```

| Prop | Type | Required | Description |
|---|---|---|---|
| `id` | `string` | Yes | Approval node identifier |
| `output` | `ZodObject<any> \| Table \| string` | Yes | Persistence target for decision |
| `outputSchema` | `ZodObject<any>` | No | Decision output validation |
| `request` | `ApprovalRequest` | Yes | Title, summary, metadata |
| `onDeny` | `"fail" \| "continue" \| "skip"` | No | Behavior on denial |
| `dependsOn` | `string[]` | No | Dependency node IDs |
| `needs` | `Record<string, string>` | No | Named dependencies |
| `skipIf` | `boolean` | No | Skip when true |
| `timeoutMs` | `number` | No | Timeout (ms) |
| `retries` | `number` | No | Retry attempts |
| `retryPolicy` | `RetryPolicy` | No | Retry backoff |
| `continueOnFail` | `boolean` | No | Continue on failure |
| `cache` | `CachePolicy` | No | Cache configuration |
| `label` | `string` | No | Display label (defaults to `request.title`) |
| `meta` | `Record<string, unknown>` | No | Arbitrary metadata |
| `children` | `ReactNode` | No | Child elements |

---

## Error Types

### SmithersError

```ts
type SmithersError = {
  code: SmithersErrorCode;
  message: string;
  summary: string;
  docsUrl: string;
  details?: Record<string, unknown>;
  cause?: unknown;
};
```

| Field | Type | Description |
|---|---|---|
| `code` | `SmithersErrorCode` | Machine-readable error code |
| `message` | `string` | Error description |
| `summary` | `string` | Short error summary without docs URL suffixing |
| `docsUrl` | `string` | Documentation URL for the error reference |
| `details` | `Record<string, unknown>` | Additional context |
| `cause` | `unknown` | Original nested cause when one is preserved |

### SmithersErrorCode

```ts
type SmithersErrorCode =
  | KnownSmithersErrorCode
  | (string & {});
```

Use `KnownSmithersErrorCode` when you want exhaustive switching over built-in Smithers failures. See [Error Reference](/reference/errors) for the full built-in list.

### KnownSmithersErrorCode

```ts
type KnownSmithersErrorCode =
  | "INVALID_INPUT"
  | "MISSING_INPUT"
  | "MISSING_INPUT_TABLE"
  // ... all built-in Smithers runtime codes
```

This union excludes the custom string escape hatch and is the right type for exhaustive `switch` statements over built-in Smithers errors.

---

## Server Types

### ServerOptions

See [HTTP Server](/integrations/server) for details.

```ts
type ServerOptions = {
  port?: number;
  db?: BunSQLiteDatabase<any>;
  authToken?: string;
  maxBodyBytes?: number;
  rootDir?: string;
  allowNetwork?: boolean;
};
```

### ServeOptions

Options for `createServeApp(...)`, the single-run Hono app exported from the root package.

```ts
type ServeOptions = {
  workflow: SmithersWorkflow<any>;
  adapter: SmithersDb;
  runId: string;
  abort: AbortController;
  authToken?: string;
  metrics?: boolean;
};
```

---

## Tool Context Types

### ToolContext

Internal context provided to tools via `AsyncLocalStorage`. Not typically used directly.

```ts
type ToolContext = {
  db: SmithersDb;
  runId: string;
  nodeId: string;
  iteration: number;
  attempt: number;
  rootDir: string;
  allowNetwork: boolean;
  maxOutputBytes: number;
  timeoutMs: number;
  seq: number;
};
```
