mobkit_gateway serves it directly. A persistent, SDK-driven
rpc_gateway also mounts the console routes, but the two binaries are not
interchangeable: SDK hosts drive rpc_gateway over stdio, while
mobkit_gateway accepts its init handshake and then serves console/admin HTTP.
The console provides real-time visibility into agents, conversations, events,
logs, approvals, and recovery actions. The stock shell is built from shared
@console-core and @console-components packages, while app-specific policy
stays in runtime config and host code.
Accessing the console
Once the runtime is serving HTTP, open the console at:http_base_url in their init result. A Rust library host chooses its own bind
address. http://localhost:8080/console is correct only when your host or
reverse proxy explicitly publishes MobKit there.
The HTML, JavaScript, and CSS are compiled into the binary via include_str!, with no external CDN or build step at deployment time.
For development with instant hot-reload:
Runtime contract
The bundled console uses a small set of stable protocol surfaces:
The console contract version is
0.5.0 in console/src/lib/contract.ts and docs/rct/console-rest-sse-contract-v0.5.0.json. The runtime JSON-RPC contract is separately versioned by MOBKIT_CONTRACT_VERSION.
Gateway custody also differs. rpc_gateway installs a SQLite console timeline
store only when its init request configures persistent_state; long-lived
--persistent process mode alone does not make the timeline durable. Without
persistent state, its timeline stays in memory. The console-only
mobkit_gateway also keeps its timeline in memory. Do not infer timeline
durability from the presence of the same browser shell and route names.
Layout
The console uses a configurable workbench layout built on the sharedConsoleWorkbench component:
Sidebar - controls and roster
The left column is navigation. It can show stock controls such as topology, roster, logs, health, and approvals, plus app-defined buttons. Clicking an agent opens chat; details and profile-style data belong in roster surfaces. Agents can be grouped by configured selectors. The default useful pattern is labels first, then structural fallbacks:- Agent display name and member ID
- Status badge (active, running, idle)
- Pin action; pinned agents persist in local storage after the first user interaction
Dock — Chat panels
The center area is a multi-panel tabbed workspace. Each panel contains aConversationPane with a ConsoleComposer.
Tab strip at the top:
- Click a tab to switch panels
+to create a new empty tab×to close a tab
- Textarea with “Message …” placeholder
- Send button (↑) — also supports Enter to send, Shift+Enter for newline
- Footer shows: target agent, member ID, profile, and status
Signals rail - event feed
The right column shows user-meaningful signals: requests, assistant replies, peer messages, image events, relevant tool activity, and alert levels. Low-level transport envelopes, scaffold prompts, raw checksum tokens, and raw tool metadata are filtered out before reaching the user-facing view.WorkGraph panel - Tree and Graph views
The WorkGraph panel (sidebar nav entry, visible when the runtime wires a WorkGraph service) readsmobkit/workgraph/snapshot and offers two views of the same data via the Tree | Graph toggle in the panel head. Tree is the default: an indented item list with claim/close actions plus the attention-binding and recent-event sections. Graph draws a read-only layered DAG - roots leftmost, one column per parent-edge depth, solid arrows into parents, dashed amber blocks edges, node borders/dots in the item-status palette (pulsing blue in progress, green completed, red failed, amber blocked, struck-through cancelled). Drag to pan, wheel to zoom, Fit resets, clicking a node shows its id/status/owner detail underneath. The view caps at 200 nodes and reports the overflow; all mutations stay in the tree and attention sections.
Agent grouping
Agents are grouped in the sidebar byconsole_config.agent_list. Selectors support labels.<key>, label:<key>, raw label keys, and direct fields such as group, subgroup, role, kind, identity, member_id, and agent_id.
Prefer mob member labels for domain-specific grouping:
Well-known labels
Console configuration
The stock console can be shaped byconfig/console.toml in the conventional workspace layout. mobkit_gateway loads that file automatically; rpc_gateway accepts runtime_options.console_config_path, and the TypeScript builder exposes .consoleConfig("config/console.toml").
The parsed config is projected through GET /console/experience as console_config.
CSS customization
The console uses the shared@console-components stylesheet with --cc-* CSS custom properties. Override these on a wrapper element with data-cc-theme="dark" (or "light").
Key tokens
Theming
The console defaults to dark mode. Setdata-cc-theme="light" on the root to switch to light mode. The shared components respond to both themes.
The sidebar uses a panel surface background (rgba(21, 22, 27, 0.82)) to differentiate from the main area. The body background is #131316.
Resizable panels
Both the sidebar and activity rail are resizable by dragging the edge dividers:- Sidebar divider — drag the right edge of the sidebar (min 180px, max 420px)
- Activity rail divider — drag the left edge of the activity rail (min 200px, max 480px)
Experience metadata
The console fetches its initial state fromGET /console/experience, which returns agent data, topology, and health information. The key field for the sidebar is agent_sidebar.live_snapshot.agents:
"addressable" and "internal_only".
Messaging protocol
1
Seed the timeline
Panels load recent visible frames with
GET /console/timeline?identity=identity:luka&mode=recent&limit=.... Older history is paged with before; live continuation uses latest_cursor.2
Send message
Identity-addressed panels call Returns
mobkit/console/send through POST /console/rpc:{ "interaction_id": "...", "identity": "..." }.idempotency_key must be unique per send; the stock console mints one
UUID per send. Reusing a key with different content is rejected with HTTP
409 / JSON-RPC -32009 idempotency_conflict. Reusing a key with
identical content is a replay: the original acceptance is returned and the
turn is not run again.The legacy POST /console/send route still exists for compatibility. New console clients should prefer JSON-RPC.3
Receive response frames
The timeline stream delivers canonical console frames:Correlate a send with its terminal by
interaction_id on frames whose
source.kind is console_event. Session-history backfill re-emits past
turns as frames with source.kind = "session_history"; they carry the
persisted interaction id of the turn they replay and are never fresh
completions, so clients MUST exclude them from live turn handling (the
rule is stated with the frame shape under mobkit/console/query_timeline
in the JSON-RPC reference).If a requested cursor is no longer replayable, the stream returns 409 replay_unavailable; refetch a recent page and resume from its latest_cursor.Console routes
Primary RPC methods:
mobkit/console/send- identity-addressed console sendmobkit/interact- identity-addressed interaction that returns a/console/identity/{identity}/streamroutemobkit/console/query_timeline- timeline replay querymobkit/console/list_identitiesandmobkit/console/inspect_identity- identity-first inspectionmobkit/blob/upload- multipart blob uploadmobkit/reload_member- non-destructive cold reload of one identity’s live member (same session, same generation); the repair for a member whose sends fail with the reload-required class. Gated by theagent.respawnaction.mobkit/member_healthis the matching read (agent.view): lifecycle state, last delivery error class, and the actor-loop probe verdict with the openstall_id, from in-process reads that answer during a stall.mobkit/retire,mobkit/respawn,mobkit/reset, andmobkit/reset_all- operator lifecycle actions.reset_allresets every identity the identity runtime knows (generation advance, oneidentity_resetlifecycle frame each, listed underreset) and retires only members with no registered identity, such as raw delegates (listed underretired_delegates); a registered identity on a runtime without a session bridge fails the preflight withidentity_reset_requires_session_bridgeand nothing is touched. Registered identities are classified by lifecycle state first: aretiringidentity is leaving the fleet and appears in no list, and a registered identity with no live member (dormantbefore its first send,brokenafter a failed materialize) is listed underfailedwithkind: identity_not_resettable_in_stateand itsstate, because a reset is the bridge’s successor transition and needs a live member to replace; the identities beside it are still reset, and the call answers-32000with the full body inerror.datamobkit/send_message- legacy member-addressed send pathmobkit/topology/query,mobkit/topology/plan,mobkit/topology/apply,mobkit/topology/operation/get, andmobkit/topology/audit/query- optional, revisioned connection management and separately permissioned durable audit
topology.bulk.
The reusable TopologyPanel keeps the authority-local and bilateral CAS
contracts distinct. Stock JSON-RPC hosts supply the scalar query revision.
Same-process coordinator hosts also supply the exact
authority_revisions map as authorityRevisions; mutation callbacks receive
that map as expectedAuthorityRevisions and must pass it to the bilateral
coordinator as expected_revisions. Cross-authority hosts must never collapse
that map to the scalar local revision or route the intent through the local
JSON-RPC adapter. They may use topologyAuthorityRevisionToken as the
component’s scalar view token when the coordinator snapshot has no scalar
revision, but never as the coordinator CAS value.
Editable mode requires a durable runtime state path; MobKit fails closed
rather than accepting reconnect/suppression intent that would disappear on
restart:
Authentication
Coarse console access is governed byConsolePolicy:
require_app_auth defaults to true. The SDK builders expose the opt-out as
consoleAuthRequired(false) (TypeScript) and console_auth_required(False)
(Python); rpc_gateway reads it as runtime_options.console_require_app_auth.
When require_app_auth is true, protected console JSON, RPC, blob, and stream
requests are checked against the AuthPolicy. The shell, static assets, and
/healthz remain public. See authentication for the
exact HTTP surface boundary.
When read_only is true, the console can inspect identities, timelines,
logs, and topology, but chat sends, uploads, lifecycle controls, and other write
RPCs are denied server-side.
For per-principal and per-agent authorization, install MobKit’s optional
AccessController from config/access.toml or the runtime builder. When
enabled, its ABAC policy is deny-by-default with deny-overrides across console
REST, JSON-RPC, and SSE. JSON-RPC denials use code -32030 with
data.kind = "access_denied"; REST and SSE return HTTP 403. mob.observe
authorizes mob-level observation but does not grant agent.view for every
agent. To observe everything, a principal needs both mob.observe and an
applicable agent.view grant.
Upstream hosts that already know a user’s ACL can also force the stock console UI
into view-only mode without changing MobKit auth: set
window.__MOBKIT_CONSOLE_READ_ONLY__ = true before loading the console bundle,
or append ?console_read_only=true (also accepted:
mobkit_console_read_only=true or view_only=true) to the console URL. This is
a frontend-only affordance for per-user UX; direct RPC calls are still governed
by the server-side ConsolePolicy.read_only setting.
Console mutation endpoints assume non-ambient credentials: pass bearer tokens
explicitly in the Authorization header or auth_token query parameter for
SSE/browser bootstrap cases. If a host proxy converts console auth into cookies
or another browser-ambient credential, that host must add origin and CSRF
protection before exposing mutation routes such as /console/rpc,
/console/rpc/multipart, or /console/send.
Build system
The console has two build modes:
The production build resolves
@console-core and @console-components as local workspace packages via esbuild aliases. The browser bundle and CSS are embedded in the gateway binary.
Development workflow
console/src/ or packages/ — changes appear instantly in the browser.
Architecture
console-core and console-components) are designed to be consumed by any application — MobKit, meerkat-app, or other hosts. They never import app stores, network code, or platform-specific APIs.
See also
- Unified runtime — how the console is composed with the runtime
- SSE API — protocol details
- Authentication — console access control
