---
title: Authoring API
description: Factory functions that turn Zod schemas into a typed, durable workflow API.
icon: "pen-nib"
---

A Smithers workflow is built from a single factory call. You hand it Zod schemas;
it owns the storage layer and hands back a typed set of JSX components plus the
`smithers()` wrapper that produces a runnable `SmithersWorkflow`.

`createSmithers` is synchronous and SQLite-only. The other factories exist for
the cases it cannot serve: Postgres/PGlite backends, environment-resolved
backends, store migration, and non-JSX (external) build functions.

```ts
import {
  createSmithers,
  createSmithersPostgres,
  openSmithersBackend,
  migrateSmithersStore,
  createExternalSmithers,
} from "smithers-orchestrator";
```

<Note>
`smithers`, `Workflow`, `Task`, `useCtx`, `outputs`, `tables`, and `db` are
**returned by the factory**, not imported. The component set is documented in the
[Components reference](/reference/components); this page covers the factories
themselves.
</Note>

## createSmithers

Schema-driven workflow API over a local SQLite database. The schemas you pass
become both the output tables and the typed `outputs` accessor. This is the
default entry point for almost every workflow.

```ts
function createSmithers<Schemas extends Record<string, ZodObject>>(
  schemas: Schemas,
  opts?: CreateSmithersOptions,
): CreateSmithersApi<Schemas>;
```

<ParamField path="schemas" type="Record<string, ZodObject>" required>
  A map of output name to Zod object schema. Each key becomes a property on
  `outputs` and a backing table. Use the reserved `input` key to type the
  workflow's run input.
</ParamField>

<ParamField path="opts" type="CreateSmithersOptions">
  Optional metadata and storage configuration.

  <Expandable title="CreateSmithersOptions">
    <ParamField path="readableName" type="string">
      Human-readable workflow name surfaced in the UI and run metadata.
    </ParamField>
    <ParamField path="description" type="string">
      One-line description surfaced alongside the name.
    </ParamField>
    <ParamField path="alertPolicy" type="SmithersAlertPolicy">
      Default alert routing for slow or stuck nodes. See
      [Alerting](/guides/alerting).
    </ParamField>
    <ParamField path="dbPath" type="string" default=".smithers/smithers.db">
      Path to the SQLite database file.
    </ParamField>
    <ParamField path="journalMode" type="string" default="WAL">
      SQLite journal mode passed through to the adapter.
    </ParamField>
    <ParamField path="backend" type='"sqlite" | "pglite" | "postgres"' default='"sqlite"'>
      The backend the API was resolved to. `createSmithers` serves only
      `"sqlite"`; `"pglite"`/`"postgres"` fail loud here and require
      `openSmithersBackend` or `createSmithersPostgres`.
    </ParamField>
  </Expandable>
</ParamField>

<ResponseField name="CreateSmithersApi" type="object">
  The typed authoring surface.

  <Expandable title="members">
    <ResponseField name="smithers" type="(build, opts?) => SmithersWorkflow">
      Wraps a `(ctx) => JSX.Element` build function into a runnable workflow. The
      default export of a workflow module.
    </ResponseField>
    <ResponseField name="Workflow / Task / Sequence / Parallel / Branch / Loop / ..." type="component">
      The full typed JSX component set. See the
      [Components reference](/reference/components).
    </ResponseField>
    <ResponseField name="useCtx" type="() => SmithersCtx<Schema>">
      Hook to read the run context (`input`, `outputs`, `runId`, `iteration`)
      inside a component. See [`SmithersCtx`](/reference/types).
    </ResponseField>
    <ResponseField name="outputs" type="{ [K in keyof Schemas]: Schemas[K] }">
      Typed output targets to pass to a component's `output` prop.
    </ResponseField>
    <ResponseField name="tables" type="{ [K in keyof Schemas]: Table }">
      The Drizzle tables backing each output schema.
    </ResponseField>
    <ResponseField name="db" type="BunSQLiteDatabase">
      The underlying Drizzle database handle.
    </ResponseField>
  </Expandable>
</ResponseField>

```ts
const { Workflow, Task, smithers, outputs } = createSmithers({
  input: z.object({ topic: z.string() }),
  research: z.object({ findings: z.string() }),
});

export default smithers((ctx) => (
  <Workflow name="research">
    <Task id="research" output={outputs.research} agent={myAgent}>
      {`Research ${ctx.input.topic}`}
    </Task>
  </Workflow>
));
```

**Source** [`create.js`](https://github.com/smithersai/smithers/blob/main/packages/smithers/src/create.js) · [`CreateSmithersApi.ts`](https://github.com/smithersai/smithers/blob/main/packages/smithers/src/CreateSmithersApi.ts) · **Tests** [`create-unit.test.js`](https://github.com/smithersai/smithers/blob/main/packages/smithers/tests/create-unit.test.js) · **See also** [Get started](/guide/get-started), [JSX overview](/jsx/overview)

## createSmithersPostgres

PostgreSQL or PGlite equivalent of `createSmithers`. Asynchronous because it
opens a connection, and it returns an extra `close()`. Reach for it when a run
must outlive a single process or be shared across hosts.

```ts
function createSmithersPostgres<Schemas extends Record<string, ZodObject>>(
  schemas: Schemas,
  opts?: CreateSmithersPostgresOptions,
): Promise<CreateSmithersApi<Schemas> & { close: () => Promise<void> }>;
```

<ParamField path="schemas" type="Record<string, ZodObject>" required>
  Same as `createSmithers`.
</ParamField>

<ParamField path="opts" type="CreateSmithersPostgresOptions">
  Extends `CreateSmithersOptions` with the backend connection. A discriminated
  union on `provider`.

  <Expandable title="provider: postgres (default)">
    <ParamField path="connectionString" type="string">
      Postgres connection URL.
    </ParamField>
    <ParamField path="connection" type="object">
      Connection object passed to the driver instead of a URL.
    </ParamField>
  </Expandable>
  <Expandable title='provider: "pglite"'>
    <ParamField path="dataDir" type="string">
      On-disk directory for the embedded PGlite database.
    </ParamField>
  </Expandable>
</ParamField>

<ResponseField name="Promise<CreateSmithersApi & { close }>" type="object">
  The same API as `createSmithers`, plus `close()` to release the connection
  pool. Call it when the process is done with the backend.
</ResponseField>

<CodeGroup>
```ts Postgres
const api = await createSmithersPostgres(schemas, {
  provider: "postgres",
  connectionString: process.env.DATABASE_URL,
});
```

```ts PGlite
const api = await createSmithersPostgres(schemas, {
  provider: "pglite",
  dataDir: ".smithers/pgdata",
});
```
</CodeGroup>

**Source** [`create.js`](https://github.com/smithersai/smithers/blob/main/packages/smithers/src/create.js) · **See also** [Control-plane deployment](/deployment/control-plane), [`migrateSmithersStore`](#migratesmithersstore)

## openSmithersBackend

Resolve the backend from the environment instead of hard-coding it. Reads
`smithers.config` / env vars and returns whichever of SQLite, PGlite, or Postgres
they select. Use it in shared CLIs and servers that should honor a deployment's
configured store.

```ts
function openSmithersBackend<Schemas extends Record<string, ZodObject>>(
  schemas?: Schemas,
  opts?: OpenSmithersBackendOptions,
): Promise<CreateSmithersApi<Schemas> & { close?: () => Promise<void> }>;
```

<ParamField path="schemas" type="Record<string, ZodObject>">
  Optional output schemas. Omit to open the backend without registering tables.
</ParamField>

<ParamField path="opts" type="OpenSmithersBackendOptions">
  Extends `CreateSmithersOptions`.

  <Expandable title="OpenSmithersBackendOptions">
    <ParamField path="backend" type='"sqlite" | "pglite" | "postgres"'>
      Force a backend instead of resolving from config.
    </ParamField>
    <ParamField path="cwd" type="string">
      Directory to resolve config and relative paths from.
    </ParamField>
    <ParamField path="configPath" type="string">
      Explicit path to the Smithers config file.
    </ParamField>
    <ParamField path="env" type="Record<string, string | undefined>">
      Environment overrides used during resolution.
    </ParamField>
    <ParamField path="connectionString" type="string">
      Postgres URL when the resolved backend is `postgres`.
    </ParamField>
    <ParamField path="connection" type="object">
      Postgres connection object alternative to `connectionString`.
    </ParamField>
    <ParamField path="pgliteDataDir" type="string">
      Data directory when the resolved backend is `pglite`.
    </ParamField>
  </Expandable>
</ParamField>

<ResponseField name="Promise<CreateSmithersApi & { close? }>" type="object">
  The authoring API for the resolved backend. `close()` is present when the
  backend holds a connection (PGlite/Postgres).
</ResponseField>

**Source** [`openSmithersBackend.js`](https://github.com/smithersai/smithers/blob/main/packages/smithers/src/openSmithersBackend.js) · **Tests** [`openSmithersBackend.test.js`](https://github.com/smithersai/smithers/blob/main/packages/smithers/tests/openSmithersBackend.test.js) · **See also** [Package configuration](/reference/package-configuration)

## migrateSmithersStore

Copy an existing SQLite store into PGlite or Postgres, table by table, and write
a migration marker. Use it once when graduating a project from the local SQLite
default to a shared backend.

```ts
function migrateSmithersStore(
  opts?: MigrateSmithersStoreOptions,
): Promise<SmithersMigrationResult>;
```

<ParamField path="opts" type="MigrateSmithersStoreOptions">
  <Expandable title="MigrateSmithersStoreOptions">
    <ParamField path="cwd" type="string">
      Directory to resolve paths and config from.
    </ParamField>
    <ParamField path="dbPath" type="string">
      Source SQLite path. Defaults to the resolved store path.
    </ParamField>
    <ParamField path="to" type='"pglite" | "postgres"'>
      Target backend.
    </ParamField>
    <ParamField path="url" type="string">
      Target connection URL for Postgres.
    </ParamField>
    <ParamField path="env" type="Record<string, string | undefined>">
      Environment overrides.
    </ParamField>
    <ParamField path="pgliteDataDir" type="string">
      Target data directory for PGlite.
    </ParamField>
    <ParamField path="keepSqlite" type="boolean" default="false">
      Keep the source SQLite file after a successful copy.
    </ParamField>
    <ParamField path="batchSize" type="number">
      Rows copied per batch.
    </ParamField>
    <ParamField path="onProgress" type="(event) => void | Promise<void>">
      Progress callback. Receives `table-start`, `table-copied`, and `done`
      events with row counts and durations.
    </ParamField>
  </Expandable>
</ParamField>

<ResponseField name="Promise<SmithersMigrationResult>" type="object">
  <Expandable title="SmithersMigrationResult">
    <ResponseField name="backend" type='"pglite" | "postgres"'>
      The backend migrated to.
    </ResponseField>
    <ResponseField name="dbPath" type="string">
      Source SQLite path that was read.
    </ResponseField>
    <ResponseField name="markerPath" type="string">
      Path of the written migration marker.
    </ResponseField>
    <ResponseField name="target" type="{ backend, dataDir?, url? }">
      Resolved target descriptor.
    </ResponseField>
    <ResponseField name="runCount" type="number">
      Number of runs copied.
    </ResponseField>
    <ResponseField name="schemaVersion" type="string">
      Schema version stamped into the target.
    </ResponseField>
    <ResponseField name="durationMs" type="number">
      Total wall-clock duration.
    </ResponseField>
    <ResponseField name="tables" type="Array<{ table, sourceRows, targetRows, durationMs }>">
      Per-table copy report.
    </ResponseField>
    <ResponseField name="sqliteRemoved" type="boolean">
      Whether the source SQLite file was deleted (the inverse of `keepSqlite`).
    </ResponseField>
  </Expandable>
</ResponseField>

**Source** [`migrateSmithersStore.js`](https://github.com/smithersai/smithers/blob/main/packages/smithers/src/migrateSmithersStore.js) · **Tests** [`migrateSmithersStore.test.js`](https://github.com/smithersai/smithers/blob/main/packages/smithers/tests/migrateSmithersStore.test.js)

## createExternalSmithers

Build a `SmithersWorkflow` from a plain build function instead of JSX. The build
function returns a `HostNodeJson` tree that maps 1:1 to what the JSX renderer
produces, so a workflow can be authored in any language that can emit that JSON.

```ts
function createExternalSmithers<S extends Record<string, ZodObject>>(
  config: ExternalSmithersConfig<S>,
): SmithersWorkflow<S> & { tables: Record<string, any>; cleanup: () => void };
```

<ParamField path="config" type="ExternalSmithersConfig<S>" required>
  <Expandable title="ExternalSmithersConfig">
    <ParamField path="schemas" type="S" required>
      Output schemas, same as `createSmithers`.
    </ParamField>
    <ParamField path="agents" type="Record<string, AgentLike>" required>
      Named agents the build function references by id.
    </ParamField>
    <ParamField path="buildFn" type="(ctx: SerializedCtx) => HostNodeJson" required>
      Pure function that returns the host-node tree for a given serialized
      context. See [`HostNodeJson`](/reference/types).
    </ParamField>
    <ParamField path="dbPath" type="string">
      SQLite path, same default as `createSmithers`.
    </ParamField>
  </Expandable>
</ParamField>

<ResponseField name="SmithersWorkflow & { tables, cleanup }" type="object">
  A runnable workflow plus its backing `tables` and a `cleanup()` to release the
  database.
</ResponseField>

**Source** [`external/index.js`](https://github.com/smithersai/smithers/blob/main/packages/smithers/src/external/index.js) · **Tests** [`create-unit.test.js`](https://github.com/smithersai/smithers/blob/main/packages/smithers/tests/create-unit.test.js) · **See also** [`SerializedCtx`, `HostNodeJson`](/reference/types)

---

Once you have a `SmithersWorkflow`, run it with the [Runtime API](/runtime/run-workflow)
or the [CLI](/cli/overview). For the full type surface, see the
[Types reference](/reference/types).
