SNA

Client agent namespace

Method-by-method usage reference for client.agent.

Client agent namespace

client.agent is the main control surface for a running coding agent. This page documents every public method with its call shape, input, return value, and usage notes.

Lifecycle methods

agent.start(session, config?)

Signature

await client.agent.start(session: string, config?: AgentStartConfig): Promise<{
  status: "started" | "already_running";
  provider: string;
  sessionId: string;
}>

Input

FieldTypeRequiredDescription
sessionstringyesTarget SNA session ID. The server auto-creates it if it does not exist.
config.providerstringnoRuntime id such as claude-code, codex, opencode, grok, or cursor.
config.modelProviderstringnoAttribution metadata for the model vendor. Stored on assistant-authored canonical rows.
config.promptstringnoInitial prompt sent immediately after startup.
config.modelstringnoRuntime model slug.
config.permissionModestringnoPermission behavior, for example acceptEdits or bypassPermissions.
config.configDirstringnoRuntime config directory override. Claude uses CLAUDE_CONFIG_DIR; Codex uses CODEX_HOME.
config.forcebooleannoKill an existing runtime and start fresh.
config.cwdstringnoWorking directory for this runtime.
config.historyunknown[]noRuntime-neutral history to resume from.
config.systemPromptstringnoReplaces the base system prompt.
config.appendSystemPromptstringnoAppends text to the system prompt.
config.allowedToolsstring[]noRestricts the agent to these tools.
config.disallowedToolsstring[]noBlocks specific tools.
config.mcpServersRecord<string, unknown>noMCP servers made available to the agent.
config.reasoningLevel`012
config.providerOptionsRecord<string, unknown>noRuntime-specific options, such as Codex serviceTier, profile, and config.
config.extraArgsstring[]noDeprecated raw CLI flags. Prefer typed fields.

For Codex, providerOptions can include serviceTier, profile, and config. profile maps to --profile <name>, while config is passed as repeatable -c key=value overrides on both codex app-server and codex exec.

Returns

FieldDescription
statusstarted when a process was spawned, already_running when the session already had a runtime.
providerRuntime used.
sessionIdRuntime session ID.

Example

const started = await client.agent.start("default", {
  provider: "claude-code",
  model: "claude-sonnet-4-6",
  permissionMode: "acceptEdits",
  cwd: "/Users/me/project",
  reasoningLevel: 3,
});

Notes

  • With HTTP enabled, the promise resolves after the process has been spawned.
  • It does not guarantee the runtime init handshake has reached an idle state. If the UI must wait for readiness, call getStatus until agentStatus === "idle".
  • Calling send immediately after start is safe in normal usage because stdin queues the message.

agent.send(session, message, opts?)

Signature

await client.agent.send(
  session: string,
  message: string,
  opts?: { images?: Array<{ base64: string; mimeType: string }>; meta?: Record<string, unknown> },
): Promise<{ status: "sent" }>

Input

FieldTypeRequiredDescription
sessionstringyesRunning session ID.
messagestringyesUser message to send to the agent.
opts.images{ base64: string; mimeType: string }[]noImage attachments for runtimes that support multimodal input.
opts.metaRecord<string, unknown>noExtra metadata stored with the user message.

Returns

{ status: "sent" } after the message has been accepted. With HTTP enabled, the message has also been persisted before the promise resolves.

Example

await client.agent.send("default", "Please inspect the failing test.");
await client.agent.send("default", "What is in this screenshot?", {
  images: [{ base64: pngBase64, mimeType: "image/png" }],
});

Notes

  • Use this only for stateful interactive sessions.
  • For a stateless one-shot task, use runOnce or runOnceStream.

agent.kill(session)

Signature

await client.agent.kill(session: string): Promise<{ status: "killed" | "no_session" }>

Input: session is the session ID whose agent process should be terminated.

Returns: killed if a runtime was stopped, no_session if the session does not exist.

Example

await client.agent.kill("default");

Notes: The session record remains. Only the running process is terminated.

agent.restart(session, config?)

Signature

await client.agent.restart(session: string, config?: Partial<AgentStartConfig>): Promise<{
  status: "restarted";
  provider: string;
  sessionId: string;
}>

Input: same config shape as start, but every field is optional.

Returns: runtime id and new runtime session ID after restart.

Example

await client.agent.restart("default", { model: "claude-opus-4-6" });

Notes: Use this after changing runtime-level settings or when the CLI process becomes unhealthy.

agent.interrupt(session)

Signature

await client.agent.interrupt(session: string): Promise<{ status: "interrupted" | "no_session" }>

Use it when a user presses a stop button and the session should stay alive for the next message.

Example

await client.agent.interrupt("default");
await client.agent.send("default", "Try a simpler approach.");

agent.resume(session, opts?)

Signature

await client.agent.resume(session: string, opts?: {
  provider?: string;
  model?: string;
  permissionMode?: string;
  configDir?: string;
  prompt?: string;
  extraArgs?: string[];
  providerOptions?: Record<string, unknown>;
}): Promise<{
  status: "resumed";
  provider: string;
  sessionId: string;
  historyCount: number;
}>

Input

FieldDescription
sessionSession to resume from stored history.
opts.providerRuntime override.
opts.modelModel override.
opts.permissionModePermission mode override.
opts.configDirRuntime config directory override.
opts.promptOptional prompt sent during resume.
opts.providerOptionsRuntime-specific options.

Returns

FieldDescription
statusAlways resumed on success.
providerRuntime used for the resumed session.
sessionIdRuntime session ID.
historyCountNumber of persisted messages loaded.

Example

const resumed = await client.agent.resume("default", { provider: "codex" });
console.log(resumed.historyCount);

agent.getStatus(session)

Signature

await client.agent.getStatus(session: string): Promise<{
  alive: boolean;
  agentStatus: "idle" | "busy" | "disconnected";
  sessionId: string | null;
  ccSessionId: string | null;
  eventCount: number;
  messageCount: number;
  lastMessage: { actor: string; kind: string; content: string; created_at: string } | null;
  config: { provider: string; model: string; permissionMode: string; extraArgs?: string[] } | null;
}>

Use it when rendering controls that depend on runtime state or when waiting after start.

Example

const status = await client.agent.getStatus("default");
if (status.alive && status.agentStatus === "idle") {
  await client.agent.send("default", "Next task");
}

One-shot and completion methods

agent.completion(opts)

Signature

await client.agent.completion(opts: CompletionOptions): Promise<CompletionResult>

Input

FieldTypeRequiredDescription
promptstringyesPrompt to send.
modelstringnoModel slug.
systemPromptstringnoReplaces system prompt.
appendSystemPromptstringnoAppends to system prompt.
labelstringnoTrace label.
timeoutnumbernoTimeout in milliseconds.
extraArgsstring[]noDeprecated raw CLI flags.
envRecord<string, string>noEnvironment overrides.
reasoningLevel`012
providerOptionsRecord<string, unknown>noRuntime-specific options.

Returns

FieldTypeDescription
textstringGenerated text.
usage.inputTokensnumberInput token count.
usage.outputTokensnumberOutput token count.
usage.cacheReadTokensnumberCache read token count.
usage.cacheCreationTokensnumberCache creation token count.
costUsdnumberEstimated cost in USD.
durationMsnumberTotal duration.
durationApiMsnumberRuntime API duration.
modelstringModel used.

Example

const result = await client.agent.completion({
  prompt: "Summarize this changelog.",
  model: "claude-haiku-4-5-20251001",
  label: "summary",
});
console.log(result.text, result.costUsd);

Use completion instead of runOnce when the task does not need an agent session, tools, or event streaming.

agent.runOnce(opts)

Signature

await client.agent.runOnce(opts: RunOnceOptions): Promise<{
  result: string;
  usage: Record<string, unknown> | null;
}>

Input

FieldTypeRequiredDescription
messagestringyesTask prompt.
modelstringnoModel slug.
systemPromptstringnoReplaces system prompt.
appendSystemPromptstringnoAppends to system prompt.
permissionModestringnoPermission behavior.
cwdstringnoWorking directory.
timeoutnumbernoTimeout in milliseconds.
providerstringnoRuntime id.
extraArgsstring[]noDeprecated raw CLI flags.
reasoningLevel`012
providerOptionsRecord<string, unknown>noRuntime-specific options.

Example

const { result } = await client.agent.runOnce({
  provider: "claude-code",
  message: "Find the most likely cause of the failing build.",
  cwd: process.cwd(),
  timeout: 60_000,
});

Notes: The server creates a temporary session, waits for completion, and cleans it up.

agent.runOnceStream(opts)

Signature

for await (const event of client.agent.runOnceStream(opts: RunOnceOptions)) {
  // event is Record<string, unknown>
}

Returns: an AsyncGenerator<Record<string, unknown>> of SSE events.

Example

for await (const event of client.agent.runOnceStream({ message: "Explain this file." })) {
  if (event.type === "assistant_delta") process.stdout.write(String(event.delta ?? ""));
  if (event.type === "complete") break;
}

Notes: Requires http: true; it uses POST /agent/run-once/stream.

Model and configuration methods

agent.listModels(runtime, config?)

Signature

await client.agent.listModels(runtime: string, config?: ListModelsConfig): Promise<ListModelsResult>

Input

FieldTypeDescription
runtimestringRuntime to inspect, for example claude-code, codex, opencode, grok, or cursor.
config.cliPathstringRuntime CLI path override for model listing only. Use launcher runtimePaths for agent spawn paths.
config.refreshbooleanBypass cache.

Returns

type ListModelsResult = {
  models: Array<{
    id: string;
    label: string;
    provider: string;
    source: "static" | "api" | "cli";
    contextWindow?: number;
    deprecated?: boolean;
    notes?: string;
  }>;
  source: "static" | "api" | "cli" | "mixed";
  fetchedAt: number;
  error?: string;
};

Example

const catalog = await client.agent.listModels("opencode", { refresh: true });
if (catalog.error) console.warn(catalog.error);

agent.setModel(session, model)

Signature

await client.agent.setModel(session: string, model: string): Promise<{
  status: "updated" | "no_session";
  model: string;
}>

Example

await client.agent.setModel("default", "claude-opus-4-6");

agent.setPermissionMode(session, permissionMode)

Signature

await client.agent.setPermissionMode(session: string, permissionMode: string): Promise<{
  status: "updated" | "no_session";
  permissionMode: string;
}>

Example

await client.agent.setPermissionMode("default", "acceptEdits");

agent.update(session, patch)

Signature

await client.agent.update(
  session: string,
  patch: { cwd?: string; model?: string; permissionMode?: string },
): Promise<{
  status: "updated";
  applied: "in-place" | "respawn";
  runtimeId: string;
  fields: string[];
}>

Example

const updated = await client.agent.update("default", {
  cwd: "/Users/me/other-project",
  model: "gpt-5.5",
});
console.log(updated.applied); // "in-place" or "respawn"

Notes: Some runtimes can apply changes in place. Others require a respawn with DB-backed history replay.

Event streaming methods

agent.streamEvents(session, since?)

Signature

for await (const event of client.agent.streamEvents(session: string, since?: number)) {
  // event is Record<string, unknown>
}

Use it when you want SSE instead of WebSocket. Requires http: true.

agent.subscribe(session, opts?)

Signature

await client.agent.subscribe(session: string, opts?: {
  since?: number;
  includeHistory?: boolean;
  tail?: number;
}): Promise<{ cursor: number; oldestCursor?: number; hasMore: boolean }>

Input

FieldDescription
sinceStart from this event cursor.
includeHistoryReplay persisted history as events.
tailReplay only the last N persisted messages. Mutually exclusive with since and includeHistory.

Example

client.agent.onEvent(({ session, cursor, event, isHistory }) => {
  if (!isHistory) renderEvent(session, cursor, event);
});
const sub = await client.agent.subscribe("default", { tail: 20 });

agent.getMessages(session, opts?)

Signature

await client.agent.getMessages(session: string, opts?: {
  before?: number;
  limit?: number;
}): Promise<{
  events: Array<{ cursor: number; event: Record<string, unknown> }>;
  oldestCursor?: number;
  hasMore: boolean;
}>

Use it when implementing reverse pagination for older persisted messages.

agent.unsubscribe(session)

Signature

await client.agent.unsubscribe(session: string): Promise<void>

Notes: Also removes the session from reconnect resubscription state.

agent.onEvent(handler)

Signature

const unsubscribe = client.agent.onEvent((event: {
  session: string;
  cursor: number;
  event: Record<string, unknown>;
  isHistory?: boolean;
}) => void);

Common event types

TypeMeaning
thinkingAgent internal reasoning block.
thinking_deltaStreaming reasoning fragment.
assistantAssistant-visible response block.
assistant_deltaStreaming text fragment.
tool_useAgent is calling a tool.
tool_use_deltaStreaming tool-input fragment when the runtime exposes one.
tool_resultTool execution result.
permission_neededRuntime is waiting for an approval decision.
completeTurn completed.
interruptedTurn was interrupted before normal completion.
errorRuntime error.
user_messageEchoed user message for multi-client sync.

Permission methods

agent.subscribePermissions()

Signature

await client.agent.subscribePermissions(): Promise<{ pendingCount: number }>

Use it when the UI needs to receive tool approval prompts. Subscribe before starting an agent if the first permission prompt must not be missed.

agent.unsubscribePermissions()

Signature

await client.agent.unsubscribePermissions(): Promise<void>

agent.getPendingPermissions(session?)

Signature

await client.agent.getPendingPermissions(session?: string): Promise<{
  pending: Array<{
    sessionId: string;
    request: Record<string, unknown>;
    createdAt: number;
  }>;
}>

Use it when reconnecting a UI and recovering prompts that arrived while disconnected.

agent.respondPermission(session, approved)

Signature

await client.agent.respondPermission(
  session: string,
  approved: boolean,
): Promise<{ status: "approved" | "denied" }>

Example

client.agent.onPermissionRequest(({ session, request }) => {
  const safe = request.tool === "Edit";
  client.agent.respondPermission(session, safe);
});

agent.onPermissionRequest(handler)

Signature

const unsubscribe = client.agent.onPermissionRequest((event: {
  session: string;
  request: Record<string, unknown>;
  createdAt: number;
  isHistory?: boolean;
}) => void);

Use it when opening a modal, notification, or command palette prompt for human approval.

On this page