Skip to main content
Serve mode starts a Hono-based HTTP server alongside a running workflow. Every route operates on the single active run, with no workflow path or run ID in requests.
API reference: Server & Gateway lists every server and gateway export, its options, and links to source and tests.

CLI

bunx smithers-orchestrator up workflow.tsx --serve --port 3000 --host 0.0.0.0
FlagDefaultDescription
--servefalseEnable HTTP server mode
--port7331TCP port
--host127.0.0.1Bind address
--auth-tokenSMITHERS_API_KEY envBearer token for auth
--metricstrueExpose /metrics Prometheus endpoint
The process stays alive after the workflow completes so final state remains queryable. Ctrl+C stops both the server and the workflow. Detached mode:
bunx smithers-orchestrator up workflow.tsx --serve --port 8080 -d

Programmatic

import { SmithersDb, createServeApp } from "smithers-orchestrator";

const adapter = new SmithersDb(workflow.db);
const abort = new AbortController();

const app = createServeApp({
  workflow,
  adapter,
  runId,
  abort,
  authToken: "sk-secret",
});

Bun.serve({ port: 3000, fetch: app.fetch });
createServeApp returns a standard Hono app. Mount it with Bun.serve, pass it to another Hono app via app.route(), or use app.fetch in tests.

ServeOptions

type ServeOptions = {
  workflow: SmithersWorkflow<unknown>;   // loaded workflow instance
  adapter: SmithersDb;               // Smithers DB adapter; e.g. new SmithersDb(workflow.db)
  runId: string;                     // active run ID
  abort: AbortController;            // shared cancellation controller
  authToken?: string;                // bearer token; falls back to SMITHERS_API_KEY; disabled if unset
  metrics?: boolean;                 // expose /metrics; default true
};

Authentication

When authToken is configured, every route except /health requires:
  • Authorization: Bearer <token>, or
  • x-smithers-key: <token>
Missing or invalid tokens receive 401.

Routes

GET /health

Returns 200 regardless of auth.
{ "ok": true }

GET /

Run status and node summary.
{
  "runId": "run-1234",
  "workflowName": "bugfix",
  "status": "running",
  "startedAtMs": 1707500000000,
  "finishedAtMs": null,
  "summary": { "finished": 3, "in-progress": 1, "pending": 2 }
}

GET /events

SSE stream of lifecycle events. Same format as the multi-workflow server.
ParameterTypeDefaultDescription
afterSeqnumber-1Only events after this sequence
event: smithers
data: {"type":"NodeStarted","runId":"run-1234","nodeId":"analyze","iteration":0,"attempt":1}
id: 1

event: smithers
data: {"type":"NodeFinished","runId":"run-1234","nodeId":"analyze","iteration":0,"attempt":1}
id: 2
  • Polls every 500ms.
  • Auto-closes when the run reaches a terminal state.
  • Reconnect with ?afterSeq=N to resume from a known position.

GET /frames

Rendered workflow frames.
ParameterTypeDefaultDescription
limitnumber50Max frames
afterFrameNonumber-Frames after this number

POST /approve/:nodeId

Approve a pending approval gate. All fields optional. Returns { "runId": "run-1234" }.
{
  "iteration": 0,
  "note": "Looks good",
  "decidedBy": "alice"
}

POST /deny/:nodeId

Deny a pending approval gate. Same body as /approve/:nodeId.

POST /cancel

Cancel the running workflow.
StatusCodeCondition
200-Cancelled successfully
409RUN_NOT_ACTIVERun is not actively running (e.g. already finished, failed, cancelled, continued, or its heartbeat has gone stale)
Note: Runs in waiting-approval or waiting-timer state are cancelled immediately and return 200.

GET /metrics

Prometheus text exposition. Same metrics as the multi-workflow server.

Error Format

{
  "error": {
    "code": "ERROR_CODE",
    "message": "Human-readable description"
  }
}
Unknown routes return 404 with code NOT_FOUND.

Serve Mode vs Multi-Workflow Server

Serve modeMulti-workflow server
ScopeSingle workflow, single runAny workflow, multiple concurrent runs
Startbunx smithers-orchestrator up --serve or createServeApp()startServer()
Routes/, /events, /approve/:nodeId, …/v1/runs, /v1/runs/:runId, …
FrameworkHonoNode.js http
Use caseDevelopment, single-purpose servicesProduction API gateway

Example

# Start a workflow with serve mode
bunx smithers-orchestrator up workflow.tsx --serve --port 8080 --auth-token sk-secret

# Status
curl http://localhost:8080/ -H "Authorization: Bearer sk-secret"

# Stream events
curl -N http://localhost:8080/events -H "Authorization: Bearer sk-secret"

# Approve
curl -X POST http://localhost:8080/approve/deploy \
  -H "Authorization: Bearer sk-secret" \
  -H "Content-Type: application/json" \
  -d '{"note": "Ship it", "decidedBy": "alice"}'

# Health (no auth)
curl http://localhost:8080/health