Node SDK

The libfx package embeds the fx agent in a Node application. It runs as a native Node addon and falls back to WebAssembly when no compatible addon is available.

Install

npm install libfx

libfx requires Node 20 or later and has no dependencies.1

The SDK is early and changes with each fx release. The changelog records what each release adds or changes.

Choose an entry point

ImportEnvironmentLoads
libfxNode or browserResolves to the entry point for the current environment
libfx/nodeNodeNative addon first, WebAssembly fallback
libfx/browserBrowserWebAssembly
libfx/wasmNode or browserThe WebAssembly host layer directly

Every entry point exports createFxAgent(), createFxTerminal(), and supportsJspi(), along with the xterm.js helpers the WebAssembly SDK uses.

Choose a backend

The native addon implements only the agent core, so createFxAgent() runs natively while createFxTerminal() runs on WebAssembly and needs JavaScript Promise Integration (JSPI), even in the same Node process.

Callautonative
createFxAgent()Native addonNative addon
createFxTerminal()WebAssemblyFails

A backend of wasm runs WebAssembly for both calls, and every WebAssembly path needs JSPI.

backend defaults to auto, which prefers a compatible addon and falls back to WebAssembly. Set it when you would rather fail than run on the backend you did not plan for:

import { createFxAgent } from 'libfx'

const agent = await createFxAgent({ backend: 'native' })

The loader checks libfx.node first, then libfx.<platform>-<arch>.node. The package ships addons for linux-x64, linux-arm64, darwin-x64, and darwin-arm64. Windows has no packaged addon, so Node on Windows uses WebAssembly.

The unsuffixed libfx.node is the slot for an addon you build yourself. Pass one directly with the nativeAddon option, which accepts a module, a path, or a URL.

Handle a missing backend

Two error codes cover every failure to start.

LIBFX_JSPI_REQUIRED means no addon loaded and the runtime has no JSPI either. Run Node with --experimental-wasm-jspi, or install a package carrying an addon for your platform.

LIBFX_NATIVE_UNAVAILABLE means you asked for backend: 'native' on a call the addon does not implement, which today is createFxTerminal(). Use auto, or switch to createFxAgent().

Call supportsJspi() before choosing the WebAssembly backend rather than checking the Node version.

Run a headless agent

import { createFxAgent } from 'libfx'

const agent = await createFxAgent({
  env: {
    AI_GATEWAY_API_KEY: process.env.AI_GATEWAY_API_KEY,
  },
  onEvent(event) {
    console.log(event.type)
  },
  async onPermission(request) {
    return request.options[0].optionId
  },
})

const session = await agent.createSession()
const turn = session.prompt('Review this schema for naming consistency: ...')

for await (const update of turn) {
  console.log(update)
}

await agent.close()

The package README documents the full agent and session API, including openSession() and listSessions() for stored conversations, and setModel(), setMode(), and setConfigOption() for changing a session while it runs.

Each session runs one prompt at a time. Cancel a turn directly or with an AbortSignal:

const controller = new AbortController()
const turn = session.prompt('Wait for more instructions.', {
  signal: controller.signal,
})

controller.abort()
console.log(await turn.stopReason) // "cancelled"

What the embedded agent can do

The embedded agent advertises no tools to the model. It cannot read files, run commands, start background processes, reach Model Context Protocol servers, or open the native secret store. A prompt returns text, and any capability beyond that comes from your host.

The embedded core is not the CLI

The empty tool set is a security boundary. Running inside your process does not grant the agent the authority the fx command line has.

The same boundary sets three more limits:

  • Models come through Vercel AI Gateway only. The Codex and Grok providers are unavailable.
  • There is no automatic permission reviewer. onPermission decides every request.
  • The modes a session reports, including code, do not change the empty tool set.

The runtime also caps values the command line leaves configurable: 64 agent steps per turn, 64 KiB per tool result, 100 turns of history, and no Gateway retries.

Supply host adapters

The native and WebAssembly backends share one JavaScript host layer, so a Node host passes the same options a browser host does:

OptionPurpose
envSupplies runtime configuration without touching process globals
fetchRoutes Gateway requests through your own client
onEventReceives runtime, ACP, terminal, and lifecycle events
onPermissionResolves permission requests
configStorePersists accepted model and mode settings
sessionStorePersists conversations

Browser integration carries the method-level contract for configStore and sessionStore. The adapters it marks as terminal-only, including the browser workspace and device login, have no effect on a Node agent.

Security boundaries

Treat nativeAddon and env.FX_GATEWAY_CHAT_URL as trusted configuration that your application sets. Neither should ever carry a value that arrived in a request, a tenant record, or user input, because both decide what code runs and where credentials go.

The native backend sends production credentials to the canonical Vercel AI Gateway endpoint. A custom FX_GATEWAY_CHAT_URL is accepted only as an explicit loopback HTTP address, which keeps local development possible without opening a path to an arbitrary host.

Footnotes

  1. Due to npm limitations, one package carries the native addons for all four platforms along with both WebAssembly builds, so it unpacks to about 37 MB.