Core Launchers
Node and Electron launch surfaces for starting an SNA server.
Core Launchers
Launchers are for host applications that need to start SNA as part of their own lifecycle. They hide port selection, process handling, and Electron packaging details.
| Import path | Surface | Purpose |
|---|---|---|
@sna-sdk/core/node | startSnaServer(options) | Starts SNA from a Node host. |
@sna-sdk/core/electron | startSnaServer(options) | Starts SNA from an Electron host as a forked child process. |
@sna-sdk/core/electron | startSnaServerInProcess(options) | Runs SNA in the current Electron main process. |
@sna-sdk/core/node, @sna-sdk/core/electron | resolveClaudeCli, resolveCodexCli, resolveOpenCodeCli | Finds runtime CLI installations for setup and diagnostics. |
Launcher handles expose enough information to stop the server and pass the discovered URL to @sna-sdk/client or @sna-sdk/react.
Options
dbPath is required. Other fields are optional.
type SnaServerOptions = {
port?: number;
host?: string;
appId?: string;
authToken?: string;
allowedOrigins?: string[];
dbPath: string;
cwd?: string;
maxSessions?: number;
permissionMode?: "acceptEdits" | "bypassPermissions" | "default";
model?: string;
permissionTimeoutMs?: number;
nativeBinding?: string;
env?: Record<string, string>;
readyTimeout?: number;
onLog?: (line: string) => void;
dataDir?: string;
logLevel?: "info" | "warn" | "error" | "silent";
runtimePaths?: RuntimePaths;
langfuse?: { publicKey: string; secretKey: string; baseUrl?: string };
};
type RuntimePaths = {
claudeCode?: string;
codex?: string;
opencode?: string;
grok?: string;
cursor?: string;
};| Field | Default | Description |
|---|---|---|
port | 3099 | API port passed to the server. |
host | 127.0.0.1 | Bind host. Keep loopback unless the host app has a stronger transport boundary. |
appId | sna-sdk | Owner ID for this server instance. Sessions created through the server are tagged with this value. |
authToken | generated | Bearer token required by protected HTTP routes and WebSocket upgrades. |
allowedOrigins | [] | Browser Origin values allowed to call the server. Native clients that send no Origin are allowed. |
dbPath | required | Absolute SQLite path. The launcher also derives cwd from this path when cwd is omitted. |
cwd | dirname(dbPath) | Working directory for the server process and runtime sessions. |
maxSessions | 5 | Maximum concurrent agent sessions. |
permissionMode | SDK default | Default permission mode for new agent sessions. |
model | SDK default | Default model for runtime calls. |
permissionTimeoutMs | 0 | 0 leaves permission prompts under host control; positive values auto-deny after the timeout. |
nativeBinding | auto-detected | Explicit better-sqlite3 native binding path. Use this for custom Electron builds. |
env | {} | Extra environment variables. Runtime command variables here override values generated from runtimePaths; launcher-owned values such as SNA_APP_ID, SNA_AUTH_TOKEN, SNA_HOST, and SNA_ALLOWED_ORIGINS remain controlled by launcher options. |
readyTimeout | 15000 | Milliseconds to wait for the standalone process to print the ready line. |
onLog | none | Receives stdout/stderr lines from the child process or SDK logger lines in in-process mode. |
dataDir | derived from dbPath | Base directory for image and asset storage. |
logLevel | info | Filters in-process logger output. Forked server file logs still record all levels. |
runtimePaths | auto-detect | Explicit runtime CLI commands or absolute paths. They map to SNA_CLAUDE_COMMAND, SNA_CODEX_COMMAND, SNA_OPENCODE_COMMAND, SNA_GROK_COMMAND, and SNA_CURSOR_COMMAND. |
langfuse | none | Enables tracing for sessions whose metadata opts in. |
The launcher returns both authToken and
connection: { baseUrl, authToken }. Pass connection to
SnaClient or SnaProvider instead of persisting the token or
reconstructing it from environment variables. The generated token is
owned by the server handle; rotate it by starting the server with a new
token.
Use runtimePaths when the host app has a setup screen or stores user-selected
CLI locations. env is still available as the final escape hatch and overrides
the values generated from runtimePaths. Use the typed launcher fields for
server identity, auth, bind host, and origin policy.
Forked vs in-process
| Mode | Use it when | Tradeoff |
|---|---|---|
Forked startSnaServer | You want process isolation and a standalone child server. | Requires packaged Electron apps to unpack @sna-sdk/core; readiness depends on the child process starting cleanly. |
startSnaServerInProcess | Electron fork() is unreliable because of asar paths, environment propagation, or orphaned children. | Shares the caller's Node event loop; the host must call stop() during shutdown. |
In-process mode does not spawn a default agent. The host starts sessions through HTTP, WebSocket, or the returned sessionManager.
Directly running the standalone server is a development/debugging path. Product
integrations should prefer startSnaServer() or startSnaServerInProcess() so
the token, owner identity, bind host, and shutdown lifecycle stay under the host
app's control.
Function reference
startSnaServer(options) from @sna-sdk/core/node
Starts SNA from a plain Node host and returns a handle with connection information and shutdown behavior. Use this for CLIs, desktop hosts, and local development processes.
const handle = await startSnaServer({
appId: "my-app",
dbPath: "/Users/me/Library/Application Support/MyApp/sna.db",
port: 3099,
allowedOrigins: ["http://localhost:5173"],
runtimePaths: {
claudeCode: "/opt/homebrew/bin/claude",
},
});
const client = new SnaClient(handle.connection);
handle.stop();The Node launcher reuses the same standalone server implementation as Electron. It is useful when the host wants SNA as a sibling process instead of importing the HTTP app directly.
startSnaServer(options) from @sna-sdk/core/electron
Starts SNA from an Electron host. It accounts for packaged application constraints and should be preferred over the Node launcher inside Electron main processes.
In forked mode, packaged apps should unpack the SDK files that need to be executed by Node:
// electron-builder example
asarUnpack: ["node_modules/@sna-sdk/core/**"]The launcher remaps .asar paths to .asar.unpacked, constructs NODE_PATH, resolves better-sqlite3, forwards logs, and waits until the server prints API server ready.
Returns:
type SnaServerHandle = {
process: ChildProcess;
port: number;
host: string;
appId: string;
baseUrl: string;
authToken: string;
connection: { baseUrl: string; authToken: string };
stop(): void;
};startSnaServerInProcess(options)
Runs SNA in the current Electron process. Use it only when tighter lifecycle integration is more important than process isolation.
Returns:
type InProcessSnaServerHandle = {
process: null;
port: number;
host: string;
appId: string;
baseUrl: string;
authToken: string;
connection: { baseUrl: string; authToken: string };
sessionManager: SessionManager;
httpServer: http.Server;
initLangfuse(config: { publicKey: string; secretKey: string; baseUrl?: string }): Promise<void>;
setTracerUser(userId?: string, userEmail?: string): void;
stop(): Promise<void>;
};stop() kills sessions, disposes runtimes, flushes tracing, clears the logger callback, and closes the HTTP server. Call it from the host shutdown path.
resolveClaudeCli(options?)
Finds a usable Claude Code CLI path. Use it during setup or diagnostics to explain why a runtime cannot start.
resolveCodexCli(options?)
Finds a usable Codex CLI path with the same env/cache/static/shell lookup order.
resolveOpenCodeCli(options?)
Finds a usable OpenCode CLI path with the same env/cache/static/shell lookup order.
validateClaudePath(path)
Checks whether a specific Claude CLI path is usable. Use it before saving user-provided CLI paths.
cacheClaudePath(path)
Stores a resolved Claude CLI path for later launches. Use it after a successful validation step.
parseCommandVOutput(output)
Parses shell command discovery output into a normalized path result. It is mainly useful for CLI resolution internals and diagnostics.