Skip to main content
The TypeScript SDK (@rkat/sdk) is a thin wrapper over Meerkat’s settled runtime-backed contracts. It spawns a local rkat-rpc subprocess and exposes the same session lifecycle used by the CLI, REST, JSON-RPC, and MCP surfaces as TypeScript-native Session and DeferredSession handles.

Getting started

1

Install the SDK

2

Install the RPC binary

By default the SDK can also auto-resolve and download rkat-rpc for the current platform, so a manual binary install is optional unless you want to control the binary path yourself.You also need an API key for at least one LLM provider (e.g. ANTHROPIC_API_KEY).
3

Configure tsconfig

The SDK is ESM. Your tsconfig.json must use Node16 module resolution:
4

Connect and run


Method overview

MeerkatClient methods

Schedule methods parse the canonical flattened response shape: planning, timestamps, labels, and other schedule configuration are top-level fields, not a nested config, and internal machine_state is never public. Missing or malformed schedule, occurrence, and tool arrays—or required facts within their entries—throw MeerkatError with INVALID_RESPONSE instead of becoming empty or zero-valued results.

Auth wrappers

The SDK also exposes the auth-profile wrappers from the RPC surface:
  • authProfileList(...), authProfileGet(...), authProfileCreate(...), authProfileDelete(...)
  • authLoginStart(...), authLoginComplete(...), authLoginDeviceStart(...), authLoginDeviceComplete(...), authLoginProvisionApiKey(...)
  • authStatusGet(...), authLogout(...)
  • realmList(...), realmGet(...)
  • sendPeerResponseTerminal(...)
  • mcpAdd(...), mcpRemove(...), mcpReload(...)
  • getBlob(...), listSkills()
  • getRuntimeHostInfo(), getRuntimeHostCapabilities(), getRuntimeHostHealth()
Every public TypeScript RPC wrapper binds its request and response transport boundary to generated RPC-schema contracts. In 0.8.24, generated names used by the job, approval, artifact, and durable-event declarations are not re-exported from the package root; callers can pass object literals matching the displayed method signature. Approval methods maintain audit records only. Requesting or deciding a record does not automatically gate, authorize, or execute an action. See JSON-RPC approvals for persistence and single-writer details. Auth profiles and credentials are realm-scoped. Login/provisioning yields an auth binding that can be referenced by SessionOptions.authBinding or a mob member spec without placing the provider secret in that spec. Remote hosts resolve bindings only within their authorized realm.

Generated assistant images

When a session model calls the built-in generate_image tool, generated images appear in committed history as SessionAssistantBlock entries with blockType === "image". The SDK preserves imageId, blobId, mediaType, width, height, revisedPrompt, and provider metadata.
Image-generation wire contracts are exported for integrations that inspect tool results directly: WireGenerateImageRequest, WireGenerateImageExecutionPlan, WireImageGenerationToolResult, WireImageOperationPhase, and WireAssistantImageRef.

Capability methods

Session methods

Live channel helper

RealtimeChannel and the old realtime convenience helpers are no longer part of the public SDK. Use LiveChannel.session(client, session.id, options?) for a session-bound wrapper around the live/* methods. The SDK returns a discriminated transport bootstrap from live/open; callers own the WebSocket or WebRTC connection. The example below requests WebRTC explicitly. For WebSocket, connect with liveWs: true and request transport: "websocket".
@rkat/sdk is Node-only and does not provide RTCPeerConnection. Keep the peer connection in a browser or inject a Node WebRTC implementation. Add an audio track or the meerkat.live data channel, call setLocalDescription, wait for ICE gathering to complete, then forward peer.localDescription.sdp to the Node process. Install the returned answer as the browser peer’s remote description. A media-less or pre-ICE SDP cannot establish the live channel.
The 0.8.24 answerLiveWebrtcOffer(...) convenience helper does not wait for ICE gathering and sends the original createOffer() SDP instead of the final local description. Use the direct client.liveWebrtcAnswer(...) exchange above for the canonical browser flow until the helper is fixed.
liveWebrtc: true passes the --live-webrtc process flag, which exists only when rkat-rpc was compiled with its non-default live-webrtc Cargo feature. The 0.8.24 release binary and a normal default-feature build do not include that flag. From the Meerkat repository, build an explicit binary with ./scripts/repo-cargo build -p meerkat-rpc --features live-webrtc, then put it on PATH or pass its path to new MeerkatClient(path).
Image keys are required, caller-stable, and session-scoped. See Live Channels for same-key replay, conflict handling, and reconnect hydration limits. seedMaxChars maps to live/open.seed_max_chars. Use a positive value to bound serialized seed messages and request a core-selected whole-turn suffix; omit it for the complete canonical seed. Every ordered System message must fit; an existing compaction summary may be retained, and any truncation reports degraded continuity. Canonical image identity, tombstone, and accounting sidecars remain complete. The server rejects zero.

Mob methods

Multi-host placement and host/grant mutation are trusted JSON-RPC operator surfaces, not agent-callable mob tools. Agent-callable spawn also cannot carry the Rust-only resume_from_role one-shot durable role-migration declaration.

MeerkatClient

Constructor

Defaults to searching $PATH for rkat-rpc. If not found, automatically downloads the correct binary for the current platform and caches it in ~/.cache/meerkat/bin/rkat-rpc. Pass an explicit path or set MEERKAT_BIN_PATH to override.

connect()

Spawns rkat-rpc, performs initialize handshake, checks contract version compatibility, and fetches capabilities. Returns this for chaining.
realmId and isolated are mutually exclusive. If realmId is omitted and isolated is not set, the spawned rkat-rpc process uses its normal isolated-mode default rather than a shared default realm. Reuse realmId explicitly to share sessions and config across processes or surfaces. Set liveWs: true for the WebSocket live adapter; the SDK starts rkat-rpc with an ephemeral listener and live/open returns its URL/token bootstrap. Set liveWebrtc: true for the WebRTC bootstrap/SDP-answer path, using a binary built with the non-default meerkat-rpc/live-webrtc feature. When both are enabled, select the requested transport through LiveChannelOptions.transport.

createSession()

Creates a new session, runs the first turn with prompt, and returns a Session object. The Session holds the last RunResult and exposes convenience accessors for the most recent text, usage, and tool call counts.

createSessionStreaming()

Creates a new session and returns an EventStream for the first turn. Iterate the stream to receive typed events as they arrive. The final RunResult is available on stream.result after iteration completes.

SessionOptions

All fields are camelCase:
createDeferredSession(...) reuses SessionOptions, but the server rejects transientTurnContext when no immediate turn exists. The current TypeScript DeferredTurnOptions also does not expose transientTurnContext, injectedContext, or selfHostedServerId: set injected context on deferred creation, and use startTurn(...) or stream(...) only with skillRefs, turnToolOverlay, additionalInstructions, keepAlive, model, provider, maxTokens, systemPrompt, outputSchema, structuredOutputRetries, and providerParams. Transient first-turn context and a self-hosted server route are not expressible through the current deferred TypeScript wrapper.

Session

createSession() resolves to a Session object that acts as the handle for subsequent turns on the same conversation. createSessionStreaming() instead returns an EventStream: after consumption, stream.result is the final RunResult and stream.sessionId is the created session’s identity. The stream does not construct a Session wrapper or expose its methods. Both creation paths use the canonical runtime session lifecycle.

Identity

Last-result shortcuts

These accessors always reflect the most recent completed turn:
session.usage is the cumulative token account for the whole session to date, not the last turn’s usage, and it keeps growing across turns. Never add successive readings together. See Usage accounting.

turn()

Sends another turn to the session and returns the RunResult. Also updates the session’s last-result shortcuts.

stream()

Sends another turn and returns an EventStream, whose iterator is typed as AsyncIterable<StreamEvent>. The session’s last-result shortcuts are updated when iteration completes.
Injected context is durable ordered user-channel context immediately before the prompt. transientTurnContext carries request-only host facts and is not a transcript message.

interrupt()

Sends turn/interrupt for this session. Has no effect if no turn is running.

archive()

Removes this session from the server. The Session object should not be used after calling archive().

invokeSkill()

Calls requireCapability("skills"), then runs a turn with the provided structured SkillKey injected. Discover an installed active skill first; names alone need not be unique across sources:
listSkills() returns generated wire-shaped keys; invocation maps key.source_uuid and key.skill_name to sourceUuid and skillName.

send() and peers()

Scope comms operations to this session. Requires the comms capability. Directory entries retain wire-shaped fields, including peer_id and sendable_kinds. Display names are not routing identities and may collide: select the intended sendable peer and send to its peer_id.

subscribeEvents()

Open a standalone event subscription for this session. Returns an async-iterable EventSubscription that yields typed AgentEventEnvelope objects.

Capabilities

Capabilities are fetched automatically during connect(). Use them to guard code paths that depend on optional features.

Config management

getConfig() returns a generated ConfigEnvelope; writes return ConfigWriteResult. These preserve optional nullable snake_case metadata (realm_id, instance_id, backend, resolved_paths, and, for writes, live_propagation). The config field is unknown, not a typed settings object. Patch known fields without spreading it, and print the returned value directly or validate it before reading properties.

Examples


See also