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

FeedEndpointFeeds
Work boardGET /v1/work?source=allThe ring's plan wedges, the ExecPlans tile, the arc lens
Daemon glanceGET /v1/console/summaryThe facts, MCP agents, integrations and engine tiles
SessionsGET /v1/console/sessionsThe Sessions tile's per-day sparkline
Fact storeGET /v1/facts/list, pagedThe 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.

TileTypeHeadlineSparkline
ExecPlansLens (default)Count from /v1/workPlans active per day
ExecPlans arcLensTracks shown of plans in the corpusNone: it is a ratio, not a series
Data graphLensVisible fact nodes renderedFacts stored per day
MemoryLensMemory-kind cellsMemory cells per day
SessionsLensstores.sessionsReal last_active_unix_ms histogram
TokensLensTotal spend, in millionsTokens per day
factsGlancestores.facts, the whole storeSame real histogram as Data graph
mcp agentsGlancedaemon.mcp_agent_countNone, a point-in-time scalar
integrationsGlanceIntegration countNone
engineGlanceon / off from dataplane_enabledNone

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

LensWhat the geometry means
ExecPlansOne wedge per plan, cells at their write-day radius. Keeps solo, ledger, lineage and both filters
ExecPlans arcA 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 graphFacts as nodes. Angle is source date, radius is confidence (higher is nearer the centre), edges join facts sharing an entity
MemoryMemory-class cells only
SessionsSessions over the window
TokensToken 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).

ControlDefaultOn meansTurn it on when
Ambient spinOn, unless the OS asks for reduced motionThe whole ring rotates slowlyIt is on a wall display. Turn it off to read labels
Reset clock to 12MomentarySnaps rotation back to zero and stops spinYou have lost your bearings mid-spin
BarsOnEach node draws a spoke from the centre outwardOff gives dots, cleaner on a dense store
Time edgeOff (outward)Off: rings grow outward as time advances. On: nodes sink inward from the rimYou want newest material pinned at the rim
CensusOffEvery plan stays on the clock permanently instead of leaving when it finishes; hovering names sectorsYou are auditing the whole portfolio, not watching current work
Show completed plansOff. Auto-on during playbackFinished plans stay visibleYou are replaying history and want the finished work in frame
Completed-plans listOff. Auto-shows during playback, hides on lens swapA ledger of completed plans opens on the leftYou want to click through to a finished plan
State coloursOffRecolours by state: complete green, in progress purple, blocked redYou are triaging. Off colours by kind instead
Lineage chordsOffDraws depends_on relationships as chords across the circleYou are checking whether a plan is blocked by another

Two toggles appear only for their lens:

ControlAppears inOptionsDefault
Token viewTokens lenscumulative (running total across the window) / per daycumulative
FocusData graph lensIsolates the selected fact node and its connectionsOff

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).

MenuOptionsDefault
Filter by node kindall kinds · gates · decisions (OD) · memory · handoffsall kinds
Filter by agent passportall agents · claude-work · codex-workall 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):

ElementInteractiveWhat it is
Start-range labelNoThe window's first day, as text
Play / pauseYesReplays the window. If the clock is already at the end, pressing play rewinds to the start first
ScrubberYesThe clock position, 0–1000 across the window
End-range labelNoThe window's last day
Scrub dateNoThe date the clock is currently showing

The bottom bar carries the window and zoom (render.js:13305):

ControlTypeWhat it does
Window start dateDate pickerSets the first day rendered
window sliders (two)RangesThe same window, as a pair of handles
Window end dateDate pickerSets the last day rendered
Zoom out / Fit / Zoom inButtonsFit 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).

#ViewHashWhat it is
1Ring#/ringsThe canvas itself
2Activity#/rings/activityA three-panel triage board: Needs you and Fleet on the left, the activity feed on the right
3Live board#/rings/live-boardWho is working right now
4Orchestrators#/rings/orchestratorsGroup plans for a session
5Punchcards#/rings/punchcardsAdvisory path leases, grouped by holder
6Agent#/rings/agentMCP tool usage and reach. Professional mode only
7Board#/rings/boardThe size-adaptive tile dashboard
8Graph#/rings/graphThe relation graph
9Tree#/rings/treeProject → 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:

SignalSourceCard
A gated transition awaiting approval/v1/work/gate/pendingApprove / Reject, operator posture only
A plan in blocked state/v1/workRead-only, with its blocker reason and a link to the plan tree
A session that may need input/v1/coord/active intent notesRead-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):

FeedContributes
/v1/coord/activeAnnounced ExecPlan, milestone, intent note, session hex, leases, overlap rows
/v1/punchcardsHeld leases with their mode
/v1/console/sessionsThe saved-session id
/v1/orchestratorsOrchestrator 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:

BadgeMeans
123×Called that many times in the window
ignoredOffered to sessions but never called
never offeredIn the catalogue but absent from every session surface
unusedNo offered-data has accrued yet, the honest default
uncatalogedCalled 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

ElementSource
Risk badgerisk_class
Milestone tagcurrent_milestone
SlugDerived from plan_path's filename, or the id with execplan: stripped
Titletitle, or the id
Progress bar and countmilestones_done / milestones_total
Owner passportassignee_passport
Notelinked_pr
graph linkOpens the relation graph focused on this plan

The toolbar

ControlDefaultPersisted asWhat it does
Searchemptynot persistedFilters cards client-side across everything visible in the card
State chips, one per columnall showncrux.console.board.work.hiddenToggles a column's visibility. The last visible column cannot be hidden (render.js:1312)
SortUpdated · newestcrux.console.board.work.sortOrders cards inside every column

Four sort orders (render.js:1054):

SortMetricCaveat
Updated · newestupdated_at_unix_msPresent on every item
Created · newestcreated_at_unix_msPresent on every item
Title · A→ZLocale compare-
Completion · most donemilestones_done / milestones_totalNot 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

ControlDefaultWhat it does
sessionblankBlank means all sessions. Enter an id and press Enter to reload into the single-session lane
token budgetthe page defaultPer-page retrieval budget. Press Enter to reload. A budget-truncated page says so in the status line
search (client-side)emptyFilters the loaded rows only. Never re-queries. 200 ms debounce
Kind chipsall onOne 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 liveoffOpens 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):

  1. Dereferences the turn's verbatim entries.
  2. Requests verification of them and renders a badge per entry, verbatim from the daemon:
BadgeMeans
✓ 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

LimitBehaviour
Single-session lane is not paginatedThe 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 capPast 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).

FieldTypeDefaultNotes
nametext-Free text
idtext, mono-Slug
execplan storageselectplanning repo (recommended)Also: daemon-native, hybrid, repo files + daemon kanban
Create projectbutton-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).

ControlDefaultWhat it does
filteremptyClient-side across id, agent, actor, passport, plan slug, matched plan id and title
archivedoffRe-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).

StatCounts sessions with
identity (actor, key prefix or binding)Any identity signal at all
write-time actor stampAn actor recorded at write time
passport bindingA minted passport binding
plan link (binding or live announce)A link to an ExecPlan by either route
agent-given titleA 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:

SectionContent
sessionRaw key, agent, state, updated, expires, archived + reason
passportThe binding, or a note that bindings are minted on POST /session and agent save_session ids resolve to none
linked ExecPlanThree lanes, most authoritative first (below)
gates decidedGate decisions by this passport, with receipt short-ids
token usageTotal tokens, and the estimate method, serialised state bytes ÷ 4
state JSONThe full state blob, collapsed

The three plan-link lanes are ranked and labelled, which is the point:

LaneStrengthMeaning
same-id matchExactThe session's id is an ExecPlan work-item id. Identity, not inference
live announceTTL-scopedA coordination announce, valid while the TTL holds
heuristicDerivedexecplan:* 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

SymptomCause
The ring shows plans you do not recogniseYou are on the snapshot. Check for data-src="live"; the live swap needs ≥50 qualifying items
Rings tiles show counts but the ring is emptyThe window excludes your data. Reset the date pickers or press Fit
The kanban is empty but you have plansCRUX_EXECPLANS_ROOT is not set on the daemon process, so the projection has no files to read
Activity is empty with a warn bannerCORECRUXD_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 offNo coordination features are enabled, expected on a stock daemon except for coord
Sessions all show no plan linkNothing is binding sessions to plans. The allocation panel's why string is the daemon's own explanation

Sources