Base URL
meta_gateway and SDK-facing persistent rpc_gateway
bind an available loopback port and report the exact http_base_url in their
meta/init result. Use that value for every route on this page; do not
assume port 8080. A Rust library host chooses its own listener and must supply
that base URL to its clients.
Console endpoints
GET /console
Returns the admin console HTML page. The page is a self-contained single-page React application with no external dependencies.
Response: text/html
GET /console/assets/console-app.js
Returns the console React bundle as JavaScript.
Response: application/javascript
GET /console/assets/console-app.css
Returns the console stylesheet.
Response: text/css
JSON API endpoints
GET /console/experience
Returns experience metadata describing the current runtime state. This is the primary data source for the console UI.
Response:
console_config, the view-level contract consumed by the bundled console.
An agent row in agent_sidebar.live_snapshot.agents, and its rows in
identity_status and health_overview, can carry last_activity_ms: the
newest time, in milliseconds since the epoch, that the console’s frame log
recorded the agent acting (a live runtime event, a console send or a tool
application). Frames rebuilt from session history or synthesized by the
console do not count, and neither do lifecycle records (respawn, retire,
reset, delete), interaction failures and memory events, which record
something done to the agent. The field is advisory: a row without it has no
known activity, and reading it wakes no agent. A row answered pending (below)
keeps it, since the frame log answers it, not the read model.
The gateway reads each agent’s newest acting frame from the log on the first
experience after it starts that lists the agent, 256 agents per store call,
and keeps the time in memory after that. At 10,000 agents that first read
takes about 56 ms in all when the agents’ newest frames record them acting,
and longer when many of those frames do not (rebuilt history, for example),
at about 0.4 to 0.9 microseconds per such frame. A retire, a delete or a
clear made meanwhile waits for at most one such call, and so do the console
writes queued behind it.
topology.live_snapshot.mob_id is the id of the mob whose members the
topology shows, when one mob is known: a runtime’s console reports its own
mob, and a shared console the mob of its one registered runtime. It is absent
on a shared console over several runtimes or none, and from a snapshot a host
builds without it. The console names the topology’s team from it, never from
runtime_id.
health_overview.live_snapshot.running is the mob owner’s answer when the
experience is read. A console served from the console aggregator answers for
its registered runtimes: true only while every registered runtime’s mob is
creating or running, and false when at least one is not. Without a runtime
that can answer (no live mob runtime, or an aggregator with no registered
runtime), it is null, and the snapshot names it in an unobserved marker:
{"reason": "not_observed", "fields": ["running"]}.
An identity-first member’s records take its session from the identity
runtime, never from a walk made under an earlier identity binding. When the
member’s binding has moved (after a reset, retire or delete), a read collects
the member again first and waits at most 2 s. Past that bound, the member’s
sidebar row answers with the identity runtime’s session, the member’s run
progress and state unknown, and offers no send or retire. Each record of
the member (the sidebar row, the identity_status and health_overview
rows, and the topology node) withholds the other facts the earlier walk
found and names them in an unobserved marker with reason
refresh_pending, for example
{"reason": "refresh_pending", "fields": ["label", "role", "state", "wired_to", "addressable"]}
on the topology node. Access and visibility still decide on the last
observed facts, so a label-scoped deny keeps such a member hidden.
GET /console/modules
Returns the configured module IDs from RuntimeDecisionState. This response
does not contain per-module health or startup state.
Response:
GET /console/identities
Returns visibility-filtered identities from the console aggregator, including
ordinary runtime/worker identities; an identity-first runtime is not required.
Without a console aggregator, this route returns 404 with
error: "unavailable".
Response: {identities: ConsoleIdentityRecord[]}. Each record carries
identity, display_name, runtime_key, runtime_member_id, optional
session_id, optional member_id (Core’s mob member id of the identity’s
last binding, live or retired: the identity’s roster member id, as Core’s
member tokens name it, which is Meta’s comms-safe encoding of the identity and
starts with mk-- when the identity has a :; absent when Core holds no
binding of the identity and on records of raw runtime members),
visibility, addressable, health, labels, and
topology_peers when non-empty. Use
meta/console/inspect_identity
for identity/peer inspection and /console/experience for affordances;
neither identities nor inspection records contain an affordances field.
GET /console/timeline
Returns console timeline frames from the Meta console log store. This endpoint is the REST equivalent of meta/console/query_timeline.
Query parameters
Query parameters
next_cursor is safe to use as the next after cursor for since pagination; latest_cursor is the latest cursor for the target window and is useful for live continuation after a recent seed.
The log keeps a streamed block’s text_delta and reasoning_delta frames until the block’s text_complete or reasoning_complete frame is stored, then removes all of them but the first, which keeps the block’s place in the timeline: a later read returns that first frame and the complete frame, whose text supersedes it, and live streams have already delivered each delta. A block that never completes keeps its deltas. Cursors are never renumbered, so the cursor of a removed frame still works as after or before.
GET /console/timeline/stream
Streams timeline replay followed by live console frames (text/event-stream).
It accepts the same query parameters as GET /console/timeline, but limit
does not bound the whole replay: recent produces one bounded seed page
(limit sizes it), while anchored since replays all retained matching
backlog, sent page by page as it is read, whatever limit says. Without
after, since switches to recent. A non-empty Last-Event-ID header
overrides the URL’s after parameter. See the
timeline SSE contract for event envelopes
and snapshot markers.
If the requested cursor can no longer be replayed, the route returns HTTP 409 with {"error":"replay_unavailable"} and cursor context. Clients should refetch a recent page and resume from latest_cursor.
An anchored replay can also end after the stream opened: if the log no longer holds what follows the frames sent (it was cleared during the replay), the stream sends a replay_unavailable event and ends, to be handled as the 409; if a later page cannot be read, the stream ends after the frames it sent, with no snapshot_complete, and the client reconnects with the last frame’s cursor as Last-Event-ID.
GET /console/identity/{identity}/stream
Identity-filtered convenience route for the same console timeline stream. It sets the identity filter from the path and accepts the remaining timeline query parameters.
POST /console/send
Legacy console send route backed by the console aggregator. New clients should prefer POST /console/rpc with meta/console/send.
POST /console/send/recover
REST twin of meta/console/recover_send:
the body is {identity, origin, idempotency_key} and the caller is the
request’s authenticated principal. It runs the same gate as /console/send
(read-only and agent.send refusals). A send the caller does not own, or
never made, answers HTTP 404 with {"error":"send_not_found"}. A
candidate launch (runtime_options.mob_composition.authority = "candidate") settles no send and answers HTTP 409 with
{"error":"candidate_launch"}, as /console/send does: recover the send on
the authoritative launch. It waits for the runtime’s admission evidence as
the RPC does: up to 45 seconds in all when the store is slow (after a restart,
reading the evidence loads the session the send recorded), so an HTTP client
whose timeout is shorter gives up first. console_fetch_timeout_ms, the bundled
console’s fetch timeout, should stay above 45 seconds.
POST /console/rpc
JSON-RPC 2.0 endpoint for console and runtime operations.
POST /console/rpc/multipart
Multipart JSON-RPC endpoint. Supported methods:
For
meta/blob/upload, send a payload part containing this JSON-RPC
request, plus exactly one binary part named file:upload-1 with
Content-Type: image/png:
params. part_name is an
alias for upload_id; both identify the suffix after file:, with
upload_id taking precedence if both are present. type is optional and,
when supplied as a string, must be image_upload. Optional media_type
must match the file part’s MIME type. Supported types are image/png,
image/jpeg, image/webp, and image/gif, with a 25 MiB per-file limit.
The result contains blob_id, media_type, and size in bytes, not url
or content_type. Fetch the bytes through GET /blobs/{blob_id}.
Console sends with image placeholders remain subject to the multipart
image-count and per-file byte limits.
GET /blobs/{blob_id}
Returns blob/image content by ID when a blob store is configured.
Authentication
The reference router keeps its frontend shell and bootstrap assets public:/,/favicon.ico, and/healthz/console,/console/, and/console/assets/*/flow-editor,/flow-editor/, and/flow-editor/assets/*
ConsolePolicy.require_app_auth is true, the console JSON, JSON-RPC,
timeline, blob, Flow Editor RPC, and SSE surfaces require a valid JWT. Clients
may use either a bearer header:
=,
&, +, and %. Prefer the header except for browser or SSE bootstrap cases.
The token is validated against the fixed trusted OIDC snapshot and configured
auth policy. See authentication for details.
Meta’s built-in console auth is bearer-token based and does not rely on
cookies. Deployments that add cookie-backed console auth at a reverse proxy must
also add CSRF/origin protection for mutating console routes.
Set ConsolePolicy.read_only to true to serve the console in view-only mode.
Read endpoints and streams remain available, while mutating JSON-RPC methods
such as meta/console/send, meta/blob/upload, lifecycle controls, gating
decisions, and metadata writes are omitted from meta/capabilities and return
a read-only error if called directly.
Error responses
API errors return standard HTTP status codes with a JSON body:
Structured
/console/send admission failures carry {error, message, data}:
429 uses admission_backlog_full, 503 uses actor_probe_unhealthy or
reload_refused, and 504 uses admission_timeout or reload_timed_out.
Preserve data when reporting these failures; a timeout does not by itself
establish execution fate or retryability. These REST status mappings are
distinct from the JSON-RPC policy codes documented in the
RPC reference.
See also
- JSON-RPC — full programmatic API
- SSE API — event streaming protocol
- Console guide — admin console details
