Operations · 3. The Rings view and the work board
Rings is the console's front page and it answers one question: what has been happening, and when. Work is the same material as a list you can act on. This chapter is reference; §3.1 explains the ring before any table, because a ring is not a chart you have seen before.
3.1 What the Rings view actually is
Imagine a clock face where the hands never move but the numbers do. Angle is time: the outer rim is the latest day in your window, the centre is the oldest. Each ExecPlan owns a wedge of the circle. Inside its wedge, every fact that plan produced sits at the radius matching the day it was written. Playing the timeline sweeps the whole picture forward, so plans appear as they start and fade as they finish.
That is the "ExecPlans" lens. Five other lenses reuse the same geometry over different material, facts, memory, sessions, tokens, and one, the arc lens, abandons the wedge entirely and gives each plan its own 270° arc of progress.
The point of the view is peripheral: you are meant to notice a shape being wrong, not read a number off it. Every number it carries is duplicated in a list somewhere else in the console.
One honesty rule governs the whole page. The ring ships with an embedded snapshot board so it renders on a daemon with no work at all. It swaps that snapshot for your real board only when the live feed returns at least 50 ExecPlan items that carry provenance timestamps and are in in_progress, complete or blocked (render.js:15119). Below that threshold you are looking at the snapshot. When it does swap, the root element gains data-src="live"; that attribute is the only reliable way to tell, and it is the first thing to check if the ring looks unrelated to your work.
The arc lens is the exception: it reads the full board from the same response, in every state, with no provenance requirement (render.js:15115).
3.2 Where the ring's data comes from
| Feed | Endpoint | Feeds |
|---|---|---|
| Work board | GET /v1/work?source=all | The ring's plan wedges, the ExecPlans tile, the arc lens |
| Daemon glance | GET /v1/console/summary | The facts, MCP agents, integrations and engine tiles |
| Sessions | GET /v1/console/sessions | The Sessions tile's per-day sparkline |
| Fact store | GET /v1/facts/list, paged | The Data-graph lens and the facts sparkline |
The fact walk pages 200 rows at a time, up to 55 pages, capped at 10,000 nodes (render.js:13118, render.js:15177). It includes reserved entities. If your store is larger, the tile says so.
3.3 The lens tiles and the glance tiles
Top right of the stage, one group of ten cards (render.js:13153). The first six are buttons that switch the lens; the last four are read-outs.
| Tile | Type | Headline | Sparkline |
|---|---|---|---|
| ExecPlans | Lens (default) | Count from /v1/work | Plans active per day |
| ExecPlans arc | Lens | Tracks shown of plans in the corpus | None: it is a ratio, not a series |
| Data graph | Lens | Visible fact nodes rendered | Facts stored per day |
| Memory | Lens | Memory-kind cells | Memory cells per day |
| Sessions | Lens | stores.sessions | Real last_active_unix_ms histogram |
| Tokens | Lens | Total spend, in millions | Tokens per day |
| facts | Glance | stores.facts, the whole store | Same real histogram as Data graph |
| mcp agents | Glance | daemon.mcp_agent_count | None, a point-in-time scalar |
| integrations | Glance | Integration count | None |
| engine | Glance | on / off from dataplane_enabled | None |
A tile without a sparkline does not have one because there is no real series behind it, not because it was forgotten. The facts glance and the Data-graph tile deliberately share one histogram rather than inventing a second.
The six lenses
| Lens | What the geometry means |
|---|---|
| ExecPlans | One wedge per plan, cells at their write-day radius. Keeps solo, ledger, lineage and both filters |
| ExecPlans arc | A 270° arc per plan. 12 o'clock is 0% of its declared milestones, 9 o'clock is complete. Newest plan innermost; completed plans fade and the stack collapses inward. Titles and token-burn bars sit left of the 12 o'clock line |
| Data graph | Facts as nodes. Angle is source date, radius is confidence (higher is nearer the centre), edges join facts sharing an entity |
| Memory | Memory-class cells only |
| Sessions | Sessions over the window |
| Tokens | Token spend over the window; gains a cumulative/per-day toggle |
3.4 The tool toolbar: nine controls, top left
These are the ring's own controls. Each is a toggle unless marked momentary (render.js:13226).
| Control | Default | On means | Turn it on when |
|---|---|---|---|
| Ambient spin | On, unless the OS asks for reduced motion | The whole ring rotates slowly | It is on a wall display. Turn it off to read labels |
| Reset clock to 12 | Momentary | Snaps rotation back to zero and stops spin | You have lost your bearings mid-spin |
| Bars | On | Each node draws a spoke from the centre outward | Off gives dots, cleaner on a dense store |
| Time edge | Off (outward) | Off: rings grow outward as time advances. On: nodes sink inward from the rim | You want newest material pinned at the rim |
| Census | Off | Every plan stays on the clock permanently instead of leaving when it finishes; hovering names sectors | You are auditing the whole portfolio, not watching current work |
| Show completed plans | Off. Auto-on during playback | Finished plans stay visible | You are replaying history and want the finished work in frame |
| Completed-plans list | Off. Auto-shows during playback, hides on lens swap | A ledger of completed plans opens on the left | You want to click through to a finished plan |
| State colours | Off | Recolours by state: complete green, in progress purple, blocked red | You are triaging. Off colours by kind instead |
| Lineage chords | Off | Draws depends_on relationships as chords across the circle | You are checking whether a plan is blocked by another |
Two toggles appear only for their lens:
| Control | Appears in | Options | Default |
|---|---|---|---|
| Token view | Tokens lens | cumulative (running total across the window) / per day | cumulative |
| Focus | Data graph lens | Isolates the selected fact node and its connections | Off |
The two filter menus
Each is an icon button that opens a single-select popover. An active filter keeps a coloured dot and its value visible on the icon when collapsed (render.js:13252).
| Menu | Options | Default |
|---|---|---|
| Filter by node kind | all kinds · gates · decisions (OD) · memory · handoffs | all kinds |
| Filter by agent passport | all agents · claude-work · codex-work | all agents |
The agent list is a fixed set of two, not a live enumeration of your passports. If your agents carry other passport ids, this filter will not list them.
Help
The ? icon opens a focus-trapped modal explaining the rings, the lenses, and the filter/zoom/solo model in the product's own words (render.js:13325). Escape and a background click close it.
3.5 Playback and the window
The play bar is mounted into the topbar, on the search field's row (render.js:14987):
| Element | Interactive | What it is |
|---|---|---|
| Start-range label | No | The window's first day, as text |
| Play / pause | Yes | Replays the window. If the clock is already at the end, pressing play rewinds to the start first |
| Scrubber | Yes | The clock position, 0–1000 across the window |
| End-range label | No | The window's last day |
| Scrub date | No | The date the clock is currently showing |
The bottom bar carries the window and zoom (render.js:13305):
| Control | Type | What it does |
|---|---|---|
| Window start date | Date picker | Sets the first day rendered |
| window sliders (two) | Ranges | The same window, as a pair of handles |
| Window end date | Date picker | Sets the last day rendered |
| Zoom out / Fit / Zoom in | Buttons | Fit accounts for the play bar and bottom bar so nothing is hidden behind them |
Mouse wheel zooms and dragging pans, anywhere on the stage. Clicking a plan sector, or a row in the completed-plans ledger, solos it: the ring reframes to that plan alone. Clicking the background clears the solo and refits.
Two behaviours that look like bugs and are not. The window's maximum date is clamped to the data, so on a snapshot ring it stops at the snapshot's last day. And when a live board arrives whose newest day is beyond where the clock was parked, the clock is carried forward to the new end, without that, plans created since the snapshot render as "not yet started" (render.js:15140).
3.6 The nine Rings views
Rings has nine views. Their buttons are not on the page; they are the Rings accordion in the left rail (render.js:14973). Selecting one fades the ring canvas out, hides all the ring-only chrome, and swaps the view in below; the draw loop pauses so it does not burn frames behind a hidden canvas (render.js:15046).
| # | View | Hash | What it is |
|---|---|---|---|
| 1 | Ring | #/rings | The canvas itself |
| 2 | Activity | #/rings/activity | A three-panel triage board: Needs you and Fleet on the left, the activity feed on the right |
| 3 | Live board | #/rings/live-board | Who is working right now |
| 4 | Orchestrators | #/rings/orchestrators | Group plans for a session |
| 5 | Punchcards | #/rings/punchcards | Advisory path leases, grouped by holder |
| 6 | Agent | #/rings/agent | MCP tool usage and reach. Professional mode only |
| 7 | Board | #/rings/board | The size-adaptive tile dashboard |
| 8 | Graph | #/rings/graph | The relation graph |
| 9 | Tree | #/rings/tree | Project → ExecPlan → Milestone → live session |
Views 7 to 9 were a separate destination once; #/canvas/board|graph|tree still redirects here, preserving any ?focus= (shell.html:5466). They are documented in chapter 6 §6.6.
Switching views from the rail rewrites the hash with replaceState rather than navigating, so the fade and the canvas state survive (shell.html:4327).
3.6.1 Activity view: the triage board
This is the view to leave open. Three panels (render.js:2551).
Needs you; everything waiting on a human. It merges three signals:
| Signal | Source | Card |
|---|---|---|
| A gated transition awaiting approval | /v1/work/gate/pending | Approve / Reject, operator posture only |
A plan in blocked state | /v1/work | Read-only, with its blocker reason and a link to the plan tree |
| A session that may need input | /v1/coord/active intent notes | Read-only, labelled "MAY NEED INPUT" |
That third one is the honest one. The coordination plane carries no structured waiting-for-input field, so the console infers it from the session's own free-text intent note, requiring both a waiting verb and a person-or-decision object (render.js:2018). Every such card carries an inferred from intent chip. Treat it as a prompt to look, not a fact.
A session counts as running only while its coordination heartbeat is between 0 and 5 minutes old; a future timestamp (clock skew) or an older one is not running (render.js:1988). The heartbeat is passport-level, not session-level, sibling sessions of one identity share it, so "fresh" means that identity is around, not that this session is doing something.
Fleet, one row per passport, merging four feeds and showing a chip per feed reading on, off or n/a (render.js:2276):
| Feed | Contributes |
|---|---|
/v1/coord/active | Announced ExecPlan, milestone, intent note, session hex, leases, overlap rows |
/v1/punchcards | Held leases with their mode |
/v1/console/sessions | The saved-session id |
/v1/orchestrators | Orchestrator membership |
Those four chips are the fastest read of "which coordination features are actually on" anywhere in the console.
Activity, the latest 12 rows from /v1/activity, as a ticker with receipt-id chips (render.js:2337). A 404 here means the activity flag is off, and the panel says so and points at the full Work › Activity surface.
3.6.2 Live board
One expandable row per live session, showing passport, tenant, announced ExecPlan and milestone, declared paths, held leases, and a "seen Ns ago" stamp computed against the daemon's own clock (pages.js:662).
A 400 or 404 renders Coordination plane disabled, set CORECRUXD_COORD=1. The daemon-side default is actually on (config.rs:1336), so seeing that message means it was explicitly disabled.
Empty and healthy shows no sessions live right now. There are no controls on this view; it is a read-out.
3.6.3 Orchestrators
One row per orchestrator: name, creator passport, member count, state (pages.js:679). A 404 renders Orchestrators disabled, set CORECRUXD_ORCHESTRATORS=1 and names the four MCP tools that manage them: create_orchestrator, attach, detach, list.
There is no console control that creates or edits an orchestrator. This is a read surface; the write path is MCP.
3.6.4 Punchcards
Leases grouped by holder passport, each showing its resource, status and mode (pages.js:690). A 404 renders Punchcards disabled, set CORECRUXD_PUNCHCARD=advisory|enforce and names the MCP tools: punch_in, punch_out, check_punchcard, list_punchcards.
The mode matters operationally. advisory records leases and warns; enforce makes the pre-tool hook deny on conflict (agentgraph_kinds.rs:155). Again, no console control writes a lease.
3.6.5 Agent (Professional mode only)
The tool-surface health view, over GET /v1/mcp/tools/usage?window_hours=720, the catalogue joined against the call ledger (pages.js:1099).
The top card gives you three lines: total calls, distinct passports and error rate; catalogue size against tools called and tools never called; and a triage hint. Below it, every tool, sorted by calls descending with zeros included.
The badge on a never-called tool is precise, and the distinction is worth learning:
| Badge | Means |
|---|---|
123× | Called that many times in the window |
ignored | Offered to sessions but never called |
never offered | In the catalogue but absent from every session surface |
unused | No offered-data has accrued yet, the honest default |
uncataloged | Called historically but absent from tools/list now, a removed or renamed tool |
Expanding a tool gives its description, calls and error percentage, distinct-passport reach, average tokens and p50 latency, last-called time, and whether it is in the current catalogue. The search box accepts unused, errors and uncataloged as terms.
The view also carries an Agent cockpit card naming where each legacy agent surface now lives, and a link to the 3D substrate at /console-3d/index.html?embed=1.
3.7 Work › ExecPlans: the kanban board
The plan list is a board, because "which state is it in" is the question you actually ask (pages.js:390).
Four columns, in this order: Planned · In progress · Blocked · Shipped · 7d (pages.js:383). Raw daemon states are folded into them, complete, deployed, archive and ok all become done; run becomes in progress; err becomes blocked (pages.js:151).
The card
| Element | Source |
|---|---|
| Risk badge | risk_class |
| Milestone tag | current_milestone |
| Slug | Derived from plan_path's filename, or the id with execplan: stripped |
| Title | title, or the id |
| Progress bar and count | milestones_done / milestones_total |
| Owner passport | assignee_passport |
| Note | linked_pr |
graph link | Opens the relation graph focused on this plan |
The toolbar
| Control | Default | Persisted as | What it does |
|---|---|---|---|
| Search | empty | not persisted | Filters cards client-side across everything visible in the card |
| State chips, one per column | all shown | crux.console.board.work.hidden | Toggles a column's visibility. The last visible column cannot be hidden (render.js:1312) |
| Sort | Updated · newest | crux.console.board.work.sort | Orders cards inside every column |
Four sort orders (render.js:1054):
| Sort | Metric | Caveat |
|---|---|---|
| Updated · newest | updated_at_unix_ms | Present on every item |
| Created · newest | created_at_unix_ms | Present on every item |
| Title · A→Z | Locale compare | - |
| Completion · most done | milestones_done / milestones_total | Not every plan reports milestone counts. Those sort last, and the control prints N of M plans report milestone counts, the rest sort last (render.js:1331) |
That caveat line is the honest bit: the board will not invent progress for a plan that does not declare milestones.
Where the items come from. GET /v1/work?source=all merges the kanban work-items table with a read-time projection over ExecPlan markdown files under $CRUX_EXECPLANS_ROOT (work_execplans.rs:58). Items with an execplan: id prefix are projections, read-only. You complete one by editing its markdown, not from this board.
3.8 Work › Activity: the rolling log
The activity log is the transcript: every question, answer, reasoning step, tool command, fact write, ExecPlan update and handoff, newest first (render.js:11771).
It defaults to the all-sessions lane and loads immediately, no session id required.
The controls
| Control | Default | What it does |
|---|---|---|
| session | blank | Blank means all sessions. Enter an id and press Enter to reload into the single-session lane |
| token budget | the page default | Per-page retrieval budget. Press Enter to reload. A budget-truncated page says so in the status line |
| search (client-side) | empty | Filters the loaded rows only. Never re-queries. 200 ms debounce |
| Kind chips | all on | One chip per kind present, with its loaded count. Toggling filters client-side. Kinds: question, answer, reasoning, command, fact, execplan, handoff, error (render.js:10533) |
| Reload | - | Re-reads with the current session and budget |
| Go live | off | Opens an EventSource on /v1/events/stream?types=activity.appended. Becomes Stop live; on a dropped connection it reads Live (reconnecting) |
| Load older | - | Pages backwards. All-sessions lane only |
The live tail is deliberately cheap and honest: the SSE event carries ids only, so on each event the console refetches page one and merges genuinely-new rows by session:seq, 500 ms debounced (render.js:12053). No row is ever fabricated from the event itself.
Rows are sorted newest-first by a monotonic per-row cursor after every load, page and merge, so out-of-order pages cannot invert the list (render.js:11801).
Reading a row
Each row shows its kind, a clickable session short-id, relative time (absolute ISO on hover), a sequence number, and the tool, intent and confidence where present. Receipt and fact references ride as chips, up to 3 receipts and 2 facts, then a +N more.
Clicking the session pill filters to that session. Clicking anywhere else expands the row, which does two things (render.js:11943):
- Dereferences the turn's verbatim entries.
- Requests verification of them and renders a badge per entry, verbatim from the daemon:
| Badge | Means |
|---|---|
✓ verified <id> · <signer> | The daemon reports the Ed25519 signature valid |
• recorded <id> | The entry exists but is not signed |
✕ <error> <id> | The daemon reports it unverifiable, with its own error string |
• recorded (verify unavailable HTTP N) | The verify call itself failed |
The console never computes "valid" itself.
The two limits
| Limit | Behaviour |
|---|---|
| Single-session lane is not paginated | The daemon returns the newest N with no older cursor. When it is full the page says so and suggests raising the budget or clearing the session |
| DOM cap | Past the cap the page stops paging and asks you to narrow with search or kind chips |
When the flag is off
A 404 renders a warning banner naming CORECRUXD_FEATURE_ACTIVITY_LOG (render.js:12026). Under ?demo=1 a labelled fixture stands in, with a banner saying exactly that.
3.9 Work › Projects
A project pairs the repositories you want tracked and searched with a planning repository where ExecPlans live (pages.js:347).
Cards are collapsed by default and carry a coloured left strip: green-ish done when archived, in-progress when it is the default project, planned otherwise.
Expanding one shows id, name, planning target, default passport and creation date, only the fields that are actually populated, then a repo grid fetched lazily per project, an + Add repos disclosure, and a View graph link.
+ New project
A + in the card header reveals a form below the list (pages.js:350).
| Field | Type | Default | Notes |
|---|---|---|---|
| name | text | - | Free text |
| id | text, mono | - | Slug |
| execplan storage | select | planning repo (recommended) | Also: daemon-native, hybrid, repo files + daemon kanban |
| Create project | button | - | SHIPPED, live. POST /v1/projects |
Create project is one of the wired writes: operator posture, a bound passport, and the real response rendered back (render.js:726). No confirmation dialog; it is additive.
+ Add repos
A per-project disclosure, operator-only (pages.js:334). It contains a GitHub status line, a link through to Studio › Integrations, a repo select, and two buttons.
Both buttons are STUBBED and deliberately so. The source states the reason: POST /v1/projects/{id}/repos needs a project id and a real repository, and the disclosure has neither while GitHub is unconnected and the select holds a placeholder; there is no groundable request body (pages.js:1668). Connect GitHub in Studio › Integrations first, and the repositories appear here.
3.10 Work › Sessions
A searchable list of saved session snapshots, over GET /v1/console/sessions (render.js:10876).
| Control | Default | What it does |
|---|---|---|
| filter | empty | Client-side across id, agent, actor, passport, plan slug, matched plan id and title |
| archived | off | Re-queries with include_archived=true |
The allocation panel
Above the list sits the panel that answers "why do so many sessions have no passport or plan?", with the daemon's own counts, computed over every listed row rather than the displayed page (render.js:10936).
| Stat | Counts sessions with |
|---|---|
| identity (actor, key prefix or binding) | Any identity signal at all |
| write-time actor stamp | An actor recorded at write time |
| passport binding | A minted passport binding |
| plan link (binding or live announce) | A link to an ExecPlan by either route |
| agent-given title | A title set by the agent at save_session |
Each shows a count, a share of the total, and a tone: warn when the daemon reports a non-zero deficit. The daemon's own explanatory why string is printed underneath. On an older daemon that does not return allocation, the panel stays hidden rather than showing zeros.
The row and the drawer
A row leads with the agent-given title when there is one, with the session id demoted to a mono tag; without a title, the id is the heading. Then a state chip, the owning agent, the write-time actor, and a relative timestamp. Meta chips carry total tokens, bound passport, plan links and the archived reason.
A session with no summary says so plainly: no state summary, agents: set title/summary in save_session state.
Expanding a row opens the full drawer over GET /v1/console/sessions/detail (render.js:11023), in six sections:
| Section | Content |
|---|---|
| session | Raw key, agent, state, updated, expires, archived + reason |
| passport | The binding, or a note that bindings are minted on POST /session and agent save_session ids resolve to none |
| linked ExecPlan | Three lanes, most authoritative first (below) |
| gates decided | Gate decisions by this passport, with receipt short-ids |
| token usage | Total tokens, and the estimate method, serialised state bytes ÷ 4 |
| state JSON | The full state blob, collapsed |
The three plan-link lanes are ranked and labelled, which is the point:
| Lane | Strength | Meaning |
|---|---|---|
| same-id match | Exact | The session's id is an ExecPlan work-item id. Identity, not inference |
| live announce | TTL-scoped | A coordination announce, valid while the TTL holds |
| heuristic | Derived | execplan:* facts authored by this session's passport. Labelled "derived from fact authorship" |
Each lane that has nothing says so in one sentence naming what would populate it.
3.11 What "wrong" looks like on these screens
| Symptom | Cause |
|---|---|
| The ring shows plans you do not recognise | You are on the snapshot. Check for data-src="live"; the live swap needs ≥50 qualifying items |
| Rings tiles show counts but the ring is empty | The window excludes your data. Reset the date pickers or press Fit |
| The kanban is empty but you have plans | CRUX_EXECPLANS_ROOT is not set on the daemon process, so the projection has no files to read |
| Activity is empty with a warn banner | CORECRUXD_FEATURE_ACTIVITY_LOG is off |
| Live board / Orchestrators / Punchcards say "disabled" | Those flags are off. Live board's default is on, so it was disabled explicitly |
Fleet shows every chip as off | No coordination features are enabled, expected on a stock daemon except for coord |
Sessions all show no plan link | Nothing is binding sessions to plans. The allocation panel's why string is the daemon's own explanation |
Sources
- crates/corecruxd/console/v2/render.js:13108,
renderRings - crates/corecruxd/console/v2/render.js:15108, the ring's live wiring and the 50-item threshold
- crates/corecruxd/console/v2/render.js:2546,
owRenderTab, the shared view renderer - crates/corecruxd/console/v2/render.js:1989,
deriveAttentionZone - crates/corecruxd/console/v2/render.js:1054, the kanban sort registry
- crates/corecruxd/console/v2/render.js:11771,
renderActivityLog - crates/corecruxd/console/v2/render.js:10876,
renderSessionsBrowser - crates/corecruxd/console/v2/pages.js:1513, the nine Rings view slugs
- crates/corecruxd/console/v2/pages.js:1668, the grounded reasons the still-gated controls are gated

