Operations · 5. Meters and System

Meters answers "what did that session burn, and where did it go". System is every setting, integration and developer surface. This chapter is reference. The two Meters pages share one feed and are useless without it, so §5.1 covers that first.

5.1 Where the Meters numbers come from, and why they might be absent

Both Meters pages read GET /v1/cost/report. That store is POST-fed. Nothing computes a cost report on its own: corecruxctl session cost --post parses a local agent transcript and posts the result (render.js:11162).

Two things must therefore be true before either page shows anything:

  1. CORECRUXD_FEATURE_COST_LENS is enabled on the daemon (cost.rs:30).
  2. At least one report has been posted for the tenant.

The empty state says both, in as many words. That is deliberate: an empty cost page that said only "no data" would be indistinguishable from a broken one.

Neither page claims a saving. The daemon measures no counterfactual, no run of the same work without it, so there is no baseline to compare against. The Usage page carries a card that says exactly that, in place of the savings figure it used to invent (pages.js:1006).

5.2 Meters › Token Burn (Session)

Open this to find the session that cost you the most, and why. One row per posted report, with filters, a totals row and a top-burn chart (render.js:11169).

The filter toolbar

ControlTypeDefaultFilters on
filtersearchemptySession id, source, actor passport, plan slugs, and the agent-given title, summary and actor from the session store
passportselectall passportsOptions are the distinct actor_passport values present, excluding __anon__
planselectall plansThe distinct execplan_slugs present
min burn (out)number, step 1000emptyKeeps rows whose output_tokens is at least this
fromdateemptySession start, UTC midnight
todateemptySession start, UTC end-of-day
sortselecttotal burn (ctx+out)See below

Both selects are populated from the data, not hardcoded, so an empty dropdown means no report carries that field.

Sorting: magnitude versus rate

The sort control switches between two readings of the same rows (render.js:11415):

SortReadsUse it to find
total burn (ctx+out)MagnitudeThe sessions that cost most
output tokensMagnitudeThe sessions that produced most
output / turnRateVerbose turns
context / turnRateSessions re-reading a large prefix
context : outputRateSessions that read far more than they wrote
most recentTimeWhat just happened

A row with no value for the chosen metric sinks to the bottom rather than sorting as zero (render.js:11425). The comment in the source puts it well: "unavailable" is not "cheap".

The totals row and the count line

Under the chart, a TOTALS strip with the summed context, summed output and the number of sessions currently visible; it re-computes as you filter. The count line above adds how many reports are posted in total and how many carry an agent-given title.

A row

Each row shows the session, its window, burn figures and its plan attribution. The plan chip is the honest part:

ChipMeans
<slug> · <state>The report carries execplan_slugs from the producer. This is a link, precise
window-inferredNo producer link. Burn attributes to plans by window-overlap on the board (render.js:11506)

Never read a window-inferred attribution as precise. It means "these plans were open at the same time", not "this session worked on them".

The advice thresholds

The page will attach an advice line to a session that trips one of five named gates, and it publishes the thresholds rather than hiding them (render.js:11400):

GateTrips when
context-heavycontext ÷ output ≥ the ratio threshold
replaycontext per turn ≥ the per-turn threshold
long sessionassistant turns ≥ the turns threshold
verbose turnsoutput per turn ≥ the per-turn threshold
over scalecontext + output exceeds the scale threshold

A session that trips none gets no advice line. Every recommendation names a feature the daemon actually ships, token_budget, query_scan / query_expand, save_session / get_session, store_fact / query_facts, and no savings percentage is claimed.

The section-model variant

Routing to this page through the section model rather than the custom renderer gives you the same feed shaped as four cards: a session select, a Headline card (context per turn, cache replay multiple, turns and tasks, the fixed-prefix share), a Where it goes bar chart of carried-cost buckets, and a What you can do to reduce burn card of grounded levers (pages.js:811). A Spend over time chart sits at the bottom and is honest about itself: the cost lens has no bucketed series endpoint, so it renders an empty state unless demo mode is on (pages.js:805).

5.3 Meters › Average Token Usage

Open this for per-period and per-turn averages. Everything on it is computed from the same posted reports; there are no controls beyond the page itself (pages.js:958).

Four cards:

Measured usage, reports counted and the days they span; last 7 days; last 30 days; all reports; a daily average; an average per session; and an average per turn.

That last line is the careful one. Per-turn averages accumulate only over reports that carry a turn count, so like divides by like; folding turn-less reports' tokens into the numerator would deflate it silently. The line states how many of how many reports contributed and that the rest are excluded rather than counted as zero (pages.js:990).

Output per session on the token-burn scale, three bars (median, mean, largest) on the same fixed 2,000,000-token ceiling and gradient the Token Burn chart uses, so a bar length means one thing console-wide.

The bars measure output, not total, and the card explains why: on the measured corpus, context is around 99% of all tokens, so a context+output bar pins at the ceiling for nearly every session and conveys nothing. Context is not dropped; it is stated as a share, in numbers, in the row beneath (pages.js:944).

Output tokens over time, a real day/week/month series, bucketed from the session windows in the reports. When no report carries a usable window timestamp, the chart says so.

Savings, a card whose entire content is that no saving is measured, and why.

5.4 System: where it lives and what is in it

System has no rail row. Its pages hang off the account badge at the bottom of the rail (shell.html:4764).

PagePosture / modeWhat it is
SettingsAllDaemon configuration and console preferences
IntegrationsAllInstalled packs and their grants, read
ExtensionsAllSigned third-party manifests, read
WorkbenchAllOperator tooling over /v1/workbench/*
Raw · JSON-RPCOperator onlyThe MCP plane, by hand
InfraProfessional mode onlyMachines, auth rails, config and session sync
DocsProfessional mode onlyBundled daemon reference

5.5 System › Settings

Open this to see how the daemon is configured, and to change the two things the console actually owns.

Read the next paragraph before you touch anything on this page.

Almost every control on Settings is read-only, deliberately. Every mutating control here carries an honest, page-specific reason instead of a generic "coming soon": read-only in the console, set on the daemon host (pages.js:792). Daemon configuration is environment, not a form. The selects and toggles show you the running value; they do not write it. Four buttons are exceptions and are called out below.

The page also injects two console-preference cards above the daemon sections: Command density and Theme, both covered in chapter 2 §2.7 and §2.9 (shell.html:5266).

Runtime capabilities (top card)

Injected before everything else, only on this page (render.js:584). Eight rows, each reading <availability>, <reason> verbatim from the daemon's capability plan:

CapabilityWhat it gates
Dataplane appendThe append path
Local embeddersOn-box embedding
Embedding delegationDelegated embedding
GPU rerankReranking
Hosted syncHosted synchronisation
Projection queriesThe living-document projection reads
Graph expansionPOST /v1/query/graph-expand
Link graph (CoreCrux proxy)The Link graph destination's visibility

The validation is strict and fails closed. A descriptor with the wrong schema version, a missing capability, a missing reason code, a non-boolean stage flag, or a self-contradicting state (available while degraded) all resolve to unavailable with a stated reason code (render.js:531). This card is the first place to look when a console pane is missing.

Node

RowSource
originThe browser's own origin
node idnode_id from the settings read
buildThe daemon build version

Access posture

ControlTypeDefaultNotes
auth modeselectThe running modeOptions come from the daemon's supported_modes when it reports them, else off / dev_scopes / jwt_hs256 / jwt_jwks. Read-only
require passport bindingtoggleonRead-only

Embedding (semantic retrieval)

Crux ships no embedding model; you point it at your endpoint.

ControlTypeDefaultNotes
enable embedding retrievaltoggleThe daemon's intent or active stateRead-only
endpoint URLtext, monoThe chosen or active URLRead-only
Probe endpointbutton-SHIPPED, live. POST /v1/console/embedding/probe, SSRF-guarded, fetches available models. No confirmation
modelselectThe chosen or active modelOptions -, bge-m3, nomic-embed-text, e5-large-v2. Read-only

Memory and freshness

The decay engine's horizons. All four are read-only.

ControlDefaultOptions
decay engineon-
volatile horizon24h12h, 24h, 48h
medium horizon35d7d, 35d, 90d
stable horizon365d180d, 365d
Run sweep now-STUBBED

Run sweep now is gated with a reason: there is no HTTP route. memory_sweep_candidates is an MCP tool and a dry run; the real sweep is a background timer with no daemon endpoint (pages.js:1673).

Coordination and leases

All three are read-only mirrors of the daemon's environment.

ControlDefault shownOptionsReal flag
punchcardsadvisoryoff, advisory, enforceCORECRUXD_PUNCHCARD, daemon default off
coordination planeon-CORECRUXD_COORD, daemon default on
observe / audit trailoff-CORECRUXD_OBSERVE, daemon default off

Note the mismatch: the punchcards select displays advisory while the daemon's own default is off (agentgraph_kinds.rs:162). Read the daemon's environment, not this control, for the truth.

Retention

ControlDefaultNotes
receipts (days)90Read-only
execplan factsindefinite, operator delete onlyInfo row
Export audit bundle-STUBBED

Export audit bundle is gated with a reason: the real route is a read that needs a session id and CORECRUXD_OBSERVE, and there is no unparameterised console trigger for it (pages.js:1674).

Onboarding

ControlStatus
Re-run onboardingSHIPPED, live, destructive. Confirms: Resets onboarding, the first-run wizard shows again on next load and the recorded completion is cleared for this node. Proceed? (render.js:769)

Daemon

ControlStatus
buildInfo row: version and port
Restart daemonSHIPPED, live, destructive

The restart confirmation is the most explicit in the console, and worth quoting because operators reach for this button expecting a graceful reload (render.js:766):

This RESTARTS THE DAEMON PROCESS, the daemon exits immediately (POST /v1/admin/restart) and relies on the service/container restart policy to come back. All in-flight requests drop and the console briefly disconnects. Proceed?

If your process manager has no restart policy, this button stops the daemon and nothing brings it back. The shipped root compose file sets restart: unless-stopped specifically so this works.

What Settings deliberately does not have

There is no Appearance section. The theme has its own card, and the old "canvas 2D | 3D toolbar switch" row was removed because no such control exists (pages.js:781).

5.6 System › Integrations (read)

This page reads the integration plane. It does not operate it. The first card says so and links straight through to Studio › Integrations, which is where connect, install, grant, invoke and revoke actually live (pages.js:543).

That link-through is on the page three times, deliberately. Before it existed, this page described flows that had no home.

CardContents
Where integrations are set upTwo info rows and the Studio link
CatalogA search box, one expander per pack (id, description, version, status, capabilities), and a header line reading enabled/disabled plus safe mode where set
Source connectorsTwo expanders: GitHub and OpenAI-compatible LLM
GrantsActive grant count, a Review grants button, and the Studio link

The two connector expanders carry live controls:

ConnectorFieldsButtons
GitHubpersonal access token (masked), skip TLS verify (dev only), default offVerify connection: SHIPPED, live, POST /v1/integrations/github/connect
OpenAI-compatibledefault model select (none default), API key (masked), organisationTest call: SHIPPED, live, confirms first

The Test call confirmation is the only spend warning in the console (render.js:751):

This makes an OUTBOUND request to the connected LLM and MAY SPEND TOKENS on your account. Proceed?

Both pages state the credential posture plainly: the token or key is held encrypted by the daemon and never in browser storage.

5.7 System › Extensions (read)

Same split as Integrations: read here, operate in the Studio (pages.js:593).

CardContents
Where extensions are managedThe Studio link-through
InstalledCount in the heading; one expander per manifest with kind, version and capabilities. When empty it says whether unsigned dev installs are allowed
Trusted signing keyspassport fingerprint, trust tier select (unknown, community_reviewed default, locally_signed, first_party), public key. Add key is SHIPPED and live
Install manifestmanifest URL/path and an Install button

Install is STUBBED here, with a precise reason: the registration route wants a full manifest object and this form supplies only a URL, so there is no groundable body. Installing from the signed catalog by id is wired, in the Studio, where the entry id and its curator-pinned sha256 are known (pages.js:1671). The card's own sub-line says the same thing.

5.8 System › Workbench

Operator deep machinery. Read tools run live; write tools are wired with confirmations (pages.js:1176).

Live read tools

Five self-loading panels, each firing a GET through the read client on open (pages.js:1186):

PanelEndpoint
API driftGET /v1/workbench/api-drift
Command ledgerGET /v1/workbench/command-ledger
Reasoning timelineGET /v1/workbench/reasoning-timeline
Audit triageGET /v1/workbench/audit-triage
Agent briefGET /v1/workbench/brief

All five default to tenant_id=default. A pro-gated payload returns an entitlement note rather than an error.

The contract card

GET /v1/workbench/contract enumerates every workbench surface with its method, path and live entitlement. Each row's badge is one of enabled, pro, entitled or the raw status (pages.js:1170). A GET row is labelled read; anything else write · gated.

The write tools

Five, all SHIPPED and live, all additive, none confirming (render.js:740):

ButtonFieldsWrites
Build context packpack tenant (default), pack queryA receipted pack fact
Run impact preflightimpact target, comma or space separated changed pathsA preflight fact
Simulate policypolicy profile (eu-ai-act default, workspace, none), action to simulateA simulation fact
Probe routeroute to probeAdmin-scoped route probe
Record capability auditcapability id, audit status (pass default, partial, fail), audit notesA capability audit

The query workbench

A read-only card of /v1/query/* lanes, text search, graph expand, time range, plus a tenant and a time-window select. Its buttons are inert here by design; the live search surface is Explorer (chapter 6 §6.4).

The legacy-console notice

The last card states that the legacy console has been fully removed and /console/legacy now 404s. The workbench is native; there is no fallback surface (pages.js:1331).

5.9 System › Raw · JSON-RPC (operator only)

The MCP plane, by hand (pages.js:1359).

ControlDefault
methodselect: tools/list, tools/call · query, tools/call · store_fact, resources/list
paramstextarea, 4 rows, pre-filled { "token_budget": 500 }
SendSTUBBED
ResponseAn output pane
X-Corecrux-Scopestext, mono, read

Send is gated and will stay gated. The reason given is a design position, not a milestone: the underlying route dispatches an arbitrary MCP tools/call, and a live console control there would be an arbitrary-write surface, breaking the curated no-arbitrary-mutation invariant the whole console rests on (pages.js:1675).

The transport card is still useful: it tells you the MCP endpoint is POST /mcp on port 14801, not on the HTTP port.

5.10 System › Infra (Professional mode only)

Five panels from one endpoint, GET /v1/console/infra/summary (pages.js:1027).

PanelShows
Onboarding checklistLogin auth (tick plus the mode), MCP enabled, machines registered and how many have hooks
Auth railsTailscale identity, device grant, agent-token-over-HTTP, each enabled or disabled
MachinesOne expander per machine: tailnet IP, OS/arch, rail, hooks, CLI version. Empty state: run corecruxctl login
Config bundlesSaved ~/.claude configs with file counts and source host, secrets redacted. Empty state names corecruxctl config push <name>
Session syncShared session snapshots across machines, with byte sizes and source host

Every empty state names the command that would populate it. There are no write controls.

5.11 System › Docs (Professional mode only)

Static reference bundled with the build: three doc expanders (mcp-system-prompt.md, PLANS.md, agent-guide.md), a README card, and a card of external doc surfaces (pages.js:1339). There is no live docs endpoint on this build, and the page says so.

5.12 Failure states across Meters and System

What you seeWhat it is
Meters: "cost lens off or unreachable"CORECRUXD_FEATURE_COST_LENS is off
Meters: reachable but emptyThe flag is on; no report has been posted. Run corecruxctl session cost --post
A cost row's plan chip says window-inferredThe report carries no producer link. Do not read the attribution as precise
Settings: everything greyed with "set on the daemon host"Working as designed. Daemon config is environment
Settings: a Runtime capability says unavailable with a reason codeThat is the daemon's answer. It is why a pane elsewhere is missing
Integrations/Extensions: a control is absentCustomer posture, or the control is one of the four gated with a stated reason
Workbench read panel: an entitlement noteA pro capability gates the payload; the surface is present
Raw: Send disabledPermanent, by design

Sources