Skip to main content

Meerkat Python SDK

Python SDK for the Meerkat runtime.

  • Contract version: the same as the package version (meerkat.CONTRACT_VERSION)
  • Python: >=3.10
  • Package: meerkat-sdk

The SDK is session-first and runtime-backed: it spawns rkat-rpc and exposes typed Python handles (Session, DeferredSession, Mob) over the same canonical JSON-RPC surface used by CLI/REST/MCP.

Install

pip install meerkat-sdk

For local development:

pip install -e "sdks/python[dev]"

Quick start

The selected model needs a compatible credential route: an already provisioned auth binding or the provider's environment key. This example selects Claude. For a clean API-key setup, export your Anthropic key in the shell that starts Python; the rkat-rpc child inherits it:

export ANTHROPIC_API_KEY="<your-anthropic-api-key>"

Skip this export if you already use a compatible auth binding; pass it with auth_binding when it is not the configured default. A different provider's key is not a substitute for the selected model's credentials.

import asyncio
from meerkat import MeerkatClient

async def main() -> None:
    async with MeerkatClient() as client:
        session = await client.create_session(
            "What is the capital of France?",
            model="claude-sonnet-4-6",
        )
        print(session.text)

        result = await session.turn("And Germany?")
        print(result.text)

        await session.archive()

asyncio.run(main())

Core API

Session creation

create_session, create_session_streaming, and create_deferred_session support:

  • host context and identity: injected_context, auth_binding, plus transient_turn_context for immediate create/stream only
  • model/provider controls: model, provider, max_tokens, system_prompt, provider_params
  • structured output: output_schema, structured_output_retries
  • runtime/tool toggles: enable_builtins, enable_shell, enable_memory, enable_schedule, enable_workgraph, enable_mob, enable_web_search
  • comms/runtime metadata: keep_alive, comms_name, peer_meta, budget_limits
  • skills: preload_skills, skill_refs
  • session metadata: labels
  • additional session config: additional_instructions, app_context, shell_env, external_tools

Deferred creation stores injected context for its eventual first turn but does not accept transient turn context. Pass transient facts to DeferredSession.start_turn(...).

Session queries

  • await client.list_sessions(...) -> list[SessionSummary]
  • await client.read_session(session_id) -> SessionDetails
  • await client.read_session_history(session_id, offset=0, limit=None) -> SessionHistory

SessionSummary is returned by session/list and includes total_tokens. SessionDetails is returned by session/read and includes model, provider, and last_assistant_text. Both use integer unix timestamps for created_at and updated_at.

Session runtime inputs

  • await client.inject_context(session_id, text, source=..., idempotency_key=...)
  • await session.inject_context(...)
  • await client.send_external_event(session_id, event_type, payload, blocks=None)
  • await session.send_external_event(event_type, payload, blocks=None)

Turns and streaming

Session.turn(...) and Session.stream(...) now expose full turn overrides:

  • injected_context, transient_turn_context
  • skill_refs, turn_tool_overlay
  • additional_instructions
  • keep_alive, model, provider, self_hosted_server_id, max_tokens, system_prompt
  • output_schema, structured_output_retries, provider_params

DeferredSession.start_turn(...) supports the same override set.

Config APIs return config write results

get_config returns a ConfigEnvelope:

{
  "config": {...},
  "generation": 12,
  "realm_id": "...",
  "instance_id": "...",
  "backend": "...",
  "resolved_paths": {...} | None,
}

set_config and patch_config return the same envelope fields plus optional live_propagation when a write fans out to live channels.

Example:

config_envelope = await client.get_config()
updated = await client.patch_config(
    {"max_tokens": 2048},
    expected_generation=config_envelope["generation"],
)

Additional surfaces

Models catalog

  • await client.get_models_catalog() -> ModelsCatalogResponse

Schedules

  • await client.create_schedule(request)
  • await client.get_schedule(schedule_id)
  • await client.list_schedules(labels=None, limit=None, offset=None)
  • await client.update_schedule(request)
  • await client.pause_schedule(schedule_id)
  • await client.resume_schedule(schedule_id)
  • await client.delete_schedule(schedule_id)
  • await client.list_schedule_occurrences(schedule_id, include_terminal=True|False)
  • await client.list_schedule_tools()
  • await client.call_schedule_tool({"name": "...", "arguments": {...}})

WorkGraph

WorkGraph is exposed as read-only observability from the SDK. Agents mutate work through their WorkGraph tools; SDK callers inspect the current graph.

  • await client.get_workgraph_item(item_id, realm_id=None, namespace=None)
  • await client.list_workgraph_items(filter=None)
  • await client.list_ready_workgraph_items(filter=None)
  • await client.get_workgraph_snapshot(filter=None)
  • await client.list_workgraph_events(filter=None)
  • await client.get_workgraph_goal_status(GoalStatusRequest(...))
  • await client.list_workgraph_attention(AttentionListRequest(...))

Jobs, approvals, artifacts, and projected event replay

  • jobs: jobs_get/list/cancel/progress/result/artifacts/retry/health/subscribe/unsubscribe
  • monitors and Meta workers: monitors_start, meta_job_*
  • approvals: request_approval, list_approvals, get_approval, decide_approval
  • artifacts: list_artifacts, get_artifact, download_artifact
  • projected event recovery: latest_event_cursor, list_events_since, event_snapshot when host event projection is enabled

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.

Explicitly ephemeral memory realms do not expose event cursor or snapshot replay APIs.

Every public Python RPC wrapper binds its request and result transport boundary to generated RPC-schema contracts. Generated request/result classes for the families above currently live in meerkat.generated.types; they are not re-exported at the package root.

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

Transcript editing and reconciliation

  • input_state, export_session_atif
  • transcript revision read/list, fork-at/fork-replace, rewrite, system-prompt update, and revision restore

Mob runtime

  • await client.read_mob_events(mob_id, after_cursor=0, limit=100)
  • await mob.read_events(after_cursor=0, limit=100)
  • await mob.spawn_many(specs) -> MobSpawnManyResult
  • await mob.wait_for_kickoff_complete(...)
  • helper methods use canonical role_name
  • trusted multi-host controls cover host bind/revoke, route installs, scope grants, hard cancel, member history, and remote member live channels

Multi-host mutations are trusted host APIs. They are not agent-callable, and the agent spawn wire cannot declare Rust's one-shot resume_from_role role migration authority.

Live WebSocket and WebRTC

LiveChannel wraps the session-bound live lifecycle. live_open returns a discriminated websocket or webrtc bootstrap. Only the WebSocket variant has url; WebRTC callers create an SDP offer and call live_webrtc_answer(channel_id, token, offer_sdp).

WebRTC requires connect(live_webrtc=True) and an rkat-rpc binary compiled with its non-default live-webrtc Cargo feature. The 0.8.24 auto-downloaded release binary omits that feature. Build a custom binary with ./scripts/repo-cargo build -p meerkat-rpc --features live-webrtc, and add an audio track or the meerkat.live data channel before the browser creates its offer. Set the local description, wait for ICE gathering to complete, and send peer.localDescription.sdp; there is no candidate-trickle RPC. Install the returned answer_sdp as the browser peer's remote description before live input. WebSocket uses connect(live_ws=True) and does not need that Cargo feature.

Realm profile CRUD

  • await client.create_mob_profile(name, profile)
  • await client.get_mob_profile(name) returns StoredMobProfile | None
  • await client.list_mob_profiles()
  • await client.update_mob_profile(name, profile, expected_revision=...)
  • await client.delete_mob_profile(name, expected_revision=...)

Streaming

session.stream(...) and client.create_session_streaming(...) return EventStream, an async context manager yielding typed event dataclasses (TextDelta, TurnCompleted, ToolExecutionCompleted, etc.).

from meerkat import TextDelta

async with session.stream("Explain this in detail.") as events:
    async for event in events:
        match event:
            case TextDelta(delta=chunk):
                print(chunk, end="", flush=True)
    result = events.result

TurnCompleted.usage is optional; absent means unmeasured, not zero. RunStarted.input preserves the typed RunInput: content (text or blocks) or a pending_tool_results continuation without a fabricated prompt. RunFailed accepts the current error_report and derives its display fields from that report.

Inventory-known events without a handwritten parser class arrive as UnknownEvent, preserving event.type and the complete wire payload in event.data. This includes server_tool_content, all four model_fallback_* events, transcript_rewrite_audit_receipt_committed, boundary_append_applied, and boundary_appends_discarded. A present type outside the generated inventory raises MeerkatError with code UNKNOWN_EVENT_TYPE.

A missing type or malformed payload for a handwritten parser class arrives as UnknownEvent(type="malformed_event"), with the original payload in event.data. The Retrying and HookFailed parsers still expect legacy flat fields; current payloads carry retry and reason, respectively, so they take this malformed path. See the event compatibility reference for details.

Run tests

pip install -e "sdks/python[dev]"

pytest sdks/python/tests/test_types.py -v
pytest sdks/python/tests/test_audit_parity.py -v
pytest sdks/python/tests/test_e2e.py -v
pytest sdks/python/tests/test_e2e_smoke.py -v

Metadata

Release files for meerkat-sdk 0.9.2

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for meerkat-sdk 0.9.2
File Size Uploaded Provenance
meerkat_sdk-0.9.2.tar.gz 328.6 kB Without provenance Details

Built distribution (wheel)

Table of built distributions (wheels) for meerkat-sdk 0.9.2
File Interpreter ABI Platform
meerkat_sdk-0.9.2-py3-none-any.whl Python 3 none any Details

Total release size: 562.7 kB

Release files / meerkat_sdk-0.9.2.tar.gz

Download URL meerkat_sdk-0.9.2.tar.gz
Size 328.6 kB
Tags Source
SHA-256 checksum
How to use checksums
b3e0ee072d30c20cceebac440216080ef1ad61b7930a8b2d7c4d9d6e7a154bd7
BLAKE2b-256 checksum
How to use checksums
fd2185b088edd91f5df5ccc19eea4bdaa36f69de1eb4d80889b3544a151f357f
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.14.8

Release files / meerkat_sdk-0.9.2-py3-none-any.whl

Download URL meerkat_sdk-0.9.2-py3-none-any.whl
Size 234.1 kB
Tags Python 3
SHA-256 checksum
How to use checksums
80299d318a9fa17cbfff9a2023ff2b6c4dee28bc164a7c01e29c61ffe63fb7a2
BLAKE2b-256 checksum
How to use checksums
f0c0630ddef8708b40c0f0af1d2b312c459235619bb4bc43a3a6bdeed698eaff
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.14.8

Security for meerkat-sdk 0.9.2

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Release history Release notifications | RSS feed

This release

0.9.2 This release

2 release files No provenance

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page