Skip to main content
This page documents MobKit v0.8.34 (mirrored from v0.8.34). The MobKit Python SDK provides a typed host API for launching and operating Meerkat mobs through the SDK-facing gateway. Apps own policy. Meerkat and meerkat-mob remain authoritative for agent execution, identity, membership, lifecycle, and wiring; MobKit packages gateway startup, provider adapters, operational modules, persistence projections, and operator surfaces.

Installation

The wheel is client-only and does not contain rpc_gateway. Download mobkit-rpc-gateway-<version>-<target>.tar.gz for Unix or macOS, or mobkit-rpc-gateway-<version>-<target>.zip for Windows, and extract its rpc_gateway binary (rpc_gateway.exe on Windows). Alternatively, follow the source-build instructions. Pass that binary’s path to .gateway(...).

Quick start

Durable detached tools

Declare long-running host work explicitly instead of holding callback/call_tool open:
The gateway durably accepts the job and returns a receipt; host work then runs outside the agent turn. Start, reconcile, and cancel are short control-plane callbacks subject to the 120-second public contract (the Python host and wire margins are 125 and 130 seconds). On reconnect, MobKit offers the exact committed attempt, fence, lease, checkpoint, and runner handle. Reopening does not mint a new fence; only a machine-authorized claim or retry can do that. Resolved credentials are attempt-local and never enter durable job state.

Identity-First API

For household-style apps (HomeCore), the identity-first API provides durable lifecycle management. Agents are addressed by stable identities (identity:luka, triage:main), not member IDs.

DurableAgentSpec fields

The roster provider returns one DurableAgentSpec per identity. The Rust side deserializes the same shape, so every field below reaches the gateway verbatim; fields left at their default are omitted from the wire.

Roster provider context

The gateway calls roster(context) with a typed RosterContext (meerkat_mobkit.identity_first_models.RosterContext), a one-to-one mirror of the Rust struct:

DispatchInput convenience constructors

Mob-Level API

For direct mob-member operations (discovery-based), the mob handle API is still available. The app-facing surface has three categories. Each is a distinct concern — no method crosses categories.

Comms — deliver work to agents

Returns a SendMessageResult with accepted, member_id, and session_id fields. The message enters the agent’s inbox and is processed by the host loop.

Observation — watch what’s happening

Observation is independent of delivery. Subscribe before or after sending — the stream is continuous.

Structural mob events — durable observability

MobHandle.query_mob_events() and subscribe_mob_events() project every meerkat MobEventKind (25 variants) into a typed envelope preserving mob_id, run_id, step_id, agent_identity, and the full payload.
MobStructuralEvent.cursor is the meerkat ledger cursor — durable across mobkit gateway restarts when the runtime is built with .persistent_state(path). Checkpoint a cursor and resume by passing it as after_seq on the next call.

Flow runs

Returns MobRun carrying the full meerkat ledger projection (step_ledger, failure_ledger, frames keyed by frame id, loops keyed by loop id, loop_iteration_ledger, flow_state, activation_params, schema_version, etc.).

Control plane — manage the runtime

ensure_member() and find_members() both return typed MemberSnapshot objects (single and list[MemberSnapshot] respectively).

Roster — inspect and manage members

MemberSnapshot exposes agent_identity, role, state, wired_to, and labels. Known state strings are exported from the top-level package as MEMBER_STATE_ACTIVE, MEMBER_STATE_RETIRING, MEMBER_STATE_BROKEN, MEMBER_STATE_COMPLETED, and MEMBER_STATE_UNKNOWN. The underlying Rust status enum is non-exhaustive, so consumers should tolerate future state strings.

Common pattern: new user first contact

Per-user agents are durable members, so stand them up on the identity plane — declare them through your roster provider and reconcile — rather than ensure_member-ing them into the mob roster. Identity-plane members get continuity records and resume across restarts; mob-plane members do not.
Reserve ensure_member for ephemeral workers (helpers a parent spawns and an idle-retire label reaps) — the worker plane. See the identity-first doctrine.

Builder pattern

Builder methods

Boot-time membership is declared, never derived: a member exists only once a .roster(provider) names it (identity plane) or ensure_member creates it (worker plane); [profiles.*] in mob.toml are role templates and spawn nothing on their own. The former .discovery(callback) and .pre_spawn(callback) builder methods were removed: they stored the callback and never transmitted it, so no boot spawn ever came from them. External identity providers follow the Rust gateway’s authoritative path: set .continuity_store(provider), .lease_provider(provider), and .scratch_dir(path) together. The Python callback dispatcher speaks the Rust wire contract for leases (result tags and ttl) and continuity deletes. LeaseProviderProtocol.renew_leases(...) is atomic from the caller’s perspective: raising means no input grant was changed, while every returned renewed or lost result is already committed for that identity. Providers must not commit a replacement grant and then raise. For continuity stores, checkpoint_version is monotonic per identity and continuity generation. A live session rebind changes session_id without resetting the version; only destructive reset advances generation and starts the version stream over. A durable member whose role changed refuses to resume with MobError::MemberRoleMigrationRequired until the host declares the migration. .role_migrations([...]) is that declaration: it emits a top-level role_migrations init param, not a runtime_options field, and the authority lasts exactly one boot because nothing persists it. Meerkat re-verifies the declared from_role against durable state and refuses with MobError::MemberRoleMigrationRejected on mismatch, and ignores the declaration entirely once the roles already agree, so a declaration left in place after the migration landed is inert. It arms only where an identity plane exists; on rpc_gateway that means alongside .roster(...). See roster and member lifecycle. Every explicit .identity_bootstrap_mode(...) call declares identity-first intent and requires .roster(...), including explicit eager mode. Omitting the setter keeps a gateway without a roster on the classic path; a configured roster with no explicit mode retains eager materialization. Gateway memory config accepts {backend: "local_json"} with an optional health_check_endpoint (memory.local_json(...)); the legacy Elephant {backend, endpoint} shape still works but emits a DeprecationWarning. memory(stores=...) is intentionally rejected because the Rust gateway does not accept store lists in mobkit/init. JWT auth is the gateway-supported auth mode; Google/OIDC helpers are not accepted by gateway init today. Agent memory is configured with .agent_memory() and requires .persistent_state(path) plus an identity roster when using the bundled gateway store. Options include realm, selection, max_entries, recall_timeout_ms, recall_failure_policy, and instruction_header; the SDK serializes them to the gateway wire contract. Automatic injection defaults to a 500 ms timeout and skips the memory block if recall fails. Storage durability declarations. The gateway is fail-closed about durable storage: a store that cannot open is a startup error, never a silent in-memory fallback. The config.runtime_store and config.event_log modules produce the explicit declarations:
The resolved picture is the typed storage census: StatusResult.storage / CapabilitiesResult.storage parse the gateway’s storage object into StorageSummary (blob durability, the H2 incremental probe, and the per-slot StorageSlotSummary census with domain, durability_class, resolution, backend, degraded, detail). A fail-closed startup refusal — file-name twins, a store that failed to open — surfaces as the typed StorageResolutionError (code -32014, STORAGE_RESOLUTION_CODE), not a TransportError; its message names the remediation (mobkit/storage/doctor, or the explicit ephemeral declaration). Blob-store durability has no wire declaration today — it is declared by Rust embedders via ephemeral_blobs(true) / binary_blob_store(...) and reported read-only in the census.

Console access

The bundled console is fail-closed. Without .auth(...) the gateway’s decision state trusts no signing key, and because require_app_auth defaults to true every console request is refused with 401; the gateway logs a startup warning naming this. Opening the console is an explicit builder call:
Use .console_auth_required(False) only behind a loopback bind or a reverse proxy that authenticates; for anything shared, configure .auth(...) instead. Earlier SDKs had no setter and hosts overrode MobKitRuntime._build_init_params to inject console_require_app_auth or console_config_path; both now have builder methods and the override is no longer needed. The gateway binds 127.0.0.1 on an ephemeral port by default. To publish it from another container, .http_listen("0.0.0.0:8080") together with either .auth(...) or the explicit .allow_remote() acknowledgement, and .http_public_base_url(...) to advertise the proxy’s address (read back as runtime.rust_http_public_base_url; runtime.rust_http_base_url stays the same-host form the SDK itself dials). A non-loopback bind without either is refused at init. See Deployment.

Runtime lifecycle

Gateway logging (stderr)

The persistent gateway reports tracing lines, panic hooks, and storage migration progress on its stderr. By default the SDK inherits the host process’s stderr, so those lines are visible where your application logs. Two environment variables adjust this: Discarding is the legacy pre-0.8.9 default and is not recommended: it hides panic output and makes a slow-but-working storage migration indistinguishable from a hang.

Session agent builder and per-profile tools

build_agent runs once per member build on the worker plane (fresh spawn or resume). The gateway pre-fills SessionBuildOptions before it calls you: Read profile_name, do not assign it. There is no way to select a profile from build_agent: the gateway applies only additional_instructions (mint builds only; on a resume they are ignored with a warning, because a resume inherits the persisted prompt state), labels, resume_session_id, and the registered tools from what you return, and ignores a host-set profile_name. Per-profile tools are therefore one builder that branches on the pre-filled value:
.session_service(builder) is the public setter; build() connects and registers the builder on the callback dispatcher for you. MobKitBuilder._config and MobKitRuntime._dispatcher are internal and change without notice. The builder must be set before build(): mobkit/init tells the gateway whether a session builder exists, so there is no post-connect registration.

Identity-first equivalent: customize_build

On the identity plane the same hook is AgentCustomizer.customize_build, registered with the public .agent_customizer(customizer). It runs on fresh create and on every restore/reconcile, receives the durable spec (so spec.profile is the profile name), and registers tools on the draft:
draft also carries model, system_prompt, additional_instructions, labels, app_context, and provider_params. A tool registered here rides the same callback/call_tool dispatch as build_agent tools, so resumed identities keep it.

Provider parameters (provider_params)

AgentBuildDraft.provider_params mirrors meerkat’s ProviderParamsOverride: the shared sampling knobs at the top level and the provider-specific knobs nested under provider_tag, which is tagged by provider. Anthropic prompt caching is such a knob; meerkat 0.8.32 (the pinned release) defaults it to disabled on every backend, so a long-lived identity opts in here:
The flat form {"cache_control": "automatic"} is refused: both ProviderParamsOverride and the provider tags deny unknown fields, so the gateway rejects the returned draft instead of dropping the knob. Knobs the draft leaves unset are filled from the profile’s own provider_params, and a provider_tag from a different provider family than the profile’s own tag is a typed merge error, not a silent union. A declared provider_params also reaches resumed sessions (the bridge masks it into resume_overrides); it requires an inline definition profile to carry it, so an identity bound to a realm-reference profile fails the build with a message naming the realm profile as the place to declare it.

Error hierarchy

All SDK errors inherit from MobKitError:

Advanced API

These methods are available for power users and module-system internals. Most apps should use send, subscribe_agent/subscribe_mob, and status/reconcile instead.

Mobpack authoring

MobHandle wraps the full Flow Editor authoring surface (mobkit/mobpacks/*) with snake_case typed methods — mobpack_templates, mobpack_catalogs, mobpack_validate, mobpack_source, mobpack_export, mobpack_import, mobpack_list, mobpack_get, mobpack_create, mobpack_save, mobpack_delete, mobpack_undo, mobpack_redo, mobpack_apply_operation, mobpack_deploy_command, and mobpack_deploy. The same wrappers exist on the SDK’s typed JSON-RPC clients.
mobpack_deploy(document, execute=True) writes the archive and runs rkat mob run on the host — gated by the surface’s advertised authoring_capabilities and, on ABAC-enforced runtimes, the caller’s mobpack.deploy grant. See the Flow Editor guide.

Public surface exports

Everything below is importable directly from meerkat_mobkit:
Module authoring helpers (ModuleSpec, define_module, etc.) live in meerkat_mobkit.helpers — not top-level.

See also