createExternalSmithersEngine() is the headless integration boundary for a
long-lived Node service. It opens the normal Smithers database and execution
engine once, lets the host construct several workflows from HostNodeJson, and
drives any number of runs before one final close().
The complete runnable example is
examples/node-embedded-engine.mjs.
Run it with plain Node:
Construct once, run many times
engine.workflow() can be called repeatedly; every returned workflow shares
the opened backend and the process-local task runtime. engine.run() waits for
one run result. A failed result rejects with a SmithersError; its cause
points at the restored run error, whose own nested causes remain available.
close() waits for this instance’s active runs, closes its backend, and closes
the process-local task runtime when the last external engine closes.
Node storage contract
Node gets the existing Postgres-dialect implementations, not a forked engine:
Smithers does not add a
node:sqlite backend here. The durable SQLite adapter,
Drizzle driver, retry behavior, and migrations currently share the synchronous
bun:sqlite contract. PGlite and Postgres already exercise the same engine
through its SQL dialect seam and are the supported Node choices.
If a legacy smithers.db contains run history, selecting PGlite/Postgres still
enforces the migration gate; migrate it instead of silently starting an empty
store.
Logging
Passlogger(record) to route structured debug, info, warn, and error
records into the host. Logger scope follows the run across awaits and timers,
so concurrent external engine instances do not overwrite one global sink. A
throwing logger is ignored and cannot fail a run. Pass logger: false to silence
engine logs. onProgress and onError run callbacks remain available for
durable events and occurrence-level error reporting.
Capability boundaries
This facade drives the same engine under Node and Bun. It does not emulate Bun-only capabilities:- Native SQLite fails with
DB_REQUIRES_BUN_SQLITEunder Node. - PTY/UI terminal hosting is not part of this headless API; use the Gateway/UI host for interactive terminals.
- Sandbox and worktree tasks still require their configured provider and local VCS/process capabilities. Existing capability checks fail with the named capability and operation when the host does not supply one.
createExternalSmithers() remains a Bun SQLite helper.
Node embedders should use the async reusable engine.
Error causes
Tagged errors crossing the process-local worker RPC now carry a JSON-safecause payload. The external engine restores serialized error objects into an
actual Error/SmithersError chain before wrapping the failed run, so ordinary
cause walking works: