module.registerHooks, which landed in
that release.
Supported backends under Node
Select a backend with
--backend, the SMITHERS_BACKEND environment variable,
or backend in smithers.config.ts:
sqlite under Node fails immediately with the DB_REQUIRES_BUN_SQLITE
error, which names both fixes: switch to pglite or postgres, or run the same
command under Bun. Nothing silently downgrades.
createSmithers() is the synchronous sqlite factory, so it also requires Bun.
Author workflows with the async factory to stay portable:
Running the CLI under Node
The published bin carries a#!/usr/bin/env bun shebang, which only decides what
runs the file when you execute it directly. Invoke it with Node and Node runs it:
npx smithers and node_modules/.bin/smithers still require Bun on PATH. The
package manager installs the bin as a link to the script, so the operating
system honours its #!/usr/bin/env bun shebang and reports
env: bun: No such file or directory when Bun is missing. Call the script with
Node, as above, on a machine that has no Bun.
Every child process the CLI spawns (the detached run engine, the supervisor, the
monitor, the TUI) is launched with the runtime that is executing right now, so a
Node parent produces Node children and no bun binary has to be on PATH.
Workflow files are TypeScript and JSX. Bun transpiles them on import; Node does
not, and its built-in type stripping refuses .tsx entirely and refuses any
.ts under a node_modules directory. The CLI therefore installs an
esbuild-backed module loader before it loads anything, covering .ts, .tsx,
.jsx, and .mdx. JSX compiles with the automatic runtime, using the
@jsxImportSource pragma in the file when it has one and the nearest
tsconfig.json otherwise, which is the same choice Bun makes.
Importing the library needs no loader at all:
Known limits under Node
- The sqlite backend is unavailable, as described above.
- Gateway custom-UI bundling requires Bun.
bunx smthrs uiandbunx smthrs monitorbuild workflow-owned<UI>entries with Bun’s bundler, and report a missing Bun install rather than serving a stale bundle. Everything else the gateway serves, including the RPC and websocket control plane and the run list, works under Node. - Cross-run memory uses the main database under Node. Under Bun a Postgres or
PGlite run keeps memory in a local sqlite sidecar; under Node there is no
sqlite, so memory is routed at the run database instead.
MemoryStoreis built on a synchronous Drizzle sqlite handle, so on a Postgres-dialect database memory operations fail rather than fall back:saveNote,searchNotes,enableNoteSearch, anddeleteThreadfail loud withDB_WRITE_FAILEDorDB_QUERY_FAILED, and the portable fact/thread/message operations surface a driver error of their own. That limit already applies to a Bun run that opens the memory store on Postgres directly. Run under Bun, or on the sqlite backend, when a workflow uses cross-run memory. - The Postgres schema still carries
_smithers_memory_notesand_smithers_memory_note_supersessions; migration0043_memory_notes_postgres_stagedlabels them staged, not served so the catalog does not imply support the runtime declines to give.