Skip to main content
This page is the canonical settled-state contract for session and runtime behavior.

Ownership model

Meerkat has one canonical semantic path:
  • the runtime control plane (MeerkatMachine in meerkat-runtime) owns keep_alive, Queue/Steer routing, comms drain lifecycle, external-event admission, and request/turn commit semantics; runtime-backed surfaces reach those semantics only by lowering into it
  • SessionService is the substrate lifecycle seam used by those surfaces
  • EphemeralSessionService / build_ephemeral_service remain valid for testing, embedded use, and WASM internals, but they are not the primary product path and do not own runtime semantics
The runtime-backed path is:
Surface -> MeerkatMachine -> SessionService -> AgentFactory::build_agent()
The runtime-backed build contract has an explicit binding seam:
  • runtime-backed surfaces should call MeerkatMachine::prepare_bindings(session_id)
  • those bindings flow into SessionBuildOptions.runtime_build_mode = RuntimeBuildMode::SessionOwned(bindings)
  • standalone / embedded / test-only builds should opt into RuntimeBuildMode::StandaloneEphemeral explicitly instead of relying on silent fallback
SessionRuntimeBindings is the epoch-local runtime handle for a session. It carries:
  • session_id
  • epoch_id
  • the canonical OpsLifecycleRegistry
  • shared consumer cursor state used for recovery-safe completion visibility
This keeps one owner for runtime semantics:
  • PersistentRuntimeDriver::recover() owns input/runtime/control recovery
  • MeerkatMachine owns session entry recovery (ops_lifecycle, epoch_id, cursor state)
Direct substrate usage is intentionally narrower:
  • Queue-only turns
  • no runtime-owned keep_alive
  • no Steer/render-metadata semantics
  • no runtime ingress/admission ownership

Agent construction contract

Agent construction is centralized in AgentFactory::build_agent().
  • Surfaces pass per-request build data in-band via CreateSessionRequest.build (SessionBuildOptions).
  • No out-of-band staging lock is used.
  • FactoryAgentBuilder maps SessionBuildOptions to AgentBuildConfig.
  • For runtime-backed builds, SessionBuildOptions.runtime_build_mode should carry RuntimeBuildMode::SessionOwned(bindings) from prepare_bindings().
  • For standalone/testing/embedded builds, prefer RuntimeBuildMode::StandaloneEphemeral explicitly.
  • Session metadata persists realm context and durable session identity:
    • realm_id
    • instance_id
    • backend
    • config_generation
    • durable LLM identity
    • keep_alive
    • visible comms identity metadata such as comms_name and peer_meta

Session lifecycle and turn semantics

create_session

create_session(req) builds the agent and optionally runs the first turn.
  • Returns RunResult with session_id.
  • InitialTurnPolicy::RunImmediately executes the first turn inline (default).
  • InitialTurnPolicy::Defer registers the session without running a turn.
Create has a commit boundary:
  • pre-commit failure: side-effect free; no committed session identity
  • post-commit first-turn failure: return session identity and keep the session resumable
Committed create failure must not be silently rewritten to “cancelled” or cleaned up as unpublished work.

start_turn

start_turn(id, req) executes a new turn on an existing session.
  • At most one in-flight turn per session.
  • Concurrent attempts return SESSION_BUSY.
  • Committed success must not be rewritten to cancellation.
  • Runtime-backed surfaces may hot-swap supported live settings on an existing session where the surface contract says that is allowed.

Deferred first-turn system prompt override

Rust supports system_prompt on StartTurnRequest only for a deferred session’s first turn.
  • deferred + first turn: allowed
  • existing history/messages: rejected
This keeps Rust aligned with the current runtime contract instead of implying arbitrary mid-session prompt replacement.

interrupt

interrupt(id) cancels an in-flight turn.
  • If no turn is running: SESSION_NOT_RUNNING.

read and list

  • read(id) and list(query) are non-blocking with respect to in-flight turns.
  • Persistent services can include durable sessions from the realm backend.
  • Presence in list() is not the same as “live session exists”; runtime-owned seams must answer liveness.

read_history

read_history(id, query) returns the last committed transcript snapshot for a session.
  • Messages are returned oldest-to-newest.
  • offset and limit apply from the start of the full transcript.
  • Active sessions do not expose in-flight partial output through history reads.
  • Archived sessions remain readable on persistent backends; the ephemeral service rejects archived history reads with SESSION_PERSISTENCE_DISABLED.

archive

  • The canonical SessionDocumentMachine owns the session_lifecycle_terminal fact for ALL profiles; shells realize its verdict, they never decide it.
  • Realization order is fail-closed: durable document commit first, runtime retire second. RuntimeState::Retired is the runtime realization of the same verdict, so the resurrection window is unrepresentable.
  • Archived sessions are excluded from list() and rejected for further reads/turns (SESSION_NOT_FOUND on persistent services; the ephemeral service serves a final in-memory view).
  • Committed transcript history remains readable via read_history on persistent backends.

Keep-alive contract

keep_alive is a runtime/session concept, not an old “host mode” execution path. Rules:
  • create / run omitted => default false
  • continue / resume omitted => inherit persisted session intent
  • explicit keep_alive override is a session/runtime mutation once validated
  • invalid keep_alive + comms configuration is rejected before any stateful work
  • once validated, an explicit keep_alive mutation may commit independently of turn success
keep_alive=true requires usable comms identity/config on the surfaces that expose it.

External events

External events are queue-only runtime-backed inputs.
  • they are admitted into runtime ingress
  • they do not invent a second direct execution path
  • “turn-boundary inbox draining” is not the primary mental model for the current runtime-backed design

Explicit override semantics

Where the surface supports omission vs explicit override, these are distinct facts:
  • omit / inherit
  • disable / false
  • set / concrete value
When all three meanings matter, the wire/API must preserve that distinction. Typed optional fields and override masks are preferred over default-value folklore. Concretely: SystemPromptOverride (Inherit / Set / Disable) is the canonical wire+persisted carrier for the per-request system-prompt fact, and per-turn provider parameters travel as the typed ProviderParamsOverride, not a raw JSON bag.

Realm contract

Sessions are realm-scoped.
  • Same realm_id: shared visibility and config context.
  • Different realm_id: strict isolation.
  • Backend is pinned per realm via realm_manifest.json.

Compaction contract

Compaction is optional and non-fatal.
  • Triggered by token thresholds and turn guards.
  • On failure, emits CompactionFailed and continues with uncompacted history.
  • Compaction usage counts toward run budgets.

Durability

Ephemeral mode

No durability across process restart.

Persistent mode

Durability follows the active persistent realm backend (sqlite or jsonl). The memory backend is explicit ephemeral storage and does not survive process restart.
  • Completed turns are persisted.
  • Crash during in-flight turn may lose only that turn.
  • SQLite-backed realms are the default persistent mode and support normal same-realm multi-process workflows.
Persistent session metadata is the source of truth for resumed durable session behavior unless an interactive surface supplies an explicit typed override.

Config concurrency contract

Config runtime uses generation CAS.
  • config/get returns current generation.
  • config/set and config/patch can specify expected_generation.
  • Mismatches fail deterministically with generation conflict.

Data governance

No automatic sensitive-data redaction is applied to session content or tool payloads. Encrypt storage at rest externally if required by your environment.

See also