The device runtime
runHost drives the whole device side: resolve credentials (enrol on first run), dial OUT to the
server, subscribe to this device's command stream, and run dispatched tool calls — reconnecting with
capped backoff. Nothing listens on the machine; the binary only ever connects out.
import { , } from "@tikab-interactive/fusion-ai-host";
await ({
: "https://pulsn.internal", // the PulsN base URL
: , // the tools this host exposes
: ["/Users/me"], // allowed roots (defaults to the home dir)
: .., // pairing code, first run only
: "Workstation A", // a human label for the device
});Every option, straight from the type:
export interface RunHostOptions {
/** Base URL of the PulsN server, e.g. `https://pulsn.internal`. */
server: string;
/** The tools this host exposes (built-ins plus any domain tools). */
tools: AnyLocalTool[];
/** Allowed root directories. Defaults to the user's home directory. */
roots?: string[];
/** Pairing code for first-run enrollment. Falls back to `FUSION_HOST_CODE`. */
code?: string;
/** Human label for this device (defaults to the OS hostname). */
name?: string;
/** Log sink (defaults to stdout). */
log?: (msg: string) => void;
}Enrollment
The CLI does not log in with a password. A signed-in user mints a one-time pairing code; the device
exchanges it (POST /api/host/enroll) for a durable per-device token bound to a server-issued
device_id — a copied binary can't claim another machine's id. The credentials are cached locally
(keyed by server origin) so subsequent runs reconnect with no code.
v1 token storage. The token is cached in a
0600file under~/.fusion-host/. The OS secret store (Keychain / DPAPI) is the end state — a native module inside a compiled binary is a packaging step still to be taken.
The dispatch loop
Once connected, each call frame on the stream is matched to a local tool, its input is validated
against the tool's zod schema, and it runs — a read/action executes immediately, a mutation returns its
plan() proposal unless the call is in apply mode (see Tools → Propose / apply). A throw is
caught and returned as an error result; the loop never crashes. A dropped connection reconnects with
capped backoff.
Packaging & signing
Compile one self-contained binary per OS — no Bun/Node install on the target:
bun build --compile --minify --target=bun-windows-x64 ./host.ts --outfile fusion-host.exe
bun build --compile --minify --target=bun-darwin-arm64 ./host.ts --outfile fusion-hostWhat's "locked down" on a modern OS is the privacy / anti-malware trust layer, which gates even the owner's own files when the app is untrusted — a freshly compiled, unsigned binary is the textbook case:
- macOS — Gatekeeper blocks unsigned/un-notarized binaries; Apple Silicon requires a signature or
the kernel kills the process. Sign ad-hoc for local use (
codesign -s -, after clearing thecom.apple.provenancexattr), or with a Developer ID + notarization to distribute. Bun's JIT needsallow-jitentitlements. - Windows (the primary target) — an unsigned
.exeruns (with a SmartScreen warning) rather than being hard-killed; managed fleets additionally need an AppLocker/WDAC allowlist entry. Sign on Windows; you can't notarize a cross-compiled.exefrom macOS.
This is deployment work, not code — Intune/Jamf pushing the binary, the signing cert, and (for managed fleets) the allowlist and a Full-Disk-Access profile.