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 holdingcallback/call_tool open:
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 oneDurableAgentSpec 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 callsroster(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
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
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
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 thanensure_member-ing them into the mob roster. Identity-plane members
get continuity records and resume across restarts; mob-plane members do not.
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:
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:
.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:
{"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 fromMobKitError:
Advanced API
These methods are available for power users and module-system internals. Most apps should usesend, 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 frommeerkat_mobkit:
ModuleSpec, define_module, etc.) live in meerkat_mobkit.helpers — not top-level.
See also
- JSON-RPC API — full method reference
- SSE API — event streaming protocol
- Modules — module configuration and lifecycle
- Rust SDK — primary Rust interface
- TypeScript SDK — TypeScript equivalent
