Skip to main content
This page documents MobKit v0.8.34 (mirrored from v0.8.34). MobKit exposes its operational API over JSON-RPC 2.0. SDK gateways use JSON lines over stdio, while the embedded console uses POST /console/rpc for the console-specific subset and runtime passthrough.

Protocol

  • SDK transport: JSON lines over stdio (one JSON object per line)
  • Console transport: HTTP POST /console/rpc
  • Version: JSON-RPC 2.0
  • Contract version: 0.5.0

Initialization handshake

The persistent SDK gateway (rpc_gateway --persistent) does not emit an unsolicited capabilities line. It waits for the client, whose first JSON line must be a mobkit/init request:
On success, the JSON-RPC response carries contract_version in result, together with http_base_url and the gateway’s runtime metadata. Clients that enforce contract compatibility compare result.contract_version before sending later requests. After init, mobkit/capabilities returns the methods available on that runtime.

role_migrations

A durable member whose role changed refuses to resume (MobError::MemberRoleMigrationRequired) until the host declares the migration, so an unintended role edit cannot silently restamp a member’s durable role, comms name and binding. The key sits at the TOP LEVEL of params, a sibling of runtime_options and persistent_state, not inside runtime_options. rpc_gateway reads it at init scope, and its runtime_options handling is a closed allowlist that would reject it as an unsupported field.
Each entry is {identity, from_role}: the exact identity being migrated (no wildcards, no prefix matching) and the role it is migrating FROM. The gateway installs the list on its session bridge for the life of this boot and never persists it, so omitting it next boot removes the authority. Lookup is by exact identity; an identity the host did not name carries no migration authority. Meerkat re-verifies from_role against the durable predecessor role and refuses with MobError::MemberRoleMigrationRejected on mismatch, and ignores the declaration once the roles already agree, so a leftover declaration is inert rather than a repeat restamp. A malformed payload fails mobkit/init with -32602 rather than arming nothing, on both gateway binaries and whether or not an identity plane is configured. One identity declared twice with conflicting from_role values is refused too, rather than letting hash order pick which predecessor role becomes authority, but the refusal differs by binary: rpc_gateway checks at init scope and answers -32602 on the request, while mobkit_gateway checks inside its identity-first block and fails the boot out as a -32603 internal error with a null id. Under identity_first: false mobkit_gateway runs neither that check nor the install, so a self-contradicting payload is not refused and nothing is armed. An identical repeat is accepted on purpose. The Python SDK exposes this as MobKitBuilder.role_migrations([...]), taking RoleMigrationDeclaration dataclasses or plain dicts, both validated; a conflicting pair raises ValueError, and an omitted or empty list emits no role_migrations key at all. The TypeScript SDK has no equivalent surface.

Request format

Response format

Error format

The optional data field carries structured context for typed errors. SDKs surface it on RpcError.data.

Mobkit-specific error codes

The -32010 constant is exported from both SDKs as MOB_EVENTS_STALE_CURSOR_CODE. The Python and TypeScript SDKs auto- reify -32010 errors into MobEventsStaleError (a typed subclass of RpcError) carrying after_cursor and latest_cursor. Console timeline replay failures use CONSOLE_TIMELINE_REPLAY_UNAVAILABLE_CODE so they are not mistaken for mob-events ledger cursor errors. The -32014 constant is exported as STORAGE_RESOLUTION_CODE and reified as StorageResolutionError, so a deliberate durability refusal at startup is a typed init failure, not a transport error. Storage refusals raised by the Rust builder surfaces (UnifiedRuntime::bootstrap) still surface as -32603 with the typed message text. The mobkit/init runtime_options storage declarations (runtime_store, event_log) are documented in Configuration → SDK and Gateway runtime options.

Topology control

Topology mutation is an optional MobKit control plane. It is disabled by default; a host must explicitly configure TopologyControlPolicy as read_only or editable. The stock console only shows its Connections view when the runtime advertises topology management, and it never invents a connect all operation. Every mutation is evaluated against both endpoint identities. With access control enabled, callers need agent.view plus topology.view to inspect an endpoint, and the action-specific topology.connect, topology.disconnect, or topology.reconnect grant on both endpoints. Planning requires the same action-specific endpoint grants as applying; it is side-effect free, not an authorization oracle. Durable mutation history and actor/principal attribution require the separate topology.audit grant on every endpoint in the returned record. Requests containing multiple explicit operations additionally require topology.bulk and remain bounded by the policy’s finite max_batch_size.

mobkit/topology/query

Return the logical roster, observed/declared/operator topology, durable suppression tombstones, current revision, and caller-specific per-endpoint affordances. A disconnected declared edge remains in the response with suppressed: true; this is how operator intent survives reconciliation and restart.

mobkit/topology/plan

Validate a side-effect-free, revision-pinned set of explicit operations.

mobkit/topology/apply

Apply a previously valid shape of request. expected_revision provides compare-and-swap protection and idempotency_key is mandatory. Exact replay is durable only across the configured retention horizon: receipt_limit keeps full operation receipts, then idempotency_history_limit keeps bounded key fingerprints that reject ambiguous reuse after a receipt ages out. Replaying a retained key whose receipt is unavailable returns -32009 with data.kind = "topology_idempotency_receipt_expired"; replaying a key whose fingerprint is still in the compacted ring returns -32009 with data.kind = "topology_idempotency_history_compacted". Once both bounded horizons have expired, that key is contractually new and normal revision and policy validation applies—clients must not assume keys are reserved forever. connect, disconnect, and reconnect are distinct policy actions: reconnect removes a suppression and repairs an absent or one-sided desired edge, while disconnect records a tombstone before removing physical wiring.

mobkit/topology/operation/get

Look up a durable operation receipt by operation_id. The endpoint is useful after a client reconnect or an ambiguous transport failure; clients should not infer success from a dropped HTTP response. The actor field is omitted unless the caller has topology.audit on every endpoint in the receipt. This lookup is also bounded by receipt_limit; persist the original request and idempotency key so an ambiguous response can be replayed while its exact receipt remains retained.

mobkit/topology/audit/query

Read the durable, versioned mutation-attempt ledger. This includes denied, invalid, interrupted, recovered, applied, and rolled-back attempts, so it is more sensitive than graph inspection and is advertised only to callers with a topology.audit grant. Returned records additionally require agent.view, topology.view, and topology.audit on every endpoint in that record. Persist next_after_seq after every response, including an empty one. If a non-zero cursor is older than oldest_available_seq - 1, MobKit returns -32009 with data.kind = "topology_audit_cursor_expired", after_seq, and oldest_available_seq; restart from after_seq: 0 only when replaying from the retained frontier is acceptable. A cursor equal to oldest_available_seq - 1 remains valid. ABAC filtering advances the cursor across records the caller cannot see. This can leave gaps in visible seq values and reveals only that retained topology activity existed at those sequence positions—not its endpoints, actor, principal, operations, or result. That aggregate activity-volume metadata is an intentional trade-off for a stable, non-duplicating forward cursor. Cross-authority JSON-RPC mutation currently fails closed. Same-process hosts that control both runtimes can use MobKit’s bilateral host API, which checks both runtime policies and endpoint grants before changing either side.

Mob events

mobkit/mob_events/query

Scan the meerkat structural-event ledger and return matches.
The response always carries a numeric next_after_seq — even when the filter matches nothing — so polling SDKs keep a valid resume anchor (caller’s after_seq or the current latest_cursor).

mobkit/mob_events/subscribe

JSON-RPC handshake that returns a snapshot plus a subscribe_url pointing to the /mobkit/mob_events/stream SSE route. The URL carries after_seq (next_after_seq ∨ caller’s after_seqlatest_cursor) and the original filters so the SSE handler picks up gaplessly with the same predicate.

Roster and reconcile methods

The roster family is served by the SDK stdio surface and, as runtime passthrough, by POST /console/rpc. Roster reads cross the mob actor’s sequential command loop and are bounded by the -32017 read budget. See Roster and member lifecycle for the lifecycle model and Profiles are templates for why none of these methods spawn members from [profiles.*] on their own. On rpc_gateway the roster itself comes from the SDK host. The gateway sends callback/roster_provider/roster with the serialized RosterContext (mob_definition, previous_identities) as the request params and expects a DurableAgentSpec[] reply. The Python and TypeScript dispatchers hand the provider params.context, which the gateway does not send, so the provider’s context argument is empty on both SDKs; derive a profile-shaped roster from the host’s own parsed definition, as the section linked above shows.

mobkit/ensure_member

Ensure a member exists, spawning it when missing. On the SDK-facing rpc_gateway this is the ephemeral worker plane (MobHandle::ensure_member); on an identity-first console gateway it upserts a durable identity unless the request carries plane: "worker" (see ensure_member gateway profiles).
After every successful ensure the gateway runs reconcile_edges, so declared definition wiring (auto_wire_orchestrator, role_wiring) converges regardless of the order members are brought up; calling reconcile_edges right after ensure_member is redundant. Spawn refusals come back as -32602 with the meerkat error in the message, for example ensure_member failed: wiring error: profile 'x' has tools.comms=false; mob meerkats require comms=true. Every mob profile must set tools.comms = true (the field defaults to false, so omitting it is refused too): a member’s identity, roster occupancy, wiring, and peer messaging are all keyed on its comms name. To keep a member from messaging peers, use read_only = true or a per-member tool policy, not comms = false. On the identity plane the same refusal does not error the RPC: the receipt’s outcome is broken and the reason lives in the identity’s bootstrap status error.

mobkit/reload_member

Non-destructive cold reload of an identity’s live member. The live runtime registration is discarded and the SAME durable session is re-materialized from durable truth: same identity alias, same session_id, same continuity generation. This is the repair for a member whose sends fail with the reload-required class (meerkat’s RecoveryRepairBlocked: “registration- authorized cold reload is required”). The delivery path runs exactly one such reload automatically before failing typed; this verb is the operator’s manual form. Contrast mobkit/respawn_member, which on an identity-first gateway is a destructive continuity reset (fence owner, advance generation, fresh session). reload_member never calls it. Result: Broken or suspended identities are refused (-32603, invalid state); they need the reconcile/repair paths. Retired identities return not_current without being revived. The primitive’s not_current is also a no-op, not a fallback to retire/rematerialize. Worker-plane members are refused: the worker plane has no non-destructive reload. Two typed failures come from meerkat’s reload primitive: a refusal (“store not healthy, reload refused, retry later”: the durable resume authority is still unreadable, the registration is retained, and sends stay reload-required) and a timeout naming the stage it reached (MEMBER_RELOAD_TOTAL_TIMEOUT, 45 s; inspect the member before retrying). Both are visible afterwards in mobkit/member_health.last_reload.

mobkit/member_health

The identity’s lifecycle and delivery health from in-process reads only. It never crosses the mob actor’s command loop, so unlike mobkit/member_status it answers while the loop is stalled, which is when an operator needs it. Result (MemberHealthReport): Actor timeouts preserve {kind: "mob_actor_command_timed_out", command_kind, stage, deadline_reached: true} in RPC error.data, console error data, and last_delivery_error.data. The upstream stages include actor_command_admission and actor_command_reply; the latter may follow runtime admission. A local observation timeout has kind actor_admission_timeout and no invented upstream command/stage. Neither form asserts execution fate or retryability: absent executed or retryable fields are not a nonexecution verdict. Consult runtime idempotency and durable fate; MobKit does not automatically retry or reload on a timeout. The same observations survive an explicit or automatic reload. In-flight probe interruptions carry observation: "in_flight", distinct from a true "before_call" refusal, and do not settle the reload worker’s execution fate. Custom SessionBridge::member_durability implementations may await their own I/O, but do not hold the runtime’s fleet entries lock. Admission backpressure and reload failures retain sanitized owner data across send/dispatch errors, console REST/RPC, and health: mob_member_admission_backlog_full carries depth, mob_member_reload_refused carries its kind only, and mob_member_reload_timed_out carries the original stage. These payloads add no execution or retry verdict and omit backend refusal details. Native reload validates the identity’s existing lease before invoking Meerkat’s registration primitive; absent or lost ownership refuses without discarding the registration.

mobkit/reconcile_edges

Converge the definition-derived edge policy over the live roster and return {desired_edges, wired_edges, unwired_edges, retained_edges, preexisting_edges, skipped_missing_members, pruned_stale_managed_edges, failures}. The reconciler only unwires edges it wired itself. It is needed after mobkit/reconcile_identity or an identity-first gateway boot when the definition declares wiring, because neither of those converges definition edges after materialization; without declared wiring the report is empty.

mobkit/reconcile_identity

Re-run the roster provider and restore_flow (Python runtime.reconcile()). Picks up added, removed, and modified identities and host TopologyProvider edges. It does not run reconcile_edges. Unavailable without an identity-first runtime.

mobkit/rediscover

Reset the whole mob, re-run the Rust builder Discovery, respawn discovered members, and reconcile edges. Neither gateway binary wires a Discovery, so on every SDK host this returns {status: "no_discovery_configured"}; with identity-first authority attached it is refused outright (-32000, rediscover resets the whole mob and is unavailable with identity-first authority; use refresh_desired_topology).

Console timeline

Console-specific RPC methods are handled by the HTTP console dispatcher and are also listed in the console contract v0.5.0. Surface split: mobkit/console/* methods are served ONLY by the HTTP console dispatcher (POST /console/rpc). The stdio JSON-RPC surface (rpc_gateway stdin) neither dispatches nor advertises them — embedders needing console data over stdio should use the http_base_url from the init handshake and call the HTTP surface. The advertised-methods list on each surface reflects exactly what that surface dispatches.

mobkit/console/list_identities

List identities known to the console aggregator.

mobkit/console/inspect_identity

Inspect one console identity and return status, affordances, output preview, and reachability metadata. Older servers may only support the legacy mobkit/inspect_identity; the headless console controller keeps that as a compatibility fallback.

mobkit/console/query_timeline

Query the console log store for timeline frames. The method backs the bundled console chat and activity panes.
Response:
next_cursor never advances past visible frames omitted due to limit, so clients can page with mode: "since" without gaps. latest_cursor is the live-continuation cursor for mode: "recent" seed queries. Backfill frames are not fresh completions. Session-history backfill re-emits past turns as frames whose source.kind is "session_history". They carry session_id, and they carry the SAME interaction_id and run_id the live frames carried: meerkat persists the message identity onto committed transcript messages and the backfill stamps it back (null only for messages that predate that persistence). Identity queries and every session-bearing live frame can trigger backfill, and a history twin of a tool-only assistant step arrives as an interaction_complete with empty text, so matching by interaction_id alone does NOT separate live completions from history. Any consumer correlating completions MUST exclude source.kind == "session_history" frames from live turn handling, ignore frame_updated marker frames (emitted when a frame’s status changes, for example accepted to delivered), and then match interaction_complete on the interaction_id returned by mobkit/console/send.

mobkit/console/send

Submit an identity-addressed console interaction through the console aggregator.
The response includes interaction_id and identity. The multipart JSON-RPC endpoint also accepts this method when content contains image_upload placeholders. idempotency_key must be unique per send (the bundled console mints one per send). Replaying a key with identical content returns the earlier interaction’s acceptance, whether or not that turn has finished; replaying it with different content is refused with -32009 (idempotency_conflict, HTTP 409 on the REST form). The key is not cleared by a member respawn.

mobkit/blob/upload

Upload a single blob/image through POST /console/rpc/multipart. The response includes a blob_id that can be rendered through GET /blobs/{blob_id}.

mobkit/list_runs

List flow runs for this mob.
Returns {runs: MobRun[]} carrying the full meerkat ledger projection: step_ledger, failure_ledger, frames (map keyed by frame id), loops (map keyed by loop id), loop_iteration_ledger, flow_state, activation_params, schema_version, root_step_outputs, loop_iteration_outputs.

mobkit/reset_all

Console surface only (POST /console/rpc; mutating; ABAC action agent.reset). The stdio surface neither dispatches nor advertises it, and the aggregator-only console (no runtime attached) refuses it with data.kind = "unsupported_reset_all_surface" rather than retiring anything. It resets every console-visible identity in one pass and never exits the gateway process: a slow reset_all is a long request, not a restart. The designed exits are elsewhere, and differ per binary: rpc_gateway ends when the SDK closes its stdin (EOF), on SIGINT or SIGTERM, or through the SDK’s shutdown handshake; mobkit_gateway keeps serving HTTP after its stdin closes and ends only on SIGINT or SIGTERM or when its HTTP server task ends. Both stdin behaviours are test-pinned (tests/gateway_concurrent_dispatch.rs). The pass is sequential, one identity at a time:
  1. Preflight, fail-closed. Every target is checked before anything is mutated: a live console alias that resolves to another identity’s runtime member, a registered identity whose live session disagrees with its binding (stale_live_identity_alias), or a registered identity when the identity runtime has no session bridge (identity_reset_requires_session_bridge). Any failure returns the body below with failed non-empty and nothing changed.
  2. Raw delegates, helper members with no registered identity, are retired.
  3. Each registered identity is reset through the identity runtime (a new generation and a new session); a live member that carries no registered identity is respawned in place. Only raw delegates without a registered identity are retired.
  4. The call waits up to 10 seconds for the reset identities’ startup history to reach the console timeline, then returns.
Identities outside the caller’s console visibility policy are outside the target set and are neither reset nor retired.

Gating methods

mobkit/gating/evaluate

Evaluate the risk tier for a proposed action.

mobkit/gating/decide

Approve or deny a pending gated action.

mobkit/gating/pending

List all pending gated actions awaiting approval.

mobkit/gating/audit

Return the gating audit log (most recent entries, bounded by retention limit).

Memory methods

mobkit/memory/index

Record an operational memory assertion or conflict signal. This surface is the MobKit assertion ledger used by routing/gating flows; it is not semantic/vector document search. The runtime owns the ledger: it loads the local JSON file once at bootstrap, holds the assertions in memory, and rewrites the whole file (optionally health-gated by an external endpoint) on every index. The file is not a shared append log; edits made to it directly are overwritten, and the ledger keeps at most 4,096 assertions. See the ownership model. The stock RPC contract stores and filters canonical assertions.

mobkit/memory/query

Query stored assertions and conflict signals by exact filters.

mobkit/memory/stores

Return information about configured memory backends. Agent-memory methods are available over the SDK JSON-RPC gateway and over console POST /console/rpc when the identity runtime has an agent-memory provider configured. Console callers can recall only identities they may view; remember and forget also require mutating console access plus agent.memory.write and agent.memory.delete respectively.

mobkit/agent_memory/remember

Write an identity-scoped agent memory record for later per-turn and build-context injection. This is separate from mobkit/memory/*, which is the operational assertion ledger. A successful write means the configured hot identity-memory provider accepted the record; optional Elephant enrichment or extraction, when supplied by a custom provider, is out of band.

mobkit/agent_memory/recall

Read identity-scoped agent memory records from the configured agent memory provider. This exposes the same durable record set used for per-turn and build-context injection. Unlike automatic injection, explicit recall reports provider errors to the caller.

mobkit/agent_memory/forget

Delete one identity-scoped agent memory record from the configured provider. Providers that do not support deletes do not advertise this method in mobkit/capabilities. forget prevents future provider recall and future automatic injection; it cannot remove text that has already been delivered into an active model context.

Routing methods

mobkit/routing/resolve

Resolve a logical destination to a physical route.

mobkit/routing/routes/list

List all registered routes.

mobkit/routing/routes/add

Register a new route.

mobkit/routing/routes/delete

Remove a registered route.

mobkit/identity/routing_status

Meerkat’s typed model-routing status for the live session behind a MobKit identity. The result is meerkat’s SessionModelRoutingStatus verbatim (WireSessionModelRoutingStatus is a type alias to it), flattened under identity and session_id. MobKit declares no mirror type, so this payload cannot drift from meerkat’s contract.
Result fields: identity, session_id, baseline_model, effective_model, and the optional session_provider, active_turn_override, active_operation_override, pending_switch_turn. session_provider is the typed provider of the session’s current LLM identity. An absent session_provider means the runtime machine has no hydrated session LLM identity yet (pre-hydration). It is not a signal to re-derive a provider from effective_model: meerkat documents that re-derivation as silently wrong for models owned by a custom ModelRegistry, which is why the field is carried typed rather than inferred. This method requires a resolved session. Identity-first materializes an identity without activating it, so an identity that has been materialized but never addressed has no session and therefore no routing status. That is the expected state after a restart, not a defect. A fleet sweep should address an identity before reading, and label its coverage post-address rather than post-restart. Failures carry a machine-readable discriminator so a sweep can classify an identity rather than only fail it: Each reason is derived only from a fact MobKit observed. session_not_held is matched on RuntimeDriverError::NotFound structurally, never on message text; because that error is #[non_exhaustive], every other upstream failure lands in upstream_read_failed rather than being asserted as a missing session.
SDKs: handle.identity_routing_status(identity) (Python), handle.identityRoutingStatus(identity) (TypeScript).

Delivery methods

mobkit/delivery/send

Send a message through a resolved route.

mobkit/delivery/history

Return delivery records for audit and inspection.

WorkGraph methods

The mobkit/workgraph/* group exposes meerkat’s WorkGraph (the shared-work ledger) for this runtime’s realm. Results serialize meerkat’s typed results verbatim (WorkItem, WorkGraphSnapshot, WorkAttentionBinding, WorkEdge, …); expected_revision is the compare-and-swap token on every mutation. All fields are snake_case. Availability and the auto-issued grant. The group is advertised in mobkit/capabilities (and "workgraph": true is set) only when the service is configured, which it is by default: runtime_options.workgraph defaults to enabled (Python .workgraph(True), TypeScript .workgraph(true); false disables, a string is an explicit durable-store directory). With persistent_state the store is <persistent_state>/workgraph.sqlite3; without it the service is memory-backed and the gateway warns at boot on identity-first launches. The WorkGraphNamespaceGrant meerkat requires per agent is issued by MobKit from the wired service (realm = the mob id, namespace default) for every member whose profile sets tools.workgraph = true; hosts do not issue it. realm_id is rejected (-32602) on every method for the same reason: the service is realm-scoped at construction and agent tool calls are scope-pinned to it. Filter semantics that are easy to get wrong.
  • labels matches ALL: every listed label must be present on the item (list, ready, snapshot). This is the opposite of the builtin task_list tool, which matches any label.
  • include_terminal defaults to false and drops completed, cancelled, and failed items even when statuses names one of them; statuses: ["completed"] without include_terminal: true returns nothing. The bundled console panel passes include_terminal: true, so it can show items the SDK default hides.
  • limit defaults to 100 and may not exceed 1000 (-32602 beyond it).
  • Nothing deletes items or edges. Close an item as cancelled or failed, or link a replacement with kind supersedes; attention/prune is the one deleting verb and removes only terminal attention-binding rows. The event stream keeps the history.
  • A parent edge points from the child (from_id) to the parent (to_id); use blocks only when the target must not be ready until the source is terminally resolved.
  • close without status records completed. Pass status explicitly when the outcome is anything else.

Read methods (ABAC workgraph.view)

Mutating methods (ABAC workgraph.manage; console also requires can_mutate)

goal/create, attention/*, and policy/escalate reject a non-default namespace (-32602) because upstream turn-overlay resolution reads only the service’s default namespace. One active (or paused) binding per target is enforced across goal/create, attention/reassign, and attention/resume; a second returns -32042 naming the occupant.

Errors

SDK method names are the RPC names with the mobkit/workgraph/ prefix dropped, in snake_case for Python (workgraph_snapshot through workgraph_attention_prune, plus workgraph_add_evidence and workgraph_escalate_policy) and camelCase for TypeScript. attention/break_glass_reassign is deliberately in neither SDK, and mobkit/workgraph/facts (the cursor-tail projection behind the SSE wake stream) has no SDK wrapper either.

Notifications

The persistent rpc_gateway sends JSON-RPC notifications (no id) to the SDK alongside responses. Callback requests (callback/*) expect a reply; these do not.

mobkit/on_error

Every runtime ErrorEvent, serialized with its internal category tag in snake_case and the variant’s fields beside it:
rpc_gateway installs the forwarding hook unconditionally, so the runtime’s absent-hook notice never fires for SDK hosts; the SDKs deliver the payload to the callback registered with Python .on_error(callback) / TypeScript .onError(callback) and drop it silently when none is registered. The same event is always logged on the gateway’s stderr at ERROR (INFO for actor_loop_recovered). mobkit_gateway emits no notifications. The variant table is in Error hook and logging.

Operator transcript verbs

Two identity-scoped operator affordances for oversized or wedged member transcripts. Both resolve their target through the same identity-control gate as mobkit/respawn / mobkit/reset, so identities the gateway does not own are refused at resolution.

mobkit/compact_member

Force one transcript compaction on a member, then restore its original compaction threshold. Arms a temporary auto_compact_threshold floor for the identity, respawns the member in place so the fresh build picks the floor up, drives one queued maintenance turn (the forced compaction fires at that turn’s pre-LLM boundary), then disarms the floor and respawns again. Params: identity (required), floor_tokens (default 1024), timeout_ms (default 60000, budget for the maintenance turn). timeout_ms bounds observation, not execution. The operation submits exactly once with a caller-owned idempotency key and reads that input’s rich finalized completion through the persistent session owner’s runtime adapter. A completion cursor, Consumed input phase, or accepted interrupt is not completion proof. After the deadline, the RPC remains an error even if compaction completes later. The existing five-second secondary observation budget allows exact late completion and profile restoration to be reported. If it expires, error.data reports kind: "compact_member_timeout", stage: "terminal_pending" and an operation_id; the runtime still owns completion and profile cleanup. Dropping the RPC caller does not drop that ownership. Read failures likewise report pending/unknown fate and retain the same input’s observer, without resending. Concurrent compaction of the same identity refuses while that operation owns it. An uncertain admission reply follows the same original key through these reads; it never causes a second submission. The pending-operation record is separate from the build override, which applies only to the intended maintenance build. Only an exact successful terminal for the captured session and incarnation authorizes clearing the floor and rebuilding the same session. A failed terminal preserves its completion_type and typed error metadata; supersession refuses restoration rather than reviving a retired identity or touching its replacement. Supersession invalidates only that operation’s obsolete override; it does not rebuild the member or let the old floor leak into a later incarnation. No timeout triggers retirement, transcript discard, or a synthetic healthy state. Stock persistent compositions supply the exact observer. Custom compositions must forward CommittedBoundaryRecoverer::runtime_completion_observer or use MobBootstrapSpec::with_runtime_completion_observer with the concrete persistent session service’s canonical runtime adapter. This is separate from the bootstrap adapter override. Missing capability returns -32016 before installing a floor; an observer-only injection does not claim recovery support. Result: identity, session_id, floor_tokens, messages_before, messages_after, compaction_applied, head_revision, last_rewrite_reason (message counts and revision facts are null when the gateway has no concrete transcript-edit service).

mobkit/bound_member_transcript

Surgical escape hatch: commit one audited keep-last-N transcript rewrite on a QUIESCED member session (running sessions refuse with -32015; retire or park the member first). The cut point is pair-safe: it never separates an assistant tool-use message from its adjacent tool_results. The removed prefix is replaced by one operator marker notice, and the rewrite is committed with a compare-and-swap against the head revision observed at read time. Params: identity (required), keep_last (default 50), note (optional audit note recorded on the rewrite reason). Result: bounded, removed, kept, message_count, parent_revision, revision (or bounded: false with removed: 0 when the transcript is already within keep_last).

Scheduling migration

Contract 0.5.0 removed mobkit/scheduling/evaluate and mobkit/scheduling/dispatch. Both names now return the standard -32601 method-not-found error. Use the durable schedule tools and ScheduleService, which own schedule definitions, occurrence claims, firing records, and target delivery. See Scheduling for migration guidance.

Session store methods

mobkit/session_store/bigquery

Execute BigQuery-specific session store operations.

Storage methods

mobkit/storage/doctor

Read-only storage diagnosis over a MobKit state directory (the diagnose half of Meerkat’s StorageMigrator seam). Safe against a live gateway: read-only SQLite opens, no file creation, no leases, no schema-ledger runs. Reports the per-directory database inventory (with schema-ledger versions), file-name twins (sessions.db beside sessions.sqlite, continuity.db beside identity_continuity.sqlite, agent-memory/ beside agent-memory-sqlite/, …), the continuity checkpoint-evidence census per identity, dangling console-frame blob references, legacy-FS blob objects, and filesystem artifacts. On a live persistent gateway the H1/H2 durability resolution (blob-durability, session-store-incremental) is attached as findings; a cold directory reports durability-census-unavailable. Available on the module-only, unified, and console (POST /console/rpc, read method, runtime.admin grant) surfaces. Additive method — no contract_version bump.

Subscribe methods

mobkit/events/subscribe

Return a bounded replay snapshot of merged runtime events. The result includes both typed event envelopes and the same events rendered as SSE frames; this method does not itself open a live HTTP stream.
Scopes have these meanings: The server applies the scope first, then retains at most the three newest matching events. With no last_event_id, all retained events are returned. With a checkpoint, replay starts at that event, inclusively. A checkpoint that is unknown, belongs to another scope, or has fallen outside the three-event window returns JSON-RPC -32602. A reconnecting consumer should deduplicate the first replayed event by event_id.

Console ingress

The older console.route style is not the stock console contract. Use GET /console/experience, GET /console/timeline, and POST /console/rpc instead.

See also