- 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 - lossy WorkGraph wake events through
GET /mobkit/workgraph/facts/stream - console timeline replay and live continuation through
GET /console/timeline/stream - identity-filtered console timeline streaming through
GET /console/identity/{identity}/stream
mobkit/events/subscribe JSON-RPC method returns bounded replay
snapshots in SSE frame format, but does not open a stream.
Authentication
Every SSE route honorsRuntimeDecisionState.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
=, &, +, %) is handled correctly.
Agent event stream
Content-Type: text/event-stream).
Frame format
Console timeline stream
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:
latest_cursor rather than retrying the stale cursor.
Identity timeline stream
identity from the path and otherwise behaves like GET /console/timeline/stream.
Event subscription
Use themobkit/events/subscribe JSON-RPC method to request a bounded
point-in-time snapshot. It returns each selected event both as a typed envelope
and as an SSE-ready frame. It does not open a live connection or return a
stream URL; use the HTTP routes on this page for live observation.
Example request:
Supported scopes:
For
agent scope, agent_id may be the exact projected ID or the bare alias
whose only difference is a trailing numeric generation suffix. The server
applies the scope first and retains at most its three newest matching events.
last_event_id is an event_id from an earlier
mobkit/events/subscribe result, not an HTTP SSE frame ID. It must be present
in that bounded, scope-filtered window. Replay is inclusive: the checkpoint
event is returned again, followed by later retained events. An unknown,
out-of-scope, or expired checkpoint returns JSON-RPC -32602, so reconnecting
consumers should deduplicate the first event by event_id.
WorkGraph wake stream
data field is a bare UnifiedEvent::Module value with module
mobkit.workgraph; the event is not wrapped in EventEnvelope and is not
duplicated into GET /mob/events or mobkit/events/subscribe.
Every connection starts with this mandatory resynchronization signal:
mobkit/workgraph/get,
mobkit/workgraph/list, mobkit/workgraph/ready, or
mobkit/workgraph/snapshot. Subsequent workgraph.fact events carry
identifiers that can accelerate another read, but they are never state
authority.
The stream has no SSE id, Last-Event-ID, cursor query, catch-up, or replay
contract. A slow consumer can miss events. When broadcast lag occurs, the
server sends workgraph.resync_required with reason: "lagged" and the
number of skipped wakes in skipped; read authoritative WorkGraph state again.
When access control is enforced, the caller also needs the workgraph.view
grant.
Structural mob events stream
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
Ifafter_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 upstream meerkat ledger cursor. Consumers
can checkpoint it and reconnect with after_seq=<checkpointed cursor> only
while the configured mob-event store retains that cursor and its later events.
.persistent_state(path) alone does not make the mob-event ledger durable. It
persists MobKit projection metadata, while the stock unified-runtime builder
still uses in-memory Mob storage. Restart-safe replay requires a separately
configured upstream Meerkat mob-event store that retains the ledger across the
restart. If a checkpoint is ahead of the available ledger, the route returns
HTTP 410 Gone as described above.
Keep-alive
The server sends keep-alive frames at a configurable interval (default: 15 seconds) to prevent connection timeouts:latest_cursor or a fresh Last-Event-ID.
Sending messages
To send a message to an agent, use themobkit/send_message RPC method and capture the returned session_id for correlation:
GET /console/timeline/stream or
GET /console/identity/{identity}/stream. Use mobkit/events/subscribe only
when a bounded merged-event replay snapshot is sufficient.
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
- REST API — HTTP endpoints overview
- Console guide — how the console uses SSE
- Events — unified event model
