Skip to main content
@smithers-orchestrator/cloudflare runs Smithers inside Cloudflare Workers. It provides a SQLite descriptor over Durable Object storage or D1, a factory that builds the Smithers API against that descriptor, and a sandbox provider backed by the Cloudflare Sandbox SDK. Import createSmithersCloudflare from the main package subpath; the descriptor and provider helpers are available from either the subpath or the scoped package:
import {
  createSmithersCloudflare,
  createCloudflareDurableObjectSqliteDescriptor,
  createCloudflareD1SqliteDescriptor,
  createCloudflareSandboxProvider,
} from "smithers-orchestrator/cloudflare";

Create the Smithers API

createSmithersCloudflare(schemas, { db }) mirrors createSmithers but takes a Cloudflare SQLite descriptor as its storage:
type CreateSmithersCloudflareOptions = CreateSmithersOptions & {
  db: CloudflareSqliteDescriptor;  // required
  close?: () => Promise<void> | void;
};

const { smithers, outputs } = await createSmithersCloudflare(
  { input: inputSchema, result: resultSchema },
  { db: createCloudflareDurableObjectSqliteDescriptor(ctx.storage) },
);
It is async (it provisions the schema and per-output tables through the descriptor) and returns the same API surface as createSmithers plus an optional close(). Omitting db throws INVALID_INPUT. createCloudflareDurableObjectSqliteDescriptor(storage) wraps a Durable Object’s SQLite store. Pass the Durable Object’s ctx.storage (or its ctx.storage.sql handle):
export class SmithersDurableObject {
  constructor(ctx, env) {
    this.descriptor = createCloudflareDurableObjectSqliteDescriptor(ctx.storage);
  }
}
This is the durable choice. When storage exposes a transaction method the descriptor binds and forwards it, so Smithers gets real interactive transactions (BEGIN / COMMIT / ROLLBACK). Frame commits, run-state checkpoints, and task completion all rely on that atomicity.

Storage: D1 (read-mostly only)

createCloudflareD1SqliteDescriptor(database) wraps a D1 binding:
const descriptor = createCloudflareD1SqliteDescriptor(env.DB);
D1 has no interactive transactions. Its prepare/bind/run API cannot hold an open BEGIN/COMMIT/ROLLBACK across round-trips. The descriptor reports that limitation, and Smithers rejects transactional writes before their operation begins instead of risking a partial commit. Do not back durable run state with D1. Use createCloudflareDurableObjectSqliteDescriptor for durability and reserve D1 for read-mostly use.

Sandbox provider

Runtime "cloudflare" is provider-backed: it has no built-in transport, so a <Sandbox> that requests it needs a provider. createCloudflareSandboxProvider(options) builds one over the Cloudflare Sandbox SDK (@cloudflare/sandbox, an optional dependency imported lazily):
const provider = createCloudflareSandboxProvider({ binding: env.Sandbox });
Pass the provider where the runtime is resolved. Requesting runtime "cloudflare" without a provider throws INVALID_INPUT (“Sandbox runtime “cloudflare” requires a provider from smithers-orchestrator/cloudflare, e.g. createCloudflareSandboxProvider().”). The provider’s id is CLOUDFLARE_SANDBOX_PROVIDER_ID ("cloudflare-sandbox"), which becomes the selected runtime. options.binding (or (request) => binding) must be the Durable Object binding for the Sandbox SDK. Other options cover the sandbox id, workdir (default /workspace), command, env, setup files, execution mode (exec or process), and cleanup (destroy or keep).

Serverless & cost

On Cloudflare, Smithers splits along the two execution modes described in Where agents run:
  • The control plane + in-process agents run inside the Worker / Durable Object. createSmithersCloudflare builds the Smithers API against Durable Object SQLite (createCloudflareDurableObjectSqliteDescriptor), and SDK agents (AnthropicAgent, OpenAIAgent, …) are plain HTTPS calls with no subprocess — so a workflow built entirely from SDK agents runs Worker-native.
  • CLI / full-OS agents cannot run in the Worker’s JS runtime (they spawn a vendor binary via node:child_process). They are offloaded to a @cloudflare/sandbox container through createCloudflareSandboxProvider, which the Worker delegates to at each <Sandbox> boundary.
Not turnkey-serverless for CLI-agent workflows today. The package ships storage descriptors and a sandbox provider, but no Worker entry / Durable Object class and no Workers-native run driver. The core engine that advances every run uses node:fs and node:child_process (git/jj worktrees on a real filesystem), so a Node/Bun host is still required to drive runs. The Cloudflare provider also creates one container per <Sandbox> run() (keyed ${runId}-${sandboxId}) — not per agent turn. Both exec and process execution modes wait for the work to finish and reconcile the result bundle; set sleepAfter to control idle hibernation. Treat Workers-native execution as the storage + in-process-agent path today, not turnkey serverless for CLI harnesses.
What’s billed on Cloudflare:
ComponentBilling driver
In-process SDK agentsModel API tokens (billed by the model provider, not Cloudflare)
Worker / Durable Object control planeWorker invocations + Durable Object requests and duration; DO-SQLite storage (rows read/written). Use DO-SQLite for durable run-of-record — D1 has no interactive transactions and can leave partial state (see the D1 warning above)
@cloudflare/sandbox container (per <Sandbox>)Container wall-clock from create → teardown. Idle hibernation follows sleepAfter (Sandbox SDK default ~10m if unset). cleanup: "keep" leaves the container billing until it hibernates; the default cleanup: "destroy" stops it at the end of the boundary — in both exec and process modes, since run() awaits completion before cleanup
Cloudflare’s own pricing for Workers, Durable Objects, and the Sandbox SDK changes independently of Smithers — check Cloudflare’s current pricing pages for exact per-unit figures. Smithers only determines the shape of what’s consumed: token calls, DO storage/requests, and container wall-clock per <Sandbox> boundary.

Notes

  • The package exports no Durable Object class and no Worker entry helper. You write the Worker and Durable Object; the package supplies the storage descriptors and sandbox provider.
  • createMockCloudflareSandboxEnvironment(handler) is exported for tests: it implements the subset of the Sandbox SDK the provider uses.
  • The descriptor helpers are also exported from @smithers-orchestrator/cloudflare; only createSmithersCloudflare requires the smithers-orchestrator/cloudflare subpath.