API reference
The embed API runs within one process. Actor hosts expose a similar HTTP contract with one writer per run. Signatures below are extracted from the runtime source; the client returns HTTP response envelopes rather than exactly the same shapes as embed methods.
Create a runtime#
import { createLooms } from '@swirls/looms/runtime'import { modules, release } from './review-definition'const looms = createLooms({ modules })try { const { runId, state } = await looms.start(release, { topic: 'Launch' }) console.log(runId, state.status)} finally { await looms.stop()}This uses the quickstart definition and an in-memory store. Pass a persistent store before relying on restart recovery. Nothing is installed by default: modules defaults to an empty list, store to memory, and serve to off.
export interface CreateLoomsOptions { /** Runtime modules to enable. Pass `agent()`, `workflow()`, `approval()`, and/or your own. */ readonly modules?: readonly AnyRuntimeModule[] readonly store?: EventStore | Promise<EventStore> | (() => Promise<EventStore>) readonly serve?: boolean | { port?: number; hostname?: string } readonly maxWakeIterations?: number /** Maximum active and queued mutation operations per run. Default 256. */ readonly maxPendingRunOperations?: number /** Durable events between mid-wake snapshots. Default 200; `0` disables. Parking always snapshots. */ readonly snapshotEvery?: number /** Defaults to the EventStore's attached store (S2) or an in-memory SnapshotStore. */ readonly snapshotStore?: SnapshotStore readonly trimAfterSnapshot?: { keepSnapshots: number coverage?: (runId: string) => EventStoreTrimCoverage | Promise<EventStoreTrimCoverage> } /** In-process cursor cache size. Default `0` (stateless between calls). */ readonly runCacheSize?: number /** Scan existing runs for pending timers on boot. Default true. */ readonly rescanTimers?: boolean /** Pluggable wake scheduler for timer waits. Defaults to an in-process Effect fiber scheduler. */ readonly scheduler?: WakeScheduler readonly worker?: EffectWorker /** Failure-isolated runtime observation sink. */ readonly observer?: RuntimeObserver /** * Authorizes HTTP API requests. Without it, run reads and writes are open while worker callback * and operations routes return 503; `bearerAuth({ worker, operations })` enables them. * * A mounted debugger is authorized as `{ access: 'read', name: 'debugger' }`. Bearer tokens on * reads block browser navigation, so hosts that need auth should use a cookie or session policy. */ readonly authorize?: Authorize /** * Serves a debugger UI under `debugger.basePath` (for example `/debugger`). The runtime does not * bundle a UI; pass `debuggerUi()` from `@swirls/looms/debugger/server`. */ readonly debugger?: DebuggerHost}snapshotEvery defaults to 200 durable events; zero disables mid-wake snapshots, while parking still snapshots. runCacheSize defaults to zero. maxWakeIterations defaults to 100 and bounds a wake cycle, not application cost. The default scheduler uses process-local timers. trimAfterSnapshot is opt-in and can remove historical replay data.
Embed methods and return types#
export interface StartResult { readonly runId: string readonly threadId: string readonly state: RunState}export interface Looms { readonly runtime: Promise<LoomsRuntime> readonly store: Promise<EventStore> ready(): Promise<{ store: EventStore; runtime: LoomsRuntime }> /** Start a run from a definition object; the input type follows the definition's schema. */ start<TDef extends DefinitionRef>( definition: TDef, input?: DefinitionInput<TDef>, options?: { runId?: string; threadId?: string; idempotencyKey?: string }, ): Promise<StartResult> /** Start a run by `{ kind, definitionName }` when you only have names (HTTP bodies, CLIs). */ startRun(args: { kind: string definitionName: string definitionVersion?: string input?: JsonValue runId?: string threadId?: string idempotencyKey?: string }): Promise<StartResult> getRun(runId: string): Promise<RunState> getEvents(runId: string, options?: { fromSeq?: number; limit?: number }): Promise<EventEnvelope[]> signal( runId: string, events: ReadonlyArray<EventInput>, options?: { idempotencyKey?: string }, ): Promise<RunState> wake(runId: string): Promise<RunState> rescanTimers(): Promise<number> recoverDeadlines(): Promise<number> inspectRun(runId: string): Promise<RunOperationalStatus> retryEffect(runId: string, effectId: string): Promise<RunState> listRuns(): Promise<string[]> project<S>(runId: string, definition: ProjectionDefinition<S>): Promise<S> replayTo(runId: string, seq: number): Promise<ReplayStep | null> cancel(runId: string, threadId?: string): Promise<RunState> workerCallback(runId: string, input: WorkerCallbackInput): Promise<RunState> fetch(req: Request): Promise<Response | null> serve(options?: { port?: number; hostname?: string }): RunningServer stop(): Promise<void>}start and startRun#
start infers input from a definition; startRun accepts registered names. Both run a wake cycle and resolve with runId, threadId, and state. A gate or child may still be pending when either method resolves. They reject on invalid input, missing definitions, storage failures, or execution limits.
Use a stable runId and idempotencyKey when retrying creation of the same logical run. Generating a new runId on every retry creates a different run. Register all definitions before starting or spawning them.
signal, wake, and cancel#
signal validates and appends inputs, then wakes execution and returns state. Its optional idempotencyKey identifies retries of the same request within a run. wake processes pending work without appending a new domain signal. cancel records cancellation for a run or thread; it cannot undo an external action.
Read and inspect#
getRun returns folded RunState. getEvents returns recorded envelopes ordered by sequence, with optional fromSeq and limit. project folds a projection and returns its state. replayTo returns before/after state at a sequence, or null when no matching step is available; it does not execute effects.
ready initializes storage and modules. rescanTimers re-registers persisted timers on the configured scheduler. fetch returns a Response or null for unhandled paths. serve starts the Bun HTTP server. stop disposes the runtime scheduler and any server it started; it does not cancel runs or back up storage.
HTTP contract#
Put authentication and authorization ahead of every route, including event streams. JSON requests use content-type: application/json.
GET /health → { ok: true }POST /runs → { runId, threadId, state }GET /runs → { runIds } (embed only)GET /runs/summaries → { runs }GET /runs/:id → { runId, state }GET /runs/:id/events → { runId, events }POST /runs/:id/events → { runId, state }GET /runs/:id/threads → { runId, threads }GET /runs/:id/status → run, deadline, and effect statusGET /runs/:id/effects → { runId, effects }POST /runs/:id/effects/:effect/retry → operator-reviewed retryPOST /runs/:id/wake → { runId, state }GET /runs/:id/replay?seq=10 → { runId, step }GET /runs/:id/projections/:name → { runId, name, value }GET /runs/:id/events?live=true → SSEPOST /operations/deadlines/rescan → rebuild wake deadlinesPOST /runs accepts kind, definitionName, input, and optionally runId and idempotencyKey. POST /runs/:id/events accepts an events array and optionally idempotencyKey. The embed handler also recognizes the Idempotency-Key header. GET event history supports fromSeq and limit. Request the same resource with Accept: text/event-stream or live=true for SSE. Streams resume after Last-Event-ID, or begin at fromSeq when that header is absent.
curl -X POST http://localhost:8787/runs \ -H 'content-type: application/json' \ -d '{"kind":"workflow","definitionName":"release-v1","input":{"topic":"Launch"}}'Actor hosts return 501 for global GET /runs; use an application registry or shared index. The embed handler maps InvalidInputError and InvalidEventError to 400, unknown projections to 404, and other caught execution failures to 500. Routing behavior differs by host; inspect status and body. Client request helpers reject non-success responses. Cancellation is currently an embed runtime method, not a client HTTP endpoint.
Client and streaming#
createLoomsClient accepts baseUrl and an optional fetch implementation. getRun and signal resolve to objects containing state; getEvents resolves to an object containing events. subscribeEvents returns an unsubscribe function and reconnects using its last cursor. stream(definition, input) or streamRun(args) returns an async iterable with a runId for events during the initial wake cycle. A stream ending does not mean a parked workflow has finished.
The current client start/signal helpers do not expose every embed idempotency option. For retry-sensitive requests, use an application endpoint or explicit HTTP bodies/headers with stable operation identifiers. See integration.
Package modules and extension APIs#
@swirls/looms/core: defineModule, defineKind, createKind, defineEventCatalog, defineThread, defineEffect, defineProjection; invoke, spawn, wait, emit, complete, fail. The bun-sqlite entry supplies Bun storage.@swirls/looms/runtime: createLooms and lower-level runtime APIs.@swirls/looms/agent: agent, defineAgent, defineTool, asThreadTool, asAgentTool, asWorkflowTool, asEvaluatorTool, defineAgentSession, submitAgentMessage, conversation, and userMessage.@swirls/looms/workflow: workflow, defineWorkflow, graph validation, failure policies, and map, fan-out, and while helpers.@swirls/looms/approval: approval, gate, decision, pendingApprovals.@swirls/looms/evaluator: evaluator, defineEvaluator, evaluate, evaluations.@swirls/looms/actor: createActorCell and createLocalActorHost.@swirls/looms/cloudflare: LoomsDurableObject and routeToDurableObject.@swirls/looms/clientand@swirls/looms/react: HTTP clients, streams, providers, and projection hooks.@swirls/looms/ai-vercel: vercelLlm for AI SDK chat models; vercelEvaluator for evaluation models such as TypeSafe Jev.@swirls/looms/projectors: post-commit indexes and fan-out.@swirls/looms/s2: stream replication.@swirls/looms/testing: deterministic in-memory helpers and conformance checks.@swirls/looms/otel: OpenTelemetry spans and metrics for runtime observations.@swirls/looms/cliand@swirls/looms/debugger: inspection tools.
For module authoring, see custom modules. For agent options and tools, see agents. Package type declarations remain the exhaustive reference for lower-level interfaces.