The Python SDK (meerkat-sdk) is a runtime-backed client over rkat-rpc.
- Contract version:
0.8.33
- Python:
>=3.10
- Runtime dependencies:
websockets>=12,<16
Install
For local development:
Quick start
Method overview
Session lifecycle
await client.create_session(...) -> Session
client.create_session_streaming(...) -> EventStream
await client.create_deferred_session(...) -> DeferredSession
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
await client.inject_context(session_id, text, source=None, idempotency_key=None)
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)
Turn APIs
Session.turn(...), Session.stream(...), and DeferredSession.start_turn(...) support:
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
Immediate session creation also accepts injected_context,
transient_turn_context, auth_binding, the schedule/WorkGraph/web-search
feature toggles, and a typed system-prompt override. Deferred creation accepts
the same durable setup except transient_turn_context; supply request-only
host facts to DeferredSession.start_turn(...) instead. Injected context
becomes ordered user-channel context immediately before the prompt. Transient
turn context is not durable transcript history.
Config APIs
await client.get_config() -> ConfigEnvelope
await client.set_config(config, expected_generation=None) -> ConfigWriteResult
await client.patch_config(patch, expected_generation=None) -> ConfigWriteResult
All config APIs return an envelope (config, generation, realm metadata), not a bare config object; writes additionally carry live_propagation.
Additional runtime surfaces
await client.get_models_catalog()
await client.create_schedule(...)
await client.get_schedule(...)
await client.list_schedules(labels=None, limit=None, offset=None)
await client.update_schedule(...)
await client.pause_schedule(...)
await client.resume_schedule(...)
await client.delete_schedule(...)
await client.list_schedule_occurrences(...)
await client.list_schedule_tools()
await client.call_schedule_tool(...)
WorkGraph observability
WorkGraph mutation remains agent-owned through tools. Host SDK callers can
inspect the graph and its goal/attention projections:
await client.get_workgraph_item(...)
await client.list_workgraph_items(...)
await client.list_ready_workgraph_items(...)
await client.get_workgraph_snapshot(...)
await client.list_workgraph_events(...)
await client.get_workgraph_goal_status(...)
await client.list_workgraph_attention(...)
Jobs, approvals, artifacts, and projected event replay
- detached jobs:
jobs_get, jobs_list, jobs_cancel, jobs_progress,
jobs_result, jobs_artifacts, jobs_retry, jobs_health,
jobs_subscribe, jobs_unsubscribe
- monitors:
monitors_start
- MobKit workers:
mobkit_job_heartbeat, mobkit_job_progress,
mobkit_job_checkpoint, mobkit_job_complete, mobkit_job_fail,
mobkit_job_cancel_ack
- approvals:
request_approval, list_approvals, get_approval,
decide_approval
- artifacts:
list_artifacts, get_artifact, download_artifact
- projected events:
latest_event_cursor, list_events_since,
event_snapshot when host event projection is enabled
Approval methods maintain audit records only. Requesting or deciding a record
does not automatically gate, authorize, or execute an action. Records persist
when the RPC bundle exposes a store path. See
JSON-RPC approvals.
Every public Python RPC wrapper binds its request and result transport boundary
to generated RPC-schema contracts. For the families above, the generated
parameter and result class names in 0.8.24 are imported from
meerkat.generated.types rather than re-exported at the package root.
Transcript history, revisions, and recovery
input_state(...) reconciles an admitted input by input id or idempotency key
export_session_atif(...) exports a session trajectory
read_session_transcript_revision(...) and
list_session_transcript_revisions(...) inspect durable revisions
fork_session_at(...) and fork_session_replace(...) create a new branch
rewrite_session_transcript(...), update_system_prompt(...), and
restore_session_transcript_revision(...) perform guarded edits
Live channel APIs
The old RealtimeChannel helper has been removed. Use LiveChannel.session(...)
for a session-bound wrapper, or call the direct live/* RPC helpers on
MeerkatClient.
For WebSocket instead, connect with live_ws=True and request
transport="websocket"; only that bootstrap has a URL.
The server exposes one offer-to-answer exchange and no candidate-trickle RPC.
Install the returned answer_sdp as the browser peer’s remote description.
live_webrtc=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 auto-downloaded 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 as MeerkatClient(rkat_path).
await client.live_open(session_id, turning_mode=None, transport=None, seed_max_chars=None)
await client.live_webrtc_answer(channel_id, token, offer_sdp)
await client.live_status(channel_id)
await client.live_close(channel_id)
await client.live_send_input_text(channel_id, text)
await client.live_send_input_audio(channel_id, data_base64, sample_rate_hz, channels)
await client.live_send_input_image(channel_id, idempotency_key, mime, data_base64)
await client.live_send_input_video_frame(channel_id, codec, data_base64, timestamp_ms)
await client.live_commit_input(channel_id, response_modality=None)
await client.live_interrupt(channel_id)
await client.live_truncate(channel_id, item_id, content_index, audio_played_ms)
await client.live_refresh(channel_id)
Image keys are required, caller-stable, and session-scoped. The helper returns
after queue acceptance; wait for user_content_committed with the matching key
before treating the image as durable context. See Live Channels
for replay, conflict, and reconnect limits.
seed_max_chars is an optional positive serialized-character budget for a
core-selected whole-turn seed suffix. Omit it for the full canonical seed.
Every ordered System message must fit. Runtime context and complete image identity, tombstone,
and accounting sidecars remain outside the window; any truncation reports
degraded continuity. Zero is rejected by the server.
Mob APIs
await client.create_mob(...) -> Mob
await client.list_mobs()
await mob.spawn(...)
await mob.spawn_many(...)
await mob.read_events(after_cursor=0, limit=100)
await mob.wait_for_kickoff_complete(...)
await mob.spawn_helper(..., result_label=..., max_text_bytes=..., role_name=...)
await mob.fork_helper(..., result_label=..., max_text_bytes=..., role_name=...)
- host/grant control:
mob.hosts(), mob.route_installs(),
mob.bind_host(...), mob.revoke_host(...), mob.grant_scopes(...),
mob.revoke_scopes(...), mob.grants()
- remote member control:
mob.hard_cancel(...), member history, member live
open/status/control/close, and member/mob event subscriptions
Multi-host placement and host/grant mutations are trusted operator APIs on the
JSON-RPC SDK surface. They are intentionally not exposed as agent-callable mob
tools. The agent-callable spawn wire also cannot declare the Rust-only
resume_from_role durable role-migration authority.
Realm profile CRUD
await client.create_mob_profile(name, profile)
await client.get_mob_profile(name) -> StoredMobProfile | None
await client.list_mob_profiles()
await client.update_mob_profile(name, profile, expected_revision=...)
await client.delete_mob_profile(name, expected_revision=...)
Additional wrappers
The Python client also exposes:
- realm helpers:
list_realms(), get_realm(...)
- auth helpers:
list_auth_profiles(...), get_auth_profile(...), create_auth_profile(...), delete_auth_profile(...), auth_login_*, auth_provision_api_key(...), auth_status(...), auth_logout(...)
- blob/skill/MCP helpers:
get_blob(...), list_skills(), mcp_add(...), mcp_remove(...), mcp_reload(...)
- comms helpers:
session.send(...), session.peers()
- typed ingress helpers:
send_peer_response_terminal(...)
- runtime host inspection:
get_runtime_host_info(),
get_runtime_host_capabilities(), get_runtime_host_health()
Auth profiles and credentials are realm-scoped. Login/provisioning yields an
auth binding that sessions and mob member specs can reference without carrying
the provider secret itself; a remote member host resolves the binding within
its 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 block_type == "image". The SDK preserves image_id, blob_id, media_type, width, height, revised_prompt, and provider metadata.
Image-generation wire contracts are also exported for integrations that inspect tool results directly: WireGenerateImageRequest, WireGenerateImageExecutionPlan, WireImageGenerationToolResult, WireImageOperationPhase, and WireAssistantImageRef.
SessionSummary (from session/list) includes total_tokens
SessionDetails (from session/read) includes model, provider, last_assistant_text
- both use integer unix timestamps for
created_at / updated_at
Streaming model
EventStream is an async context manager returned by session.stream() and client.create_session_streaming(). Iterate it to receive typed event dataclasses, then read events.result.
TurnCompleted.usage is optional. Absence means the provider supplied no
normalized accounting for that call; skip the row instead of treating it as
zero.
The generated 0.8.24 inventory has eight event types with no handwritten
parser case, so they arrive as UnknownEvent. Current Rust
server_tool_content and transcript_rewrite_audit_receipt_committed are
missing from that inventory and are rejected as UNKNOWN_EVENT_TYPE.
RunStarted, RunFailed, Retrying, and HookFailed also retain legacy
parser field shapes and can arrive malformed. See the reference page for the
exact list; do not treat these SDK fallbacks as alternate wire contracts.