MobMemberListEntry projections. Deep execution
inspection is a separate operation that returns MobMemberSnapshot.
Profiles are templates and members are declared
A[profiles.<name>] entry in mob.toml is a role template: model, tool
posture, skills, runtime mode, peer description. It produces no member. A
member exists only when something names it:
- the identity roster: the
RosterProvidercallback onrpc_gateway(Python.roster(provider), TypeScript.rosterProvider(provider)), or theidentity_rostertop-levelmobkit/initparam onmobkit_gateway(a list ofDurableAgentSpecobjects, restored at boot and extended at runtime bymobkit/ensure_member); - a Rust
Discoveryimplementation onUnifiedRuntimeBuilder(classic, non-identity boot only; neither gateway binary wires one); - an explicit
mobkit/ensure_member.
orchestrator names a profile, not a member. The only automatic
spawn anywhere is mobkit_gateway’s no-config fallback, which ensures a single
alpha member of its built-in definition when no config/mob.toml or
definition.json exists; a workspace definition with an empty
identity_roster boots with no members at all.
The roster callback does not hand you the definition. On rpc_gateway the
gateway sends callback/roster_provider/roster with the serialized
RosterContext (mob_definition, always the definition the gateway booted
with, and previous_identities) as the request params, but the Python and
TypeScript SDK dispatchers pass the provider params["context"], a key the
gateway does not send. The context argument your roster(context) receives
is therefore an empty dict or object on both SDKs, and
context["mob_definition"] raises KeyError. A host that wants a
profile-shaped crew derives it from the definition it already holds, the same
mob.toml text it passes to .mob_inline(...) (HomeCore builds its roster the
same way, from its own parsed config, and ignores context):
When to call reconcile_edges
Declared definition wiring ([wiring] auto_wire_orchestrator = true or
role_wiring rules) is applied by meerkat only at spawn time and, for the
orchestrator rule, only from the non-orchestrator side, so the result depends on
bring-up order. MobKit installs the definition’s wiring as a reconcilable edge
policy and converges it with mobkit/reconcile_edges (Python
handle.reconcile_edges(), TypeScript handle.reconcileEdges()).
mobkit/ensure_memberalready runs that reconcile after every successful ensure, on both the worker plane and the console identity plane. Callingreconcile_edgesafterensure_memberis redundant.mobkit/reconcile_identity(Pythonruntime.reconcile()) and the identity-first gateway boot do not: the gateway reconciles definition edges before the roster is materialized. When the definition declares wiring, callreconcile_edgesonce after boot and after eachruntime.reconcile().- Without declared wiring there is no definition edge policy; the call returns
an empty report. Edges from a host
TopologyProviderconverge on every identity restore and reconcile on their own, and the reconciler never unwires an edge it did not wire itself.
Roster operations
All operations are available through the gateway’s JSON-RPC interface.ensure_member gateway profiles
The same method name has different ownership and result contracts across the
two gateway profiles:
The identity receipt’s
outcome is created, resumed, dormant, broken,
or unchanged. The other roster operations keep the contracts shown in the
operation table.
Lightweight roster entries
list_members, get_member, and find_members project Meerkat’s
MobMemberListEntry. ensure_member projects the same type only on the
worker-plane paths described above. A raw MobKit worker-plane response has this
shape:
The lightweight entry deliberately omits session IDs and live connectivity
fanout. Use
mobkit/member_status when those details are required.
Runtime modes
runtime_mode comes from the profile ([profiles.<name>] runtime_mode), or
from a per-spawn override where a surface offers one. autonomous_host is
meerkat’s default when a profile omits the key, and it is the mode most hosts
end up on without choosing it. The two modes differ in ways that show up on
the roster and on every send:
- A fresh
autonomous_hostmember runs one kickoff turn as soon as it is spawned, on itsinitial_messageif the spawn carried one, otherwise on meerkat’s fallback prompt (You have been spawned as '<identity>' (role: <role>) in mob '<mob>'.). Thekickofffield on the roster entry reports that turn. Later sends are ordinary durable inputs that queue behind it; nothing is dropped, but the member answers in order. - Autonomous inbox delivery carries no user-channel work boundary, so meerkat
refuses injected context and completion-bearing sends on that path. MobKit
therefore skips ambient per-turn agent-memory recall for
autonomous_hostmembers with the typed reasonruntime_mode_autonomous_host(the turn still runs, without memory). Ambient per-turn memory requiresruntime_mode = "turn_driven"until meerkat’s carrier change lands; the Unreleased entry in the repositoryCHANGELOG.mdrecords this. turn_drivenmembers run exactly one turn per delivered input and sit idle between inputs. It is the mode meerkat’s tracked, completion-bearing turn carriers support; onautonomous_hostthose are refused withtracked turn completion is not supported by autonomous inbox delivery.
runtime_mode = "turn_driven" explicitly on every profile that hosts a
durable, addressable identity unless the member is meant to run its own inbox
loop.
Operational list projections retain active, retiring, and broken rows as
applicable. They filter terminal completed and unknown rows, even though
those values remain part of the status vocabulary.
Deep member status
mobkit/member_status serializes Meerkat’s MobMemberSnapshot. It is a deep
inspection result, not the type returned by roster list operations. Its core
fields are status, output_preview, error, tokens_used, is_final, and
current_session_id. It can also include peer connectivity, kickoff,
external-member observations, resolved model capabilities, execution progress,
placement, reachability, freshness, and lifecycle-capability diagnostics.
The snapshot’s Rust agent_identity is bridge-internal and skipped during
serialization. The requested member ID identifies the result on the MobKit RPC
surface. The snapshot also does not carry the roster entry’s role,
runtime_mode, wired_to, or labels fields.
Member statuses
The knownMobMemberStatus values are:
MobMemberStatus is non-exhaustive. Branch on the known values and tolerate
new status strings. Do not reduce lifecycle handling to only active and
retiring. The Rust MobMemberSnapshot structure is also non-exhaustive.retiring can be transient. At the Meerkat Rust layer, a successful
MobHandle::retire is the terminal lifecycle barrier and returns unit, so a
later roster read can show the member as absent rather than retiring.
Role migration
A durable member’s role is part of its durable identity, not a configuration knob: the stored role, the member’s comms name, and its mob-member binding are one fact. A resume that targets a different role than the durable predecessor is therefore a restamp of identity, and Meerkat refuses it withMobError::MemberRoleMigrationRequired unless that exact resume declares the
migration. If a durable member stopped resuming after a role or profile rename,
this is the refusal to look for.
Migration authority is supplied by the activation, per exact identity, as a
top-level mobkit/init param. It is not a runtime_options field:
RoleMigrationDeclaration dataclasses or plain
{"identity": ..., "from_role": ...} dicts:
MobError::MemberRoleMigrationRejected on mismatch, so a mistyped from_role
cannot authorize an unintended restamp, and MobKit never retries a resume that
Meerkat refused. Once the durable and requested roles agree, Meerkat returns
before it reads the declaration at all, so a declaration left in place after the
migration landed is inert rather than a repeated restamp. That is why an
identical repeated declaration is accepted on purpose, while one identity
declared twice with conflicting predecessor roles is refused.
Only the identity plane carries migration authority. Every mob-plane resume path
passes no declared predecessor role, so a role change reached through the worker
plane still fails closed. Which declarations arm also depends on the binary:
rpc_gateway installs them inside its roster-provider branch, mobkit_gateway
inside its identity-first block. Declarations that reach neither arm nothing,
because there is no identity plane to migrate on.
Peer identity and comms names
A member’s comms (peer) name is{mob_id}/{role}/{member} (meerkat’s
MemberCommsName): the mob definition id, the profile name, and the
mob-roster member id. That is the string peers see in the peers tool and in
Peer message from ... projections; the routing key underneath is the
pubkey-derived peer id.
Identity-first members are registered under an encoded roster id, because a
durable identity such as domain:security contains : and a comms-name
component may only contain ASCII letters, digits, -, and _. MobKit’s
mk-- codec escapes it (domain:security becomes mk--domain_csecurity), so
the peer-facing name is home/domain/mk--domain_csecurity. Console, RPC, and
SDK surfaces decode the id back to the public identity; the model-facing
projections do not.
The mob id is part of every member’s name, so renaming a mob (changing the
definition id) re-mints every peer name in it. Nothing rewrites records that
already hold the old strings: identity-keyed agent memory lives in the host
realm, survives the rename, and can recall {old_mob}/... names into a later
prompt. Renaming a member’s role is a different case and is refused unless
declared, as the previous section describes.
Mutation results
The underlying Meerkat Rust operations have different success types:MobHandle::retirereturnsResult<(), MobError>.MobHandle::respawnreturnsResult<MemberRespawnReceipt, MobRespawnError>. The receipt identifies the respawned member.
MemberRespawnReceipt publicly serializes only identity; its
runtime and fence atoms are internal. Meerkat’s typed mob/respawn surface
wraps that outcome as status (completed or topology_restore_failed), a
receipt containing identity and an opaque member_ref, and optional
failed_peer_ids.
MobKit’s compatibility RPC consumes the worker-plane respawn receipt and
projects both mutations as acceptance acknowledgements. Identity-owned targets
can add identity-first receipt fields such as a fencing token for retire, or a
session ID and generation for respawn. The Python and TypeScript SDK wrappers
discard these acknowledgement objects and return None or void. Re-read the
member when the caller needs the resulting roster or execution state.
SDK projections
The SDK type namedMemberSnapshot wraps the lightweight roster response. It
currently exposes agent_identity, role, state, wired_to, and labels.
It does not expose every field present in the raw MobMemberListEntry JSON.
The separate RichMemberSnapshot type wraps mobkit/member_status.
- Python
- TypeScript
Reconciliation
Reconciliation compares the desired member set with the current roster and spawns, retains, or retires members to converge. See the unified runtime guide for the complete flow.Roster provider context
Every time the identity runtime derives the desired roster it calls the host’s roster provider with aRosterContext. Behind the SDK gateway that is
the callback/roster_provider/roster request, whose params nest the context
under context (the same envelope the topology and customizer callbacks use):
The Python SDK delivers this as
RosterContext from
meerkat_mobkit.identity_first_models; the TypeScript SDK as the exported
RosterContext interface (mobDefinition, previousIdentities).
See also
- Identity-first doctrine - choose the identity plane or worker plane
- Python SDK - Python roster helpers
- TypeScript SDK - TypeScript roster helpers
- RPC API - JSON-RPC protocol and method signatures
- Unified runtime guide - reconciliation and session lifecycle
