Skip to main content
This page documents MobKit v0.8.34 (mirrored from v0.8.34). MobKit ships a web-based operator console through its HTTP composition. The console/admin 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:
Both gateway binaries bind an available loopback port and report the exact 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 shared ConsoleWorkbench component:
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:
Each agent row shows:
  • Agent display name and member ID
  • Status badge (active, running, idle)
  • Pin action; pinned agents persist in local storage after the first user interaction
Non-addressable agents (e.g., Gate, Health Monitor) appear dimmed and cannot be messaged.

Dock — Chat panels

The center area is a multi-panel tabbed workspace. Each panel contains a ConversationPane with a ConsoleComposer. Tab strip at the top:
  • Click a tab to switch panels
  • + to create a new empty tab
  • × to close a tab
Split panels — click the split controls (← → ↑ ↓, visible on hover) to divide a panel. This lets you chat with multiple agents side-by-side. Composer at the bottom of each panel:
  • 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) reads mobkit/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 by console_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 by config/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.
Keep this config view-level. It should decide presentation, ordering, visibility, labels, defaults, and links. It should not decide runtime authorization, routing, or whether an agent exists.

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. Set data-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)
The resizers use pointer capture for smooth dragging and show a subtle glow line on hover.

Experience metadata

The console fetches its initial state from GET /console/experience, which returns agent data, topology, and health information. The key field for the sidebar is agent_sidebar.live_snapshot.agents:
Identity-first status and inspect payloads use lowercase wire enums for addressability: "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 mobkit/console/send through POST /console/rpc:
Returns { "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 send
  • mobkit/interact - identity-addressed interaction that returns a /console/identity/{identity}/stream route
  • mobkit/console/query_timeline - timeline replay query
  • mobkit/console/list_identities and mobkit/console/inspect_identity - identity-first inspection
  • mobkit/blob/upload - multipart blob upload
  • mobkit/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 the agent.respawn action. mobkit/member_health is the matching read (agent.view): lifecycle state, last delivery error class, and the actor-loop probe verdict with the open stall_id, from in-process reads that answer during a stall.
  • mobkit/retire, mobkit/respawn, mobkit/reset, and mobkit/reset_all - operator lifecycle actions. reset_all resets every identity the identity runtime knows (generation advance, one identity_reset lifecycle frame each, listed under reset) and retires only members with no registered identity, such as raw delegates (listed under retired_delegates); a registered identity on a runtime without a session bridge fails the preflight with identity_reset_requires_session_bridge and nothing is touched. Registered identities are classified by lifecycle state first: a retiring identity is leaving the fleet and appears in no list, and a registered identity with no live member (dormant before its first send, broken after a failed materialize) is listed under failed with kind: identity_not_resettable_in_state and its state, 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 -32000 with the full body in error.data
  • mobkit/send_message - legacy member-addressed send path
  • mobkit/topology/query, mobkit/topology/plan, mobkit/topology/apply, mobkit/topology/operation/get, and mobkit/topology/audit/query - optional, revisioned connection management and separately permissioned durable audit
Topology management is opt-in at the runtime. With the default disabled policy, the stock console remains a passive topology viewer and does not show the Connections tab. Read-only mode exposes searchable connection state with server-provided denial reasons. Editable mode offers only pairwise actions authorized for both endpoints; bulk controls appear only when a host supplies an explicitly bounded action and the runtime advertises 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 by ConsolePolicy:
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

Edit any file in console/src/ or packages/ — changes appear instantly in the browser.

Architecture

The shared packages (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