Operations · 6. Explorer, Studio, Site map and the graphs
These are the surfaces that are not about a specific subsystem: search, building, finding and looking. This chapter is reference. Studio is the largest and comes first.
6.1 Studio: what it is, and where its four sections live
Studio is the console's builder. It lives at #/canvas/studio and is reached two ways: the Studio button beside the theme control in the expanded rail, or the Studio row in the account menu (shell.html:3658, shell.html:3733).
Inside it, a four-button segmented control is the primary navigation. Each section is deep-linkable with ?sub= (render.js:7377):
| Section | Hash | What it is for |
|---|---|---|
| Board | #/canvas/studio | Compose a board of tiles: notes, live API read-outs, same-origin embeds |
| Pages | #/canvas/studio?sub=pages | Define workspaces and the pages inside them |
| Integrations | #/canvas/studio?sub=integrations | The one actionable integrations home: connect, install, grant, invoke, revoke |
| Library | #/canvas/studio?sub=library | The curator-signed catalogue of boards, designs, workspaces and packs |
Any other ?sub= value falls back to Board (shell.html:5403).
The destination is named canvas for historical reasons, Board, Graph and Tree used to live here before they moved into Rings. Every #/canvas/board|graph|tree link redirects; #/canvas/studio is stable.
6.2 Studio › Board: the tile studio
Open this to build a dashboard. You drag tiles onto a snapping canvas, bind some of them to live daemon reads, and the layout persists daemon-side as a fact (render.js:6084).
Boards are stored under console:tileboard:<id> and reusable tile configurations under console:tiledesign:<slug>, both with key doc/def (render.js:5516). Everything is a fact, so an agent can write one via MCP.
The tile kinds
Twelve kinds ship (render.js:5538):
| Kind | Body | What it is |
|---|---|---|
| Note | standard | Title, sub, body text |
| Project | standard | - |
| Server | standard | - |
| Storage | standard | - |
| Client | standard | - |
| Output | standard | - |
| Box | blank | A container to group tiles visually |
| Web embed | iframe | A same-origin, root-relative path only |
| API tile | route-bound | Reads a daemon GET route and renders it with a preset |
| Text search | fixed route | A search read-out |
| Corpus status | fixed route | Corpus health |
| Receipts | fixed route | Recent receipts |
| Extensions | fixed route | Installed extensions |
Two legacy kinds were dropped and render an honest unsupported note rather than mis-rendering: 3D model tiles and PDF document tiles (render.js:5556).
A web tile may embed only a same-origin, root-relative path. External URLs, protocol-relative //host, javascript: and data: are all rejected (render.js:5581). The stated alternative is to ingest the data and bind an API tile.
An API tile may bind only to a route in the generated GET allowlist. Arbitrary strings are rejected before any fetch (api.js:958).
The toolbar
| Control | Default | What it does |
|---|---|---|
| Toggle library | shown | Shows or hides the left palette of tile kinds and saved designs |
| Zoom out / Zoom in | - | Canvas zoom |
| Fit | - | Fits all tiles |
| Toggle grid | on | Shows the 20px snap grid |
| Live chip | - | The live-tile stream state, from /v1/events/stream |
| Board settings | - | Opens the settings modal |
| Export | - | Builds a portable, signed pack from this board and downloads it |
| Import | - | Applies a Studio pack. Operator posture only; read-only otherwise |
| ? | - | How to publish a pack |
| Save | - | Saves the board now. Operator posture only |
Autosave runs 1.5 seconds after any move, resize or edit; Save is the manual override (render.js:5522).
Board settings
| Field | Default | Options |
|---|---|---|
| Board title | empty | - |
| Description | empty | - |
| Grid | 20 | 16, 20, 24, 32, 40 |
| Refresh | - | Off · Live · 30s · 60s · 5m (render.js:5530) |
| Accent | - | The theme accent tokens |
Live streams via /v1/events/stream with a targeted refetch on relevant events; the numeric options are poll intervals; Off is manual.
The tile inspector
Select a tile and the right panel becomes its editor. With nothing selected: Select a tile to edit it. Add tiles from the library on the left.
| Control | Applies to | Notes |
|---|---|---|
| Bring front / Send back | Any tile | Z-order |
| Save as design | Any tile | Saves the configured tile as a reusable design in the library |
| Delete tile | Any tile | Danger-styled |
| Same-origin path | Web tile | Placeholder /console |
| Daemon GET route | API tile | A datalist of the known literal GET routes. Free text is validated against it |
| Token budget | API tile | Shown only for routes that accept one, /v1/activity, /v1/facts, /v1/context (render.js:5527) |
| Preset | API tile | stat · list · sparkline · gauge · badge |
| Refresh | API tile | The same five options as the board |
| JSON path | API tile | Which field to read out of the response |
| Limit | List preset | Default 7 |
That budget field is the operationally important one: budgets are mandatory on retrieval reads, so the editor surfaces the field exactly where it applies and hides it where it would be ignored.
Links between tiles
Drag from a tile's link handle onto another to create a link. Selecting a link gives a label field, a Make one-way / Make two-way toggle and Delete link.
Export and import
Export opens a modal with pack id (pre-filled studio.<slug>), name, version (0.1.0), publisher passport fingerprint and summary, then Build + download.
Import takes a .json file and shows what it would write before Apply to this board, which is operator-only.
6.3 Studio › Pages: workspaces
Open this to reshape the console's navigation. A workspace is a named set of destination groups and the pages inside them; built-ins render from the registry until you take control (render.js:7442).
The page states its own storage contract in a footer line: entities console:workspace:<uid> and console:page:<uid>, key def, canonical key-sorted JSON. An agent can generate identical workspaces via PUT /v1/facts or MCP store_fact, the console is one writer of that format, not the only one.
Layout is a tree on the left and an editor on the right.
| Control | Where | What it does |
|---|---|---|
| + New workspace | Header | Creates from a starter template, remix, not blank |
| Workspace row | Tree | Selects a workspace for editing |
| + page | Under a workspace's group | Adds a page of any registry type |
| Page row | Tree | Selects a page. A forked built-in carries a forked badge |
| revert | On a forked built-in | Reverts to the registry version. The fork is reversible by design |
Editing a workspace gives its title, sub-line, icon (from a fixed set of fourteen glyphs) and destination groups. Editing a page gives its title, sub, destination and config, plus a raw-JSON escape hatch that preserves unknown keys, so a page written by a newer agent is not silently stripped when you edit it in the console.
In customer posture the whole surface is browsable and a banner says: Read-only, operator posture required to create, edit, fork or revert. Everything below is live and browsable.
6.4 Studio › Integrations: the actionable home
This is the only place in the console where an integration is actually connected, installed, granted, invoked or revoked. Both System pages link here rather than restating flows they cannot run (render.js:8624).
Four sections, each with a one-sentence statement of what it is:
| Section | The sentence it leads with |
|---|---|
| Connectors | Credentials are sealed daemon-side. The console posts them once and never reads them back |
| Packs | Install is not grant, a pack does nothing until a passport grant names its capabilities |
| Extensions + catalog | Community extensions, installed from a curator-signed index the daemon re-verifies locally against its trusted keyring |
| Trusted keys | The Ed25519 keyring every signed manifest verifies against |
The distinction in the Packs line is the one operators get wrong. Installing a pack grants nothing. A grant is a separate, passport-scoped action.
Cards in the section, in order: GitHub connector, OpenAI connector, packs, installed extensions with per-extension grant panels, the catalogue browser with a per-entry safety scorecard, and the trusted-key list with an add form.
In customer posture the whole surface is live and read-only, with a banner: Read-only, customer posture. Status is live; connect, install, grant, invoke and revoke need operator posture.
Every write here goes through the same gated client and the same bound-passport requirement as everywhere else.
6.5 Studio › Library: the signed template catalogue
Open this to install a board, design, workspace or pack somebody else built (render.js:8951).
Two routes back it: GET /v1/studio/library returns the daemon's cached, signature-verified index joined against what is already installed, and POST /v1/studio/library/{id}/install is the single mutation.
Entries are grouped by kind: Boards · Designs · Workspaces · Packs (render.js:8686).
Three refusals are built into this surface and each is worth knowing (render.js:8671):
1. There is no Refresh button. The daemon has no fetch-index route; the cache is populated by corecruxctl studio sync. The surface names the command rather than offering a control that would do nothing.
2. The tier chip is advisory. A Pro or Team chip is echoed from the catalogue, not enforced locally. The daemon stamps every response tier_enforcement: "advisory" and never gates an install on it. The chip's tooltip says so verbatim (render.js:8690). Do not read a tier chip as a local entitlement check.
3. Install results are rendered in the response's own shape, the written entities, the collision remaps (from → to) and the provenance block, and errors verbatim. A 404, 409 or 403 each carries the daemon's own detail string.
An install can only add. A colliding id is remapped, never overwritten. The header says so.
6.6 The three former Canvas views: Board, Graph, Tree
These are Rings tabs 7 to 9 (chapter 3 §3.6), and also available as workspace page types.
Board: the size-adaptive dashboard
A registry of eighteen widgets composes onto a tile canvas, with the set chosen by viewport width (render.js:3402).
| Tier | Width | Widgets shown |
|---|---|---|
xs | < 720px | 4: glance tiles, Needs you, Fleet, Activity |
s | < 1600px | + Token burn, ExecPlans |
m | < 2560px | + Token usage, Facts, Engine, Fleet dashboard |
l | < 3840px | + Projects, Sessions, Tenants, Live board |
xl | ≥ 3840px | + Passports, Gates, Orchestrators, Integrations |
A very short viewport steps down one tier. Below 640px the canvas falls through to a plain stack (render.js:3447).
| Control | Default | What it does |
|---|---|---|
| Edit layout | off (Locked) | Off, tiles cannot be dragged or resized, reading never moves a tile. On, they can (render.js:2989) |
| Click a tile | - | Expands it in place |
| Drag the canvas | - | Pans |
| Resize handle | Edit mode only | Resizes |
Positions persist per tier under a storage key of board-<tier>, so a 4K layout and a laptop layout do not fight. The meta line under the board states the tier, the widget count and the grammar.
Graph: the relation graph
Real edges only. An edge exists only when both endpoints resolved to a node (render.js:3497). Seven feeds compose it: projects, work, pending gates, passports, live coordination sessions, per-project repositories and saved sessions (render.js:4502).
| Control | What it does |
|---|---|
| Click a node | Opens the inspector |
| Pin | Keeps the inspector loaded when you click empty space or navigate |
| Close | Closes the inspector and unpins |
Deep link ?focus=<type>:<id> | Opens focused on that node |
The work feed is capped at 80 items, active-first and deterministic, because source=all can exceed a thousand and an illegible graph is worse than a partial one. The focused node is always kept, and a note under the stage states honestly: showing N of M work items, active first (render.js:4564).
Tree: the plan tree
Project → ExecPlan → Milestone → live session, from /v1/projects, /v1/work and /v1/coord/active (render.js:4662).
A session row carries its announced milestone, its declared paths (up to four) and its held leases inline, each lease showing its mode and reason.
| Control | Default | What it does |
|---|---|---|
| Kind chips | all on | Filter by node kind |
| State chips | all on | Filter by work state |
| Filter | empty | Free text across label, id and slug |
| Node expand | native | Nodes with children are <details>, no JavaScript needed |
Two markers matter. A plan whose daemon hash and local hash disagree carries a hash-state chip with the mismatch in its tooltip. A session announcing an execplan_slug that resolves to no work item is marked unresolved: <slug> (render.js:4621); that is a real coordination problem, surfaced rather than swallowed.
Each feed that fails emits its own notice with a machine-readable reason, distinguishing "coordination is off" from "coordination errored" from "unreachable" (render.js:4582).
6.7 Explorer: searching the corpus
Open this to search. It is a destination with no sub-pages: Explorer is a search box (render.js:12642).
It starts vertically centred and un-centres once results render, the layout is the state indicator.
| Control | Default | What it does |
|---|---|---|
| Search query | empty | 250 ms debounce, then searches |
| Backend toggle | Local | Local is daemon retrieval; the other is the daemon-mediated engine |
| Budget field | 1500 | Relabels with the backend (below) |
The budget field is two different controls wearing one input (render.js:12681):
| Backend | Label | Meaning | Cap |
|---|---|---|---|
| Local | token budget | Retrieval token budget, default 1500 | none |
| Mediated | Number of Results | top_k, default 8 | 50 |
Switching backend re-runs the search if there is a query. Both are reads, so Explorer is visible in every posture.
Results are cards: title, snippet, source, score (colour-toned) and tenant, real fields only. Clicking one opens it on its own page with a ← Back to results button. The detail view says plainly that full detail is sourced from the engine's Ask surface and that wiring is in progress.
Failures are specific rather than generic: a 404 on the mediated backend says WikiCrux search unavailable, engine mediation off; a 404 locally says Search unavailable, feature off.
A query typed into the topbar search field is carried straight in and executed on arrival.
6.8 Site map: every surface, one click away
Open this when you cannot find something. It is a map derived from the live page registry, so it cannot drift from the navigation (render.js:10461).
One section per destination, accent-coloured, each node an <a> to a registered route showing the page name, what it is for, and its literal hash route.
| Element | What it means |
|---|---|
| YOU ARE HERE | The card matching the hash you navigated from, tracked on every hash change |
| Numbered steps 1–4 | The recommended first-run path: Rings → Sessions → Facts → Receipts (render.js:10349) |
OPERATOR badge | Lane weights · Pending mints · Raw JSON-RPC |
FEATURE-GATED badge | Identity |
ENGINE OFF badge | Mediation |
The map is posture-aware: operator-only pages are omitted for a customer, and Pro-only pages are omitted entirely, so every rendered node resolves to a live route in your current posture. There are no dead nodes.
The footer prints the honest count, N destinations · M surfaces, and states that the map is derived from the registry.
6.9 Link graph: the six-degrees explorer
A WebGL explorer over the enwiki-prose link graph, through the daemon's read-only mediation proxy (render.js:12789).
This destination is capability-gated on the daemon's runtime plan. It does not appear in the rail, the site map or the phone sheet unless the daemon reports console_link_graph as available (shell.html:4118). A deep link to #/linkgraph on a daemon without the proxy fails to an honest empty state naming CORECRUXD_CORECRUX_GRAPH_BASE_URL (render.js:12797).
| Control | Default | What it does |
|---|---|---|
| From article | empty | Path start, e.g. Dog |
| To article | empty | Path end, e.g. Barack Obama |
| Find path | - | Resolves both titles, then requests a path with max_hops=6 |
| Enter, in either field | - | Same as Find path |
| Click a node | - | Expands its 1-hop ego network, budgeted at 400 nodes / 1,500 edges / degree cap 40 |
The header stat line carries the graph's own numbers and, when present, the build digest of the CoreCrux graph artefact, artefact provenance, so you can say which build you were looking at.
Errors are specific: a 503 renders Link graph unavailable, the CoreCrux graph is not built/enabled upstream, distinct from an unreachable backend (render.js:12782).
The WebGL renderer is a separate ES module, dynamically imported only when this pane opens, resolving three through the shell's import map to an already-vendored copy. No external request is made (shell.html:62).
6.10 Explore: the reader surface
Switching the workspace to Explore replaces the rail with a document tree and the content region with a reading column and an evidence panel (render.js:10076).
Eleven surfaces sit under it (render.js:9108). Their honesty status is published in the source as a per-surface manifest, and it matters (pages.js:2061):
| Surface | Status | Backed by |
|---|---|---|
| Proof | Real | Tenants + facts + activity |
| Watch | Real | /v1/activity |
| Ask | Real | POST /v1/query/text-search |
| Living Objects | Real | /v1/admin/projections/artifacts/{id}/state |
| Dependencies | Real | POST /v1/query/graph-expand |
| Signals | Demo surface | No endpoint: fixture only, and chipped |
| Receipt Diff | Real | /v1/activity |
| Sourcing | Demo surface | No endpoint: fixture only, and chipped |
| Lanes | Real | /v1/console/corecrux/lane-weights |
| Domains | Real | /v1/features/capabilities/analysis/coverage |
| Reverse | Demo surface | No endpoint: fixture only, and chipped |
Three of the eleven are demo-only. They render a fixture behind the demo flag and nothing otherwise. Every one carries a demo chip. Reading a number off Signals, Sourcing or Reverse and treating it as your data would be a mistake, and the chip is there to stop you.
Real-backed surfaces use their fixture only as an empty or degraded fallback; live data always wins.
The reader also carries bundled daemon reference documents, which are genuinely shipped with the build and need no endpoint (render.js:9008).
6.11 Failure states across these surfaces
| What you see | What it is |
|---|---|
| Studio Board: Save and Import greyed | Customer posture |
| Studio Board: a tile says "not supported in the console" | A 3D-model or PDF tile from an older board |
| Studio Board: a route will not bind to an API tile | It is not in the generated GET allowlist |
| Studio Library: empty | The cache has never been synced. Run corecruxctl studio sync |
Studio Library: a Pro chip on an entry you can install | Correct. The tier is advisory; the catalogue server enforces it |
| Graph: "showing N of M work items" | The 80-item cap. Not an error |
| Graph: "Graph unavailable" | One of the seven feeds threw. Check /v1/projects first |
Tree: unresolved: <slug> | A session announced a plan slug that no work item matches |
| Explorer: "engine mediation off" | CORECRUXD_ENGINE_BASE_URL unset |
| Link graph: not in the rail | The capability is not available. Check System › Settings › Runtime capabilities |
Explore: a surface with a demo chip | It is a fixture. There is no endpoint behind that surface |
Sources
- crates/corecruxd/console/v2/render.js:7357,
renderCanvasand the Studio dispatch - crates/corecruxd/console/v2/render.js:6084,
renderTileStudio - crates/corecruxd/console/v2/render.js:7442,
renderWorkspaceStudio - crates/corecruxd/console/v2/render.js:8624,
renderIntegrationsStudio - crates/corecruxd/console/v2/render.js:8951,
renderLibraryStudio - crates/corecruxd/console/v2/render.js:12642,
renderExplorer - crates/corecruxd/console/v2/render.js:10461,
renderSiteMap - crates/corecruxd/console/v2/render.js:12789,
renderLinkGraph - crates/corecruxd/console/v2/render.js:3402, the eighteen board widgets and their tiers
- crates/corecruxd/console/v2/pages.js:2061, the Explore surface-port manifest with each surface's real-or-demo status

