Skip to main content
MobKit uses Server-Sent Events (SSE) for several real-time flows:
  • agent-scoped streaming through GET /agents/{agent_id}/events
  • mob-merged streaming through GET /mob/events
  • structural mob events through GET /mobkit/mob_events/stream
  • console timeline replay and live continuation through GET /console/timeline/stream
  • identity-filtered console timeline streaming through GET /console/identity/{identity}/stream
  • event subscription and replay through mobkit/events/subscribe

Authentication

Every SSE route honors RuntimeDecisionState.console.require_app_auth. When require_app_auth is on, the request must carry one of:
  • Authorization: Bearer <token> header, or
  • ?auth_token=<token> query parameter
Missing or invalid credentials return HTTP 401. Tokens are percent-decoded; a token containing characters that need URL-encoding (=, &, +, %) is handled correctly.

Agent event stream

Subscribe to raw Meerkat agent events for one agent (Content-Type: text/event-stream).

Frame format

Console timeline stream

Streams a bounded replay snapshot followed by live console timeline frames. The route accepts the same identity, conversation_id, after, before, mode, and limit parameters as GET /console/timeline. If replay cannot satisfy the requested cursor, the server returns HTTP 409 with:
Clients should resume from latest_cursor rather than retrying the stale cursor.

Identity timeline stream

Convenience route for an identity-filtered console timeline stream. It sets the timeline query identity from the path and otherwise behaves like GET /console/timeline/stream.

Event subscription

Use the mobkit/events/subscribe JSON-RPC method to request a point-in-time event snapshot plus replay frames. Example request:
The response includes: Supported scopes:

Structural mob events stream

Per-client SSE stream of structural MobEvents (typed envelopes preserving mob_id, run_id, step_id, agent_identity, and the full MobEventKind payload). Each connection opens its own MobEventsView::subscribe_after so catch-up and live tail share the same ordered stream — there is no race window between snapshot and live subscription.

Query parameters

Frame format

Stale cursor

If after_seq > latest_cursor, the route returns HTTP 410 Gone with {"error":"event_query_stale","after_cursor":N,"latest_cursor":M}. SDK clients should rewind to latest_cursor and reconnect.

Continuation from mobkit/mob_events/subscribe

The JSON-RPC handshake returns a snapshot frame plus a subscribe_url field that already encodes the resume cursor and filters:
after_seq falls back to latest_cursor captured at handshake when the snapshot is empty, so the SSE handler picks up gaplessly even when no events match yet.

Cursor durability

MobStructuralEvent.cursor is the meerkat ledger cursor — durable across mobkit gateway restarts when the runtime is built with .persistent_state(path). SDK consumers can checkpoint a cursor and resume by reconnecting with after_seq=<checkpointed cursor>.

Keep-alive

The server sends keep-alive frames at a configurable interval (default: 15 seconds) to prevent connection timeouts:
When the console timeline broadcast lags (slow consumer, channel saturated), the stream closes. Clients should refetch a recent timeline page and reconnect from the returned latest_cursor or a fresh Last-Event-ID.

Sending messages

To send a message to an agent, use the mobkit/send_message RPC method and capture the returned session_id for correlation:
Then observe streamed responses via GET /console/timeline/stream, GET /console/identity/{identity}/stream, or broader replayable event history via mobkit/events/subscribe.

Error handling

If the target agent/member does not exist or a subscription request is malformed, SSE routes return an HTTP error response before opening the stream:

See also