Skip to main content
Smithers runs under Bun and under plain Node. Bun is the recommended runtime and the one every example assumes. Node is fully supported for the library, the CLI, and the gateway, with the backend and bundling limits listed below. Importing the library needs Node 22 or newer. The CLI needs Node 22.15 or newer, because it installs module hooks with 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:
Asking for 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 ui and bunx smthrs monitor build 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. MemoryStore is built on a synchronous Drizzle sqlite handle, so on a Postgres-dialect database memory operations fail rather than fall back: saveNote, searchNotes, enableNoteSearch, and deleteThread fail loud with DB_WRITE_FAILED or DB_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_notes and _smithers_memory_note_supersessions; migration 0043_memory_notes_postgres_staged labels them staged, not served so the catalog does not imply support the runtime declines to give.