Introduction
Understand SNA, boot the server, open a session, and send a first prompt.
The shortest path from zero to live events. By the end of this page you'll have an SNA server running in your app, a session attached to Claude Code (or Codex / OpenCode), and tokens streaming back over WebSocket.
Build agentic applications with SNA
SNA is a runtime layer for agentic applications: products where a long-running agent is part of the application, carries session history, uses tools, asks for permission, and streams state back to the product.
That means you can build:
- Sessionful product agents that keep project context and continue across turns instead of answering one prompt at a time.
- Cache-friendly long conversations where the app keeps sending to the same SNA session instead of reassembling history and cache settings for every turn.
- Tool-using workflows where the agent can call the same capabilities its CLI runtime already knows how to use.
- Human-in-the-loop applications with permission requests surfaced through your own UI.
- Runtime-harness-backed agents that use the orchestration layer tuned by Claude Code, Codex, or OpenCode instead of rebuilding that loop from raw model APIs.
- Multi-runtime products where the product API stays stable while the underlying agent runtime can change.
What you're about to build
SNA is a small server you embed in your app. You ask it to start a session, the server spawns an agent CLI as a managed subprocess and exposes it through one HTTP + WebSocket API. From the consumer side it looks like talking to a backend; under the hood it's a real Claude Code / Codex / OpenCode process doing the work.
your app
│
│ HTTP for control (send, interrupt, kill, …)
│ WS for events (assistant_delta, tool_use, complete, …)
▼
SNA server ──spawn──► claude | codex | opencodeFive steps below. For the why behind the design choices (canonical history, runtime swaps, attribution), read What is SNA? next.
Prerequisites
- Node.js 20+.
- At least one runtime CLI:
claude,codex, oropencodeonPATH, or an explicitruntimePathsentry when starting SNA. - A package manager. Examples below use
pnpm, but npm / yarn / bun work too.
1. Install
pnpm add @sna-sdk/core@0.17.2 @sna-sdk/client@0.17.2SNA is still in the 0.x.x line, so pin exact package versions in apps
that depend on it. See Install for the
stability note; bugs and feature requests belong in
GitHub issues.
See Install for the full prerequisite checklist plus CLI overrides.
2. Boot the server
In your app:
import { resolveClaudeCli, startSnaServer } from "@sna-sdk/core/node";
const claude = resolveClaudeCli();
const sna = await startSnaServer({
appId: "my-app",
port: 3099,
dbPath: "./data/sna.db",
runtimePaths: {
claudeCode: claude.path,
},
});This forks the SNA server as a managed child process. sna.port holds
the bound port (auto-allocated if 0), sna.connection is passed to SDK
clients, sna.appId is tagged onto sessions created by this server, and
sna.stop() sends SIGTERM.
3. Connect a client
import { SnaClient } from "@sna-sdk/client";
const client = new SnaClient(sna.connection);
client.connect();4. Open a session and start the agent
const { sessionId } = await client.sessions.create({ label: "scratch" });
await client.agent.start(sessionId, {
provider: "claude-code",
model: "claude-sonnet-4-6",
});5. Subscribe to events, then send
client.agent.onEvent(({ event }) => {
if (event.type === "assistant_delta") process.stdout.write(event.delta as string);
if (event.type === "tool_use") console.log("\n[tool]", event.message);
if (event.type === "complete") console.log("\n[done]", event.data);
});
await client.agent.subscribe(sessionId);
await client.agent.send(sessionId, "List the files in this directory.");That's the whole loop. Tokens stream into assistant_delta, tool
invocations fire tool_use, the turn finishes on complete with usage
and cost.
One-shot instead?
If you just want a single answer (no session, no events), use
completion():
import { completion } from "@sna-sdk/core";
const result = await completion({
prompt: "Summarize: ...",
provider: "claude-code",
model: "claude-haiku-4-5",
onDelta: (chunk) => process.stdout.write(chunk),
});
// result.text, result.usage, result.costUsd, result.durationMsSee Cookbook → Streaming for the three streaming flavors (in-process callback, SSE, full event stream).
Next
- What is SNA?: the conceptual deep dive.
- Embedding: run SNA inside Electron.
- Concepts: sessions, history, runtimes, permissions.