---
title: "Python SDK"
description: "Get started with the Meerkat Python SDK: sessions, streaming, schedules, mobs, and typed runtime contracts."
icon: "python"
---

The Python SDK (`meerkat-sdk`) is a runtime-backed client over `rkat-rpc`.

- **Contract version:** `0.6.19`
- **Python:** `>=3.10`
- **Runtime dependencies:** `websockets>=12,<16`

## Install

```bash
pip install meerkat-sdk
```

For local development:

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

## Quick start

```python
import asyncio
from meerkat import MeerkatClient, TextDelta

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

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

        async with session.stream("Give one extra fact.") as events:
            async for event in events:
                match event:
                    case TextDelta(delta=chunk):
                        print(chunk, end="", flush=True)
            print()

        await session.archive()

asyncio.run(main())
```

## 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`

### Session runtime inputs

- `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:

- `skill_refs`, `flow_tool_overlay`
- `additional_instructions`
- `keep_alive`, `model`, `provider`, `max_tokens`, `system_prompt`
- `output_schema`, `structured_output_retries`, `provider_params`

### Config APIs

- `await client.get_config() -> ConfigEnvelope`
- `await client.set_config(config, expected_generation=None) -> ConfigEnvelope`
- `await client.patch_config(patch, expected_generation=None) -> ConfigEnvelope`

All config APIs return a **config envelope** (`config`, `generation`, realm metadata), not a bare config object.

### 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(...)`

### 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`.

```python
from meerkat import LiveChannel, MeerkatClient

client = MeerkatClient()
await client.connect(live_ws=True)
try:
    session = await client.create_session("Open a live channel")
    channel = LiveChannel.session(client, session.id, turning_mode="explicit_commit")

    opened = await channel.open()
    # Connect to opened["transport"]["url"] externally.
    await channel.send_input_text("hello")
    await channel.commit_input(response_modality="text")
    await channel.close()
finally:
    await client.close()
```

- `await client.live_open(session_id, turning_mode=None)`
- `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, 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)`

### 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(..., role_name=...)`
- `await mob.fork_helper(..., role_name=...)`

### 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(...)`

### 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.

```python
history = await session.history()
image = next(
    block
    for message in history.messages
    for block in message.blocks
    if block.block_type == "image"
)
payload = await client.get_blob(image.blob_id)
```

Image-generation wire contracts are also exported for integrations that inspect tool results directly: `WireGenerateImageRequest`, `WireGenerateImageExecutionPlan`, `WireImageGenerationToolResult`, `WireImageOperationPhase`, and `WireAssistantImageRef`.

## Typed session metadata

- `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`.

```python
async with session.stream("Summarize logs") as events:
    async for event in events:
        ...
    result = events.result
```
