npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@rkat/sdk

v0.8.29

Published

TypeScript SDK for Meerkat agent runtime

Readme

Meerkat TypeScript SDK

TypeScript client for the Meerkat runtime. The SDK is a thin session-first wrapper over the same runtime-backed contracts used by the CLI, REST, JSON-RPC, and MCP surfaces. It communicates with a local rkat-rpc subprocess over JSON-RPC 2.0 (newline-delimited JSON on stdin/stdout).

Current contract version: 0.8.24.

Installation

npm install @rkat/sdk

Prerequisites

  • rkat-rpc binary on PATH -- build the Meerkat repo through make build, then ensure the resulting rkat-rpc binary is in your $PATH. The SDK can also resolve and download a release binary automatically.
  • Node.js >= 18 (uses node:child_process, node:readline, node:test).
  • API key for at least one LLM provider set in your environment (e.g. ANTHROPIC_API_KEY, OPENAI_API_KEY, or GOOGLE_API_KEY).

tsconfig Requirements

The SDK is published as ESM ("type": "module" in package.json). Your project's tsconfig.json must use Node16 module resolution:

{
  "compilerOptions": {
    "target": "ES2022",
    "module": "Node16",
    "moduleResolution": "Node16",
    "lib": ["ES2022"],
    "strict": true,
    "esModuleInterop": true
  }
}

Quick Start

import { MeerkatClient } from "@rkat/sdk";

const client = new MeerkatClient();

// Connect spawns `rkat-rpc`, performs the initialize handshake,
// and fetches runtime capabilities.
await client.connect();

// Create a session (runs the first turn immediately).
const session = await client.createSession("What is the capital of Sweden?");

console.log(session.text);      // "Stockholm..."
console.log(session.id);        // UUID of the new session
console.log(session.usage);     // { inputTokens, outputTokens, ... }

// Multi-turn: send a follow-up in the same session.
const followUp = await session.turn("And what is its population?");
console.log(followUp.text);

// Clean up.
await session.archive();
await client.close();

API Reference: MeerkatClient

Constructor

new MeerkatClient(rkatPath?: string)

| Parameter | Type | Default | Description | |-----------|------|---------|-------------| | rkatPath | string | "rkat-rpc" | Path to the RPC binary. |

connect()

async connect(options?: ConnectOptions): Promise<this>

Spawns rkat-rpc as a child process, performs the initialize handshake, checks contract version compatibility, and fetches runtime capabilities via capabilities/get. Returns this for chaining. Pass { liveWs: true } only for WebSocket live-adapter flows that need live/*; it requires a configured live provider. WebRTC uses { liveWebrtc: true } and a binary compiled with the non-default meerkat-rpc/live-webrtc Cargo feature.

Throws MeerkatError with code "VERSION_MISMATCH" if the server's contract version is incompatible with the SDK's CONTRACT_VERSION.

close()

async close(): Promise<void>

Kills the rkat-rpc subprocess and cleans up resources.

createSession(prompt, options?)

async createSession(
  prompt: string | ContentBlock[],
  options?: SessionOptions,
): Promise<Session>

Creates a new session and immediately runs the first turn with the given prompt. Returns a runtime-backed Session wrapper whose lastResult tracks the latest RunResult and whose methods (turn, stream, history, archive) stay aligned with canonical backend semantics.

Parameters:

| Parameter | Type | Default | Description | |-----------|------|---------|-------------| | prompt | string \| ContentBlock[] | (required) | The user prompt for the first turn. | | options.injectedContext | readonly ContentInput[] | undefined | Ordered durable host-attached context immediately before the prompt. | | options.transientTurnContext | string | undefined | Request-only host facts for the first turn. | | options.model | string | Server/config default | LLM model name (e.g. "gpt-5.5", "gemini-3.5-flash", "claude-opus-4-8"). | | options.provider | string | Resolved from the model registry | Force a specific provider ("anthropic", "openai", "gemini"). | | options.authBinding | WireAuthBindingRef | undefined | Resolve credentials through an explicit realm binding. | | options.systemPrompt | string \| { action: "disable" } | undefined | Override or explicitly disable inherited system prompts. | | options.maxTokens | number | undefined | Maximum output tokens for the LLM response. | | options.outputSchema | Record<string, unknown> | undefined | JSON Schema for structured output extraction. | | options.structuredOutputRetries | number | 2 (server default) | Max retries for structured output validation. | | options.hooksOverride | Record<string, unknown> | undefined | Run-scoped hook overrides. | | options.enableBuiltins | boolean | Runtime/config default | Override built-in tool availability. | | options.enableShell | boolean | Runtime/config default | Override shell-tool availability; enabling it also requires built-ins. | | options.enableMemory | boolean | Runtime/config default | Override semantic-memory availability. | | options.enableSchedule | boolean | Runtime/config default | Override schedule-tool availability. Omission currently inherits the configured runtime default. | | options.enableWorkGraph | boolean | Runtime/config default | Override WorkGraph-tool availability. | | options.enableMob | boolean | Runtime/config default | Override mob-orchestration helper availability. | | options.enableWebSearch | boolean | Runtime/config default | Override the built-in web-search path. | | options.toolFilter | WireToolFilter | undefined | Apply the session tool visibility policy. | | options.keepAlive | boolean | false | Run in keep-alive mode for inter-agent comms. | | options.commsName | string | undefined | Agent name for comms (required when keepAlive is true). | | options.peerMeta | Record<string, unknown> | undefined | Metadata advertised to peer comms surfaces. | | options.budgetLimits | Record<string, unknown> | undefined | Runtime budget limits for the session. | | options.providerParams | Record<string, unknown> | undefined | Provider-specific parameters (e.g. thinking config). | | options.preloadSkills | SkillRef[] | undefined | Structured skills to load before the run. | | options.skillRefs | SkillRef[] | undefined | Canonical structured skill references. | | options.labels | Record<string, string> | undefined | Session labels used for filtering and metadata. | | options.additionalInstructions | string[] | undefined | Extra instruction blocks appended to the system prompt. | | options.appContext | unknown | undefined | Opaque app context passed to custom builders. | | options.shellEnv | Record<string, string> | undefined | Per-session shell environment variables. | | options.externalTools | Record<string, unknown>[] | undefined | Inline callback tool definitions for this session. |

createDeferredSession(prompt, options?)

async createDeferredSession(
  prompt: string | ContentBlock[],
  options?: SessionOptions,
): Promise<DeferredSession>

The server rejects options.transientTurnContext on deferred create because no immediate turn exists. Current DeferredTurnOptions also omits injectedContext, transientTurnContext, and selfHostedServerId. Set injected context during deferred creation; transient first-turn context and a self-hosted server route are not expressible through this wrapper.

Creates a session identity without running the first turn yet. Use await deferred.startTurn(...) for a result or deferred.stream(...) for an EventStream when you want the first runtime-backed turn to happen later.

listSessions()

async listSessions(options?: {
  labels?: Record<string, string>;
  limit?: number;
  offset?: number;
}): Promise<SessionInfo[]>

Returns an array of typed SessionInfo objects with camelCase fields such as sessionId, sessionRef, messageCount, isActive, and labels.

readSession(sessionId)

async readSession(sessionId: string): Promise<SessionInfo>

Returns typed session details including model, provider, lastAssistantText, and labels.

Session ingress helpers

async sendExternalEvent(sessionId: string, eventType: string, payload: unknown, options?: { blocks?: ContentBlock[] }): Promise<Record<string, unknown>>
async injectContext(sessionId: string, text: string, options?: { source?: string; idempotencyKey?: string }): Promise<{ status: string }>

These expose session/external_event and session/inject_context as first-class public APIs.

Input reconciliation, ATIF export, transcript revision read/list, forking, guarded rewriting, system-prompt update, and revision restore are also public through the corresponding inputState, exportSessionAtif, and *SessionTranscript* helpers.

Session.turn and Session.stream accept injectedContext, transientTurnContext, skillRefs, turnToolOverlay, additionalInstructions, keepAlive, model, provider, selfHostedServerId, maxTokens, systemPrompt, outputSchema, structuredOutputRetries, and providerParams.

DeferredSession.startTurn and DeferredSession.stream accept skillRefs, turnToolOverlay, additionalInstructions, keepAlive, model, provider, maxTokens, systemPrompt, outputSchema, structuredOutputRetries, and providerParams.

Schedules, Models, and Mob profile APIs

async getModelsCatalog(): Promise<ModelsCatalog>

async createSchedule(request: CreateScheduleRequest): Promise<Schedule>
async getSchedule(scheduleId: string): Promise<Schedule>
async listSchedules(options?: ScheduleListOptions): Promise<Schedule[]>
async updateSchedule(request: UpdateScheduleRequest): Promise<Schedule>
async pauseSchedule(scheduleId: string): Promise<Schedule>
async resumeSchedule(scheduleId: string): Promise<Schedule>
async deleteSchedule(scheduleId: string): Promise<Schedule>
async listScheduleOccurrences(scheduleId: string, options?: ScheduleOccurrencesOptions): Promise<ScheduleOccurrencesResult>
async listScheduleTools(): Promise<ScheduleToolsResult>
async callScheduleTool(request: ScheduleToolCallRequest): Promise<Record<string, unknown>>

// WorkGraph is read-only from the SDK; agents mutate it through WorkGraph tools.
async getWorkGraphItem(itemId: string, options?: WorkGraphItemLookupOptions): Promise<WorkItem>
async listWorkGraphItems(filter?: WorkItemFilter): Promise<WorkItemsResult>
async listReadyWorkGraphItems(filter?: ReadyWorkFilter): Promise<WorkItemsResult>
async getWorkGraphSnapshot(filter?: WorkGraphSnapshotFilter): Promise<WorkGraphSnapshot>
async listWorkGraphEvents(filter?: WorkGraphEventFilter): Promise<WorkEventsResult>
async getWorkGraphGoalStatus(params: GoalStatusRequest): Promise<GoalStatusResult>
async listWorkGraphAttention(params?: AttentionListRequest): Promise<AttentionListResult>

async readMobEvents(mobId: string, options?: MobEventsOptions): Promise<MobEventsResult>
async spawnMobMembers(mobId: string, specs: SpawnSpec[]): Promise<MobSpawnManyResultEntry[]>

async createMobProfile(name: string, profile: MobProfile): Promise<MobProfileLookupResult>
async getMobProfile(name: string): Promise<MobProfileLookupResult>
async listMobProfiles(): Promise<MobProfileLookupResult[]>
async updateMobProfile(name: string, profile: MobProfile, expectedRevision: number): Promise<MobProfileLookupResult>
async deleteMobProfile(name: string, expectedRevision: number): Promise<MobProfileDeleteResult>

The client additionally exposes detached jobs and monitors, approval and artifact lifecycles, projected event cursor replay/snapshots, and trusted multi-host mob controls. Every public TypeScript RPC wrapper binds its request and response transport boundary to generated RPC-schema contracts. Generated job/approval/artifact/event names are not re-exported from the package root in 0.8.24; pass matching object literals. Multi-host host/grant mutations are trusted operator APIs and cannot be invoked through agent mob tools.

Event cursor and snapshot methods require host event projection. Explicitly ephemeral memory realms do not expose those replay APIs.

Approval calls maintain audit records only; they do not automatically gate, authorize, or execute an action. They persist when the RPC bundle exposes a store path and otherwise remain process-local.

Auth profiles and credentials are realm-scoped. Provisioning returns an auth binding for SessionOptions.authBinding or a mob member spec, so the spec does not carry the provider secret. Remote hosts resolve bindings only inside their authorized realm.

Live channels support both WebSocket and WebRTC. Branch on opened.transport.transport; only websocket has url. Use client.liveWebrtcAnswer for the canonical WebRTC SDP exchange. The Node SDK does not provide RTCPeerConnection; inject a compatible implementation or forward browser-created SDP to the Node process. Add an audio track or the meerkat.live data channel, set the local description, wait for ICE gathering to complete, and send peer.localDescription.sdp. The 0.8.24 answerLiveWebrtcOffer helper does not wait for ICE completion and sends the original offer SDP, so it is not the canonical browser exchange. The 0.8.24 release binary omits the non-default live-webrtc Cargo feature, so WebRTC requires a custom rkat-rpc build, for example:

./scripts/repo-cargo build -p meerkat-rpc --features live-webrtc

Session lifecycle on wrappers

Cancellation and archive operations live on the runtime-backed session wrappers:

await session.interrupt();
await session.archive();
const history = await session.history({ limit: 20 });

capabilities

client.capabilities

Returns the cached Capability[] collected during connect().

hasCapability(capabilityId)

hasCapability(capabilityId: string): boolean

Returns true if the given capability is "Available" in the runtime. Known capability IDs:

| Capability ID | Description | |---------------|-------------| | "sessions" | Session lifecycle (create/turn/list/read/archive) | | "streaming" | Real-time event streaming | | "structured_output" | JSON schema-based structured output extraction | | "hooks" | Lifecycle hooks | | "builtins" | Built-in tools | | "shell" | Shell tool | | "comms" | Inter-agent communication | | "memory_store" | Semantic memory | | "session_store" | Session persistence | | "session_compaction" | Context compaction | | "skills" | Skill loading and invocation |

requireCapability(capabilityId)

requireCapability(capabilityId: string): void

Throws MeerkatError with code "CAPABILITY_UNAVAILABLE" if the capability is not available.

getConfig()

async getConfig(): Promise<ConfigEnvelope>

Returns a config envelope: { config, generation, realmId?, instanceId?, backend?, resolvedPaths? }.

setConfig(config)

async setConfig(config: Record<string, unknown>): Promise<ConfigWriteResult>

Replaces the entire runtime configuration and returns the updated envelope plus any live-propagation report.

patchConfig(patch)

async patchConfig(patch: Record<string, unknown>): Promise<ConfigWriteResult>

Merge-patches the runtime configuration and returns the updated envelope plus any live-propagation report.

Public Types

The TypeScript SDK exposes camelCase domain types at the package root. The JSON-RPC snake_case wire format stays internal.

  • RunResult is available from session.lastResult, await session.turn(...), await deferred.startTurn(...), and stream.result.
  • Usage, SessionInfo, Capability, and SchemaWarning model the runtime responses directly.
  • Session and DeferredSession are the canonical runtime-backed wrappers for session lifecycle.
  • EventStream yields typed events such as text_delta, turn_completed, and tool_execution_completed.

TurnCompletedEvent.usage is optional; absent means unmeasured, not zero. The 0.8.24 handwritten parser returns eight inventory-known event types as UnknownEvent, rejects current Rust server_tool_content and transcript_rewrite_audit_receipt_committed because the generated inventory omits them, and can preserve current run_started, run_failed, retrying, and hook_failed frames as MalformedEvent because their parser field shapes are stale. These are SDK/code-generation gaps.

Use the built-in client helpers directly for capability and skill flows:

const client = new MeerkatClient();
await client.connect();

if (client.hasCapability("skills")) {
  const session = await client.createSession("Review this function");
  const result = await session.invokeSkill(
    { sourceUuid: "source-123", skillName: "code-review" },
    "Focus on performance regressions.",
  );
  console.log(result.text);
}

Error Handling

The SDK provides a hierarchy of error classes, all extending the base MeerkatError:

MeerkatError

class MeerkatError extends Error {
  readonly code: string;
  readonly details?: unknown;
  readonly capabilityHint?: {
    capability_id: string;
    message: string;
  };

  constructor(
    code: string,
    message: string,
    details?: unknown,
    capabilityHint?: { capability_id: string; message: string },
  );
}

Base error class. The code field contains a machine-readable error code (e.g. "VERSION_MISMATCH", "NOT_CONNECTED", "CAPABILITY_UNAVAILABLE"). The optional capabilityHint suggests which capability needs to be enabled.

CapabilityUnavailableError

class CapabilityUnavailableError extends MeerkatError {}

Thrown when a required capability is not available in the runtime (e.g. feature not compiled in, disabled by policy).

SessionNotFoundError

class SessionNotFoundError extends MeerkatError {}

Thrown when a session ID does not exist in the runtime.

SkillNotFoundError

class SkillNotFoundError extends MeerkatError {}

Thrown when a referenced skill cannot be found.

Error handling example

import {
  MeerkatClient,
  MeerkatError,
  CapabilityUnavailableError,
} from "@rkat/sdk";

const client = new MeerkatClient();

try {
  await client.connect();
  const session = await client.createSession("Hello");
  console.log(session.text);
} catch (err) {
  if (err instanceof CapabilityUnavailableError) {
    console.error("Missing capability:", err.message);
    if (err.capabilityHint) {
      console.error("Hint:", err.capabilityHint.message);
    }
  } else if (err instanceof MeerkatError) {
    console.error(`Meerkat error [${err.code}]: ${err.message}`);
  } else {
    throw err;
  }
} finally {
  await client.close();
}

Version Compatibility

The SDK exports CONTRACT_VERSION (currently "0.8.24"). During connect(), the SDK checks that the server's contract version is compatible:

  • While the major version is 0, minor versions must match exactly (e.g. SDK 0.1.x requires server 0.1.x).
  • Once 1.0.0 is reached, major versions must match (standard semver).
import { CONTRACT_VERSION } from "@rkat/sdk";
console.log(CONTRACT_VERSION);  // "0.8.24"

If the versions are incompatible, connect() throws a MeerkatError with code "VERSION_MISMATCH".

Config Management Example

const client = new MeerkatClient();
await client.connect();

// Read the current config.
const config = await client.getConfig();
console.log(config.generation, config.config);

// Replace the entire config.
await client.setConfig({ ...config.config, max_tokens: 4096 });

// Or merge-patch specific fields.
const updated = await client.patchConfig({ max_tokens: 8192 });
console.log(updated.config.max_tokens);  // 8192

await client.close();

Structured Output Example

const client = new MeerkatClient();
await client.connect();

const session = await client.createSession("List three European capitals", {
  outputSchema: {
    type: "object",
    properties: {
      capitals: {
        type: "array",
        items: { type: "string" },
      },
    },
    required: ["capitals"],
  },
  structuredOutputRetries: 3,
});

// Parsed structured output (matches the schema).
console.log(session.structuredOutput);
// { capitals: ["Paris", "Berlin", "Madrid"] }

// Schema warnings from provider-specific validation issues.
if (session.lastResult.schemaWarnings) {
  for (const w of session.lastResult.schemaWarnings) {
    console.warn(`[${w.provider}] ${w.path}: ${w.message}`);
  }
}

await client.close();

Multi-turn Conversation Example

const client = new MeerkatClient();
await client.connect();

// Create session with first turn.
const session = await client.createSession("My name is Alice.", {
  model: "claude-sonnet-4-6",
});

// Follow-up turns reuse the runtime-backed session handle.
const turn2 = await session.turn("What is my name?");
console.log(turn2.text);  // Should mention "Alice"

// Check session state.
const state = await client.readSession(session.id);
console.log(state);

// List all active sessions.
const sessions = await client.listSessions();
console.log(`Active sessions: ${sessions.length}`);

// Clean up.
await session.archive();
await client.close();

License

MIT OR Apache-2.0