Developer preview. Pre-admission. Not for sensitive, proprietary, regulated, or production code. Expect breaking changes and data loss. Read the limits.

DESIGN — COCKPIT V2

The complete UI reimagining. Nothing from the current UI is reused — not one component, not one layout, not one page.

This spec is written to be handed to build agents verbatim. Where a builder could choose, the choice is made here. Where a capability does not exist yet, the section is marked NEEDS-BACKEND with the exact shape of the need. Marks: BUILD-NOW (phase 1–2), BUILD-NEXT (phase 3–4), NEEDS-BACKEND (blocked until the named block/action exists — design is final, wiring waits).


0. The verdict this answers, and the standing law

The user’s verdict, condensed to its charges, each with the structural answer in this spec:

Charge Structural answer Section
“still see the old ui: metrics, stats at the top, right menu, git, login page” The old component tree is deleted at cutover. No page called Metrics, no right rail, no login form, no git panel exists in V2. §13
“sidebar of rows / tiles above and below / chat not full width” One shell grammar: FLOW · SWEEP · DESK · HORIZON · ROOMS · SCOPE. There are no tiles, no sidebars, no floating chips. The conversation is the full-bleed center. §2, §3
“tiles not the same size, not clear, maybe there’s better than tiles” Tiles are abolished as a category. Where uniform cells are genuinely right (the Instruments room), every cell is the same fixed size by mechanical test. §2.6, §8
“we don’t care about data if we cannot act on it” No verb, no pixels. A fact renders by default only if it carries an operable verb or an abnormal state. Everything else lives behind ask/zoom. §1.2
“buttons doing nothing useful” Every control in this spec names the block action it POSTs. A control without a wired action is forbidden by guard. §1.2, §14
“not interesting or interactive, no life, feels like an informational dashboard” The system visibly computes: findings authored by the computer dock into the flow at the moment of relevance; the bead runs the causal edge; the sweep ticks with real events. §1.3, §4, §11
“navigating to a project/conversation is not very clear” One gesture: the Switch — full-screen, recency-ordered, type-to-filter, every row carrying measured facts and verbs. §5
“timeline is identical, I asked for novel ways” The timeline list is deleted. The record is the SWEEP (persistent flight-recorder band) + semantic-zoom into causal trees + the ARM retro-trigger. §6
“graphs loading all broken, things loading after everything else” One-reveal boot: fixed geometry first paint, one coordinated fill, and a mechanical guard that nothing mounts late. A chart may render only with ≥2 measured points. §8.3, §10
“options everywhere, no consolidated” Settings exist in exactly two forms: adjust-in-place (from the pixel where the behavior manifests) and one flat searchable index. No settings pages per feature. §9

The three binding principles (equal weight)

  1. THE SPINE. The conversation/run is the product; everything else is instrumentation around the living run. Full-bleed when active. The causal flow of a run visibly moves through the instruments.
  2. ACTION-FIRST. Every fact carries its verb, adjacent and operable. Every verb has a real effect (a named block action). No data display without its action; no button without an effect.
  3. THE SYNTHESIS. Raw facts are the floor. Surfaces earn their place by deriving what no single source contains — aggregate, match, extrapolate (honestly labeled), compute on demand — with the derivation stated and inspectable.

What survives (and only this)


1. The operating rules (mechanically enforced)

1.1 The honest-data law (inherited, restated)

Nothing fabricated, ever. Absence renders as absence, in plain words (“not measured yet”, “collecting since 14:02”). Every number is a measured number with an asOf. Projections are permitted only with their derivation sentence attached (§4.4). Plain zero-knowledge language everywhere: no internal ids, no registry vocabulary, no git nouns in first position.

1.2 No verb, no pixels

A fact earns default pixels only if at least one of:

Everything else exists — reachable through ask (§4.5), the Instruments room (§8), and LENS — but does not sit on screen. This is the High-Performance HMI result (40–60% faster operator response on quiet-by-default surfaces) applied as a rendering precondition, and it is the honest form of “we don’t care about data we cannot act on.”

Guard (new, cockpit-native): tests/prevention/cockpit-verb-owner.test.ts — every interactive element in src/cockpit/** must reference a registered block action id or a client navigation primitive; a <button> without one fails CI.

1.3 The computer speaks in findings

Derived facts (aggregate / match / extrapolation) are authored by “the computer” and render as findings: a distinct typographic register (§12.5), a ∴ gutter mark, a derivation one level deep behind LENS, and the verb where one exists. A finding may never state what a single source already states — it must join, count, compare, or project. §4 specifies the engine.

1.4 One manifestation per fact per screen

A fact renders in exactly one place at a time. Pinned monitors (§2.5) are references to the single source, and open their source on click. This kills the duplicate-tile disease structurally.

Guard: cockpit-manifest-owner.test.ts — signal ids rendered in the FLOW may not simultaneously render in HORIZON except via the monitor reference component.


1.5 THE FEEL — acceptance criteria every surface must satisfy

The user’s bar, verbatim: “the ux must feel very smart and adaptive, show whats most important, it must feel like its alive and reactive to both the data and the user, it must be interesting to use and dynamic.” Concretized as four testable qualities. Every surface section below must deliver all four (the matrix at the end of this section is the checklist); where a surface honestly cannot deliver one, it says so and why.

F1 — Smart & adaptive. The surface reorganizes around computed importance: synthesis and the admission controller decide prominence; dark-cockpit discipline decides what earns color and size. “Show what’s most important” means the system decides — and the decision is always explainable: LENS on any prominent element states why it is prominent in plain words with its inputs (“expanded: it caused the beat you’re focused on” / “annunciating: crossed its declared threshold 40s ago”). Unexplained salience is a bug, mechanically: any component that sets prominence must pass a reason prop; cockpit-salience-owner.test.ts fails a prominence change without one.

F2 — Alive & reactive to the data. Real activity visibly moves through the UI as it happens: beats appended as they stream, the bead traversing recorded edges, the sweep’s now edge ticking, breakers glowing during their calls, digits rolling on true change. Nothing pulses that didn’t happen (the no-fake-motion guard, §11.8), and everything that happens registers within the latency budget — a spec-level requirement builders inherit, enforced in CI:

Budget Bound
keystroke → paint < 16ms
action → visible acknowledgement < 100ms (optimistic; same frame for press states)
any view/room/scope open < 200ms
live event → its beat/tick on screen < 100ms from frame receipt
finding → docked at its seam < 300ms from the seam event

F3 — Reactive to the user. Attention and intent change the surface: hover deepens (adds precision, provenance, previews — never mere highlight); focus arms verbs (the focused beat’s verbs move to full contrast and onto the home keys . and ,); a selection rescopes every consuming surface at once through the selection bus; the composer’s / grammar scopes to the focused object first; and recorded use shapes defaults honestly — the computer surfaces the verb you habitually take at the moment you usually take it (∴ You ran checks after your last 5 edits — run checks now, from insight.habit), and says exactly that when asked. Manual choices always beat computed ones and are remembered (§3.2 fisheye, §4.6 dismissal learning).

F4 — Interesting & dynamic. The interest is power: operating a live system mid-flight (breakers and interventions at quantized boundaries), a computer that visibly derives and speaks at the right moment, retro-capture of anything because everything was recorded, and depth everywhere (every fact opens; every number is a handle). Motion has meaning or does not exist. No decoration budget exists; the fun budget is spent on responsiveness, verbs, and discovery.

The matrix (how each surface delivers; builders verify per row):

Surface F1 smart/adaptive F2 alive to data F3 reactive to user F4 interesting/dynamic
FLOW (§3) causal fisheye with stated reasons; check deltas not states beats stream in; bead runs recorded edges focus arms verbs; expand/collapse remembered; selection lights ribbons every beat opens; verbs on the past (rerun, rewind, fork)
DESK (§3.4–3.5) strips ordered by token share; abnormal-only summaries when closed live gauges; executing tool glows; strips re-measure per turn , opens any row’s setting; breaker flips take effect at next boundary mixing the model’s next turn; mid-run breaker flips
COMPUTER (§4) admission controller ranks findings; dismissals retrain it findings dock <300ms of their seam event ? grammar; dismissals learned; habit verbs at their moment the system thinking alongside you — the core of F4
SWITCH (§5) recency river; outcome lines rank what mattered micro-sweeps are real densities; badges from live state type-to-filter <50ms; stable spatial grouping reels tell what happened there; replay from start
SWEEP/ARM (§6) error ridge and flags stand out only when real now edge ticks per event; backfill on boot scrub = time travel everywhere; zoom to any depth; m marks arming traps; retroactive capture; causal chains lighting
CUSTODY (§7) parcels grouped by producing run; unattributed honestly separate updates on real fs/git events keep/undo per parcel or file; suggested message from your own words undo at run granularity; history joined to conversations
INSTRUMENTS (§8) dark by default; abnormal cells are the only colored ones signals stream; digits roll on true change pin to HORIZON; ask prefills the question; adjust in place every number is a handle into ledger + setting
SETTINGS/LENS (§9) index ranks by recently-manifested surfaces values read back live after write adjust from the pixel; search by behavior words honestly limited F4: an index’s job is consolidation, not delight — its interest is that you rarely need it
REGISTRATION (§10) honestly limited F1: boot is a fixed probe sequence; its adaptivity is compression (fast system → 3 lines, 200ms) every line is a measured probe; sweep backfills with real history typing during boot buffers into the composer, never lost the record surfacing right-to-left — once per session, earned

2. The shell grammar — FLOW · SWEEP · DESK · HORIZON · ROOMS · SCOPE

[Brief §8 — the layout system. Decision: committed.] Not a spatial canvas (user-arranged canvases decay into janitorial work and entropy — the documented failure of Muse-class tools). Not stage-and-wings (wings re-grow into the rail we just killed). The commitment is a single-column instrument stack: everything is either in the flow, on one of three fixed instruments, or in a summoned room. The user never manages layout. Layout is computed from the run’s causal structure.

┌──────────────────────────────────────────────────────────────────────┐
│ HORIZON  40px   identity · place · annunciators (≤3) · monitors (≤4) │
├──────────────────────────────────────────────────────────────────────┤
│                                                                      │
│ FLOW     flex   the run — full-bleed block stream                    │
│                 prose at measure (76ch, centered)                    │
│                 instruments + effects bleed to full width            │
│                 findings docked at causal seams                      │
│                                                                      │
├──────────────────────────────────────────────────────────────────────┤
│ SWEEP    48px   flight recorder — the whole ledger, always visible   │
├──────────────────────────────────────────────────────────────────────┤
│ DESK     64px   where you act: composer · gauges · breakers grip     │
│          ↕ 280px when opened (channel strips + breaker panel)        │
└──────────────────────────────────────────────────────────────────────┘
ROOMS   full-screen, summoned, one at a time, Esc closes (Switch,
        Instruments, Custody, Settings index, Memory, Tools)
SCOPE   the inspector — right sheet min(560px, 42vw); at ≥1900px it
        side-docks and the FLOW narrows; below, it overlays

Prior art & difference: closest is Warp’s block terminal (viewport = ordered typed blocks). Structural differences: (a) our stream is causal, not linear — blocks nest and reference by parentEventId; (b) three fixed instruments (HORIZON/SWEEP/DESK) frame the stream, none user-arranged; (c) rooms replace tabs/routes entirely.

2.1 The FLOW

Full-bleed vertical stream of the active conversation/run. Internal grid: a 76ch centered measure for prose (yours and the model’s words), with full-width bleed rows for anything instrumental — tool beats, diffs, findings, gauges. This is the honest answer to “chat not taking the full width”: text gets a readable measure (a 3840px-wide paragraph is worse, not better); instruments get every pixel. Nothing ever renders above or below the flow except the three fixed instruments.

2.2 The SWEEP (fixed, 48px)

The recording lattice made permanently visible — a horizontal density band of the entire ledger for the current scope. Specified in §6. It is one continuous instrument, not a strip of anything.

2.3 The DESK (fixed, 64px closed / 280px open)

Where all acting happens: the composer (one input, three grammars, §5.3), the context gauge, and the grip that opens the full desk — channel strips (CONTEXT DESK) and breakers (BREAKER PANEL). Specified in §3.4–3.5.

2.4 The HORIZON (fixed, 40px)

The only top chrome. Left: identity glyph (you, measured session) and place — project ▸ conversation, which is the Switch trigger. Center: annunciator slots — at most 3, priority-ordered, dark when healthy (a lit slot = a fact in abnormal state + its verb: 1 check failing · rerun). Right: up to 4 pinned monitors (user-pinned live values, uniform 96×28px each) and the LENS toggle. No metrics strip, no logout button, no model selector parked here — model lives at the desk where sending happens; sign-out lives under the identity glyph.

2.5 ROOMS

Full-screen surfaces summoned by key or verb, never persistent, never side-docked: Switch (§5), Custody (§7), Instruments (§8), Settings index (§9), Memory, Tools/Breakers full view. One room at a time; Esc always returns to the flow; the flow’s state is kept alive under it (keep-alive survives as a concept — re-implemented in the cockpit shell, not via any old component).

2.6 Manifestation ladder (the density ladder, re-expressed)

The Tier 0–4 contract survives; its geometry is remapped. A module manifests as:

Contract tier V2 manifestation Where
t0 sweep badge / annunciator pip SWEEP, HORIZON
t1 pinned monitor (96×28, uniform) HORIZON
t2 finding / interstitial card (full-bleed row) FLOW
t3 room section ROOMS
t4 SCOPE sheet SCOPE

The relevance engine survives as the finding admission controller (§4.6) — it decides what may dock into the flow, with the same damping disciplines (dwell, hysteresis, budget), not as a rail re-orderer (there is no rail).

2.7 Geometry, breakpoints, density, keyboard

Key Action  
⌘K or / in empty composer command grammar in the composer (§5.3)  
⌘J the Switch  
⌘. open/close the desk (strips + breakers)  
⌘' Instruments room  
⌘, Settings index room  
⌘G Custody room  
[ ] sweep scrub back / forward (asOf) · ⇧[ ⇧] by run  
Enter on a beat open its SCOPE · Esc close scope / close room / return to now  
↑↓ move beat focus by causal order · ←→ collapse/expand a beat’s children  
⌘⏎ send · i focus composer  
. on any focused fact its verb menu · , on any focused fact its setting (§9.1)
⌘L LENS mode (explain any pixel)  
⌘⇧A ARM a trigger (§6.4)  

Roving tabindex through beats; every divider with full separator semantics; one global :focus-visible rule in the new token file.

Mark: BUILD-NOW (the shell is phase 1).


3. The spine — the FLOW, the DESK, the live run

[Brief §1]

3.1 Concept

The conversation is a causal block stream: one ordered, virtualized stream of typed beats. A beat is one causal fact: your words, the model’s words, a tool call, a file effect, an inline event (hallucination/steering/bias/self-heal from EVENT_KINDS), a check delta, a finding. Beats carry their verbs on the surface (not behind hover-only affordances; hover adds, never reveals-or-else). Tool calls show their actual input → output transformation (“show the data”), not a status line — the recording already has both sides; no competitor can render this honestly.

During a live run, the causal flow is visible motion: the bead (§11.2) travels the real edge from the desk into the turn, branches into each tool beat as it opens, and lands on effects as they commit. The flow renders causality as it happens, not after.

3.2 Beat anatomy

Every beat, uniformly:

[gutter 32px] [body: measure or bleed] [verbs, right-aligned, visible at rest]
 gutter: causal spine line + beat glyph (per kind) + connection to parent

Causal fisheye (concept transplant, DOI with an honest function): beats collapse with causal distance from your focus — full beat → one-line ghost → tick in the gutter. The interest function is explainable from the record (causal distance + recency + abnormality), and every compressed beat states its reason on focus (“collapsed: 3 turns old, no effects”). ←→ expand/collapse manually; manual wins over automatic for the session. Closest prior art: fisheye source-code views (CHI 2006); difference: no geometric distortion, only representation change, and the DOI terms come from the causal ledger so “why is this big?” always has an answer.

3.3 Walkthrough — a run, second by second

  1. You type “refactor the reader path” and hit ⌘⏎. The beat appears instantly (optimistic); the bead leaves the desk gutter and enters it.
  2. The model turn opens; words stream at measure. The desk gauges tick: context 61% → 62%, tok/s live.
  3. A tool beat opens full-bleed: read file — src/lib/data/reader.ts — the bead forks into it; input path on the left cell; 4ms later the output cell fills (first 6 lines + fold). The beat closes to one line.
  4. edit file opens; +42 −8 · writing… with args streaming. The BREAKER chip for edit file in the desk glows live (it is being used now).
  5. The effect beat commits: src/lib/data/reader.ts +42 −8 with see what changed · undo this · keep this. The sweep ticks — a new event mark appears at “now.”
  6. The computer speaks: ∴ This edit reaches 47 files through 12 imports — see them · run checks now (computed from the existing impact block, docked at the seam within 300ms of the effect, §4.2).
  7. A check delta beat: typecheck: passing → failing (1 error) — rerun · open error.
  8. The run ends. The turn seam renders: a full-bleed hairline carrying the turn’s measured rollup in one sentence (§4.3) — not a card, one line with verbs.

3.4 The CONTEXT DESK (integrated, not bolted on)

Open the desk (⌘.): the composer stays; above it, channel strips — one per context source of the next turn, mixing-desk style:

SYSTEM PROMPT   ████████░░  3,211 tok           [view] [pin]
MEMORIES (4)    ██░░░░░░░░    812 tok   [view] [pin] [mute]
HISTORY 12 turns█████████░  9,404 tok   trim point ▸ turn 4   [adjust]
FILES (2)       █░░░░░░░░░    488 tok   [view] [mute]
TOOL RESULTS    ███░░░░░░░  2,006 tok   [view] [mute]
────────────────────────────────────────────────────────────
NEXT TURN       15,921 / 100,000 tok · 16%      [model: … ▾]

Every bar is a measured share of the next composition (from the same composition math the server uses — served, not simulated). pin = always include; mute = exclude from the next turn; the trim point is draggable by turn. Per-turn provenance: any past turn’s gutter glyph opens its recorded composition strips read-only in the SCOPE — what the model was actually given, from the ledger.

Closest prior art: Ableton’s mixer / channel strips. Structural difference: channels are context sources with measured token cost, and the faders are real composition controls, recorded to the ledger when changed.

NEEDS-BACKEND: a run.compose block —

3.5 The BREAKER PANEL (integrated, not bolted on)

Right half of the open desk: one row per available tool — breaker rows, uniform:

edit file     ● on    12 calls · last 3.2s   [off]
run command   ● on     4 calls · last 11ms   [off]
web fetch     ○ off    0 calls               [on]
search        ▲ tripped — 3 failures in a row [reset] [why]

NEEDS-BACKEND: tools.breaker block — read: per-tool { id, label, state: "on"|"off"|"tripped", calls: number, lastMs?: number, lastError?: string } for the current chat; actions: tools.breaker/set { tool, on: boolean, at: "next-boundary" }, tools.breaker/reset { tool }, tools.breaker/arm { tool, tripAfterFailures: number }. The run loop must honor at: "next-boundary" and record the flip as a ledger event with the acting user.

3.6 What this replaces

The chat panel, the transcript card, the tool accordions, the activity/timeline split, the run status widget, the steering queue, the tools page toggle list, the context gauge in the old header. All deleted.

3.7 Honest-data story

Every beat is a rendered ledger fact with traceId from the envelope. Streams render only received frames. The composition strips are served by the composing code path. Absent causality renders as visible absence (unattributed renders as its own mark, never hidden).

3.8 Build shape

New components (src/cockpit/flow/): Flow.svelte (custom height-indexed virtualizer — index beats by height, contents opaque, the Warp SumTree approach; the event log stays outside $state, only the visible window is reactive — this is the known Svelte 5 large-proxy trap), Beat.svelte + kind bodies (TurnBeat, ToolBeat, EffectBeat, CheckDeltaBeat, EventBeat, FindingNote), Seam.svelte, Desk.svelte, ChannelStrip.svelte, BreakerRow.svelte, Composer.svelte, Bead.svelte. Sources: the existing run stream channel + trace events via the Broker; blocks run.compose, tools.breaker (new), diffs via the existing git diff-patch route surfaced as a block.

Mark: BUILD-NOW (the spine is phase 1; compose/breaker actions land as their blocks land — render read-only from what exists rather than waiting).


4. The synthesis — the computer, and its findings

[The third principle made concrete. This is the life of the product.]

4.1 Concept

The system is not an observatory; it is a colleague that shows its work. Findings are computed sentences that join sources: ledger × checks × context × git × history. Each finding is: one sentence · ∴ mark · its verb(s) · its derivation one LENS-level deep (the exact join, in plain words, with counts). Because the causal ledger is complete, matching is exact joins over recorded history — honest pattern-matching, not model guessing. That is the unclonable version of “smart.”

Closest prior art: IDE “insights” panels and observability anomaly feeds. Structural difference: findings are deterministic joins with mandatory derivations, docked at their causal moment in the spine, each carrying an operable verb — never a separate insights page, never a confidence score.

4.2 The four synthesis moves

  1. Aggregate — cross-source rollups. ∴ This conversation: 6 files touched, 2 checks failing that passed before it started, 40% of context consumed. Verbs: each clause is a handle (files → Custody, checks → rerun, context → desk).
  2. Match — the present against the recorded past. ∴ 3 previous runs edited these same files — two needed follow-up fixes. see them · ∴ You've turned this tool off in 4 of your last 5 runs. keep it off by default? Exact joins on file paths, tool ids, check ids, error signatures across traceIds.
  3. Extrapolate, labeled — deterministic projections with stated derivation. ∴ At this rate, context fills in ~12 messages — projection from your last 10 messages (avg 1,120 tok each). trim now · adjust Never rendered without the derivation clause. Never a probability.
  4. Compute on demand — §4.5: asking is a primary gesture at the desk.

4.3 Placement — findings dock at causal seams

Findings render in the flow, at the moment of relevance, at three seams only:

Findings never interrupt streaming prose (they wait for the beat to close), never stack more than one deep per seam (the admission controller queues the rest behind a +2 more fold), and never push content the user is reading (they dock below the reading position or above the desk).

4.4 The derivation contract

Every finding carries, one LENS-level deep: the sources joined (as block/signal ids in plain words), the counts at each join step, and the asOf of the oldest input. Guard: cockpit-derivation-owner.test.ts — a finding component may not render without a machine-readable derivation prop; extrapolations must include the word “projection” and their input window.

4.5 Asking — the ? grammar

The composer accepts three grammars (§5.3). ? asks the computer, not the model: deterministic computed questions against the intelligence blocks that already exist (impact, path, reuse, retrieval) and the new insight blocks. ? what does this edit reach → the impact answer as a finding, instantly, zero model tokens, derivation attached. ? runs that touched reader.ts → a match listing with verbs (open, compare). The answer renders in the flow as a finding beat you can keep or dismiss. Autocomplete enumerates the askable questions from the block registry — the palette cannot lie about what’s computable.

4.6 The admission controller

The relevance engine survives here: it scores candidate findings (base per kind + boosts from when-eval predicates), admits at most one per seam, applies dwell (a finding stays ≥8s before another may replace it at the desk line), and learns dismissals (a finding kind dismissed 3× in a session stops self-docking and retreats to ask-only — recorded, inspectable in the Instruments room).

4.7 What this replaces

The conversation-summary tile, the awareness/quality signal boards as passive walls, every “insight” that was a static stat. Deleted.

4.8 Honest-data story

Every finding is a deterministic function of ledger rows and block reads, reproducible from its derivation. If a join returns zero rows, no finding renders (absence of a finding is the honest output). Projections state their window and method inline. No finding ever uses a model.

4.9 Build shape

src/cockpit/computer/: FindingNote.svelte, Derivation.svelte, admission controller store (computer.ts — plain module, when-eval predicates, dwell timers). Client-computable now: turn rollups (from cached beats + checks state), context projection (measured tokens/message from the transcript). NEEDS-BACKEND for the joins:

Mark: BUILD-NOW for client-computable findings + the ? grammar against existing intelligence blocks; NEEDS-BACKEND for the three insight blocks (exact shapes above).


5. Navigation — the Switch and the one input

[Brief §2]

5.1 Concept

There is no sidebar, no project list page, no tab bar. Navigation is one full-screen room (the Switch) plus one command grammar in the composer. Places are reels: a conversation with its measured outcomes, not a row with a name.

5.2 The Switch (⌘J, or click the place in the HORIZON)

Full-screen room, instant (in-memory data). Layout: a single recency river — reels ordered by last activity, grouped under their project caps, newest at top-left, flowing left-to-right then down. Every reel is the same fixed size (grid cells 320×88px): name · relative time · one measured outcome line (14 turns · 6 files · checks green — from insight.rollup, or honest absence: no runs yet) · a 24px micro-sweep (that conversation’s real event density). Verbs on the reel: resume (default, Enter) · replay (opens with the sweep scrubbed to start) · custody (its uncommitted work, if any — badge visible).

Closest prior art: macOS Mission Control / Arc’s space switcher. Structural difference: every cell carries measured run outcomes and verbs, and the micro-sweep is the real ledger density — a switcher that tells you what happened there, not just what it’s called.

5.3 The one input (composer grammars)

The composer is the only text input in the shell. Three prefixes, mode chip renders as you type:

Closest prior art: Superhuman/Raycast palettes. Structural difference: the verb list is the self-enumerating block registry — the palette is generated from the same declarations the server executes, so it can neither lie nor go stale.

5.4 What it replaces / honest data / build shape

Replaces: the 25-row module sidebar, the projects panel, the constellation, the tab bar, breadcrumbs-as-navigation. Honest: outcome lines come from insight.rollup (absence: “no runs yet”); micro-sweeps from the spectrum block, never decorative. Build: src/cockpit/rooms/SwitchRoom.svelte, Reel.svelte, MicroSweep.svelte (one shared canvas painter with the SWEEP); CommandGrammar.ts + GrammarMenu.svelte in the desk. Sources: entities blocks (exist), insight.rollup (§4.9), spectrum (§6.6).

Mark: BUILD-NOW (Switch with honest absences before insight.rollup lands).


6. The flight recorder — SWEEP, semantic zoom, ARM

[Brief §3 — not a list. The timeline list is deleted.]

6.1 Concept

The ledger is always on screen as the SWEEP: a 48px full-width band above the desk — a time-binned density skyline of every recorded event in scope, drawn on one canvas. It is at once: proof the system is recording (the lattice, visible), the navigation instrument for time, and the trigger surface for forensics. The “timeline page” concept is abolished; depth comes from zooming into the sweep, not from a different screen.

6.2 Anatomy

6.3 Semantic zoom (the camera, without the canvas)

Scroll/pinch on the sweep zooms time. Zoomed out: runs are single blocks (skyline). Zoom in: a run opens into its causal tree — turns as bands, tool calls as nested ticks. Zoom further on any tick: it becomes a full beat preview; Enter opens the SCOPE on it. The layout at every zoom level is computed from the record — the user never places anything. DOM blocks render only near focus (~10–100), canvas carries the mass.

Closest prior art: video-editor timelines and tldraw’s camera. Structural difference: one axis is always time (no 2D wandering, no lost-in-space), the representation changes with scale (semantic, not geometric), and zoom targets are causal structures from the ledger.

6.4 ARM — the retro-trigger

Because recording is complete, capture can be retroactive. ⌘⇧A (or , on any check/tool/signal → “arm”): define a trigger from a small predicate menu (when-eval over live events/signals): a check fails · any tool errors · context crosses 80% · file X is edited. Armed triggers live on the sweep’s left edge as cocked flags. When one fires:

Oscilloscope arm/trigger semantics on a software ledger — closest prior art is a scope’s single-shot trigger; the structural difference is retro-capture is free because the “waveform” (the ledger) is always fully recorded.

6.5 Causal ribbons

Selecting any beat or sweep tick lights its causal chain: the gutter spine in the FLOW draws the parent path (run → turn → call → effect) in the beam color, and the sweep underlines the same instants. One chain at a time. This is brush-and-link reduced to the one linkage that matters: cause.

6.6 What it replaces / honest data / build shape

Replaces: the timeline page, the event list, the event-inspector panel (its content moves to SCOPE), rewind menus (rewind = a verb on your past turn beats). Honest: bins are server-counted rows; the now edge ticks only on received events; a paused stream renders a visible stream reconnecting — last event 14:02:31 state on the sweep itself, never a frozen fake-live band. Build: src/cockpit/sweep/ — Sweep.svelte (canvas painter + a parallel a11y outline listing runs/flags for AT), SweepHead.svelte, ArmMenu.svelte, CausalRibbon.svelte (SVG path in the flow gutter). NEEDS-BACKEND: sweep.spectrum block — read ?scope=chat|project&bins=1200 → per-bin counts per category + error count, packed (base64 Int16Array), plus arm.flags block (read stored flags/ranges; actions arm/set {predicate}, arm/capture {t0,t1,label}, arm/clear {id} — flags are ledger-backed). The head’s asOf resolution needs ranged reads (?until= param) on history-bearing blocks — an additive, uniform block-read param.

Mark: BUILD-NOW for the sweep band + head with a client-binned fallback over the already-streamed window; NEEDS-BACKEND for full-history spectrum + arm storage + until reads.


7. Git → CUSTODY — status is verbs

[Brief §4]

7.1 Concept

Git nouns (stage, stash, HEAD, branch) never lead. The product speaks custody of work: every changed file is held by the run that produced it (an exact ledger join — effect events carry the file and the producing turn), and the three verbs are keep (commit), undo (revert), see what changed (diff). Custody appears in two places: on effect beats in the flow (§3.2 — the primary surface), and the Custody room (⌘G) as the consolidated view.

7.2 The Custody room

Full-screen, one column of work parcels — changes grouped by the producing conversation/turn (not by directory, not by staged-ness):

FROM THIS CONVERSATION · turn 7 · 14:02                       [keep all] [undo all]
  M src/lib/data/reader.ts   +42 −8      [see] [undo]
  M src/lib/data/broker.ts   +11 −0      [see] [undo]
FROM "fix flaky test" · yesterday                              [keep all] [undo all]
  M tests/reader.test.ts     +6 −6       [see] [undo]
NOT FROM A RECORDED RUN                                        [keep all] [undo all]
  M notes.md                 +2 −0       [see] [undo]
────────────────────────────────────────────────────────────────
SAVED WORK  ‹history as a run-correlated list: each save shows the
conversation that produced it›            [share this work ▸]

Closest prior art: GitHub Desktop / Tower. Structural difference: grouping key is the producing run via the ledger join — no other tool can group changes by the conversation that caused them, or revert at run granularity.

7.3 Honest data / build shape

All statuses are real reads; the run-attribution is the effect-event join, and files with no join render in the unattributed bucket. undo uses git checkout paths (no invented preimage store needed). Build: src/cockpit/rooms/CustodyRoom.svelte, Parcel.svelte, DiffSheet.svelte (SCOPE body, real unified diffs from the diff-patch route surfaced as a block). NEEDS-BACKEND: custody.state block — read → parcels as above (server does the ledger join effect-events × current git status); actions custody/keep { files, message }, custody/undo { files }, both recorded; custody.history read → commits × producing-chat join.

Mark: BUILD-NEXT (effect-beat verbs in the flow are BUILD-NOW via existing git routes; the room and the join block follow).


8. Metrics → honest instruments

[Brief §5 — no broken charts, no space waste.]

8.1 Concept

There is no metrics page. Measured numbers live where their verbs live: context at the desk, tok/s on the live turn, per-tool latency on breaker rows, check history on the check’s own scope. The consolidated fallback is the Instruments room (⌘') — the honest index of every measured signal, dark-cockpit style: quiet, uniform, actionable.

8.2 The Instruments room

A uniform grid of instrument cells, all exactly 280×96px (mechanical test), grouped by module, no gaps, no featured tiles:

┌ context utilization ────────┐┌ tool calls (this chat) ─────┐
│ 16%            ▁▂▂▃▃▄       ││ 12          ▂▁▄▂▃▅          │
│ asOf 14:02 · adjust · ask   ││ asOf 14:03 · breakers · ask │
└─────────────────────────────┘└─────────────────────────────┘

Each cell: plain-language name · current measured value · spark only if ≥2 measured points exist (with fewer, the measured value alone owns the readout — no chart, no placeholder, no empty axes, no broken chart can exist by construction; collecting since 14:02 is the absence state of a cell with no sample yet) · asOf · up to two verbs resolved mechanically from the exposure registry (its bounding setting → adjust-in-place; its action → the verb; always ask → prefilled ? query). Cells with no data render the honest absence state, same size. Signals stream over the existing signal channel; digits roll only on real change.

pin on any cell → it becomes a HORIZON monitor (uniform 96×28: name, value, spark-dot). Max 4; pinning a 5th asks which to displace.

8.3 The no-broken-chart law

A time series renders only from its measured ring buffer. No axis without data; no interpolation across gaps (gaps render as gaps); no chart placeholder states. Guard: cockpit-chart-owner.test.ts — the spark component throws in dev if fed <2 points, and the cell renders the absence state instead.

8.4 Replaces / honest data / build shape

Replaces: the metrics page, all 11 generated signal boards as separate surfaces, every stat tile, the header token counters (tokens now: turn footers, desk gauge, turn-seam rollups). Build: src/cockpit/rooms/InstrumentsRoom.svelte, InstrumentCell.svelte, Spark.svelte (one canvas painter shared with micro-sweeps), Monitor.svelte (HORIZON). Sources: the signal stream + exposure registry (exist). Mark: BUILD-NEXT (nothing here blocks the spine; monitors ship with HORIZON in phase 1).


9. Settings — in place, plus one index

[Brief §6 — “options everywhere, no consolidated” → two surfaces total.]

9.1 Adjust-in-place (the fact→verb rule applied to config)

Anywhere a behavior manifests, , (or the ·adjust verb) opens the setting sheet: a one-setting SCOPE mini-sheet anchored to the fact — label, plain description, the control (drag-scrub numeral / segmented enum / switch), the current measured effect where one exists (trip after 3 failures — tripped twice this week), and save writes through the existing customization action, optimistically, recorded. The mapping fact→setting resolves mechanically from the exposure registry (Facet.signalId → customizationId), never hand-wired.

9.2 LENS, redesigned, gains “change this”

LENS survives as a concept and a data layer; its overlay is new: ⌘L then hover — a single hairline callout (not a panel) naming the pixel’s source (signal context.utilization · 1.2s ago · via stream), its derivation if computed (§4.4), and its verbs: adjust (the setting sheet) · ask · open source. LENS is now the universal answer to “why is this here and how do I change it.”

9.3 The index (⌘,)

One flat, searchable room generated from the 88 customizations + cockpit-local preferences (density, reduced motion, sound opt-in, theme): every row = label · current value · inline control · which surface it manifests on (a link). Search by behavior words, not by internal names. No categories-as-pages, no per-feature settings screens, no duplicated controls: the index rows and the in-place sheets are the same component bound to the same action.

Replaces: the settings page(s), the client-debug section, scattered per-panel option menus. Honest: every row shows the value read back from the server after write (no silent overwrite). Build: SettingSheet.svelte, SettingsRoom.svelte, LensCallout.svelte. Mark: BUILD-NEXT (the setting sheet primitive early, since breaker/ARM rows use it).


10. Login + boot — REGISTRATION

[Brief §7 — the first second is the product’s character.]

10.1 Concept

Boot and login are one continuous registration sequence — the instruments checking in, truthfully. No splash, no spinner, no form floating in a void, and no late pop-in ever.

10.2 Walkthrough — cold start, signed out

  1. First paint (<100ms, static shell): the full cockpit geometry — HORIZON, empty FLOW, SWEEP band, DESK — in the ground palette, inert, at exact final geometry.
  2. The registration column types itself down the center measure — real boot facts as they are measured, monospaced, each with its ms (schema · 42ms · recording lattice · ready · index · 1,318 files). These are actual readiness probes, not theater; on a warm cache the whole column may be 3 lines and 200ms, and that is the correct experience.
  3. The column ends at the signature line: sign in to open the logbook — one passphrase field on the measure, the only chromatic pixel on screen (beam caret). Enter.
  4. Sign-in is recorded (it is a ledger event — say so: signed in · recorded 14:02:07), and the same column continues seamlessly into session boot: the SWEEP backfills right-to-left with the real spectrum (history arriving is the signature moment — the record surfacing), the desk gauges fill, the last conversation’s flow fades in at its kept position. One reveal: the flow and instruments appear in one coordinated frame when the critical batch (schema + conversation + spectrum seed) is complete; everything else fills silently at idle priority with zero layout motion.

10.3 The one-reveal law

After the reveal frame, nothing may mount, move, or resize except from user action or a live event. Guard: cockpit-boot-owner.test.ts — a Playwright boot trace asserts zero layout shifts and zero late mounts between reveal and first interaction; per-read failures render as in-place absence states, never as a layout change (one failing non-critical read can no longer break the shell).

Replaces: the login page, the boot pop-in cascade, per-panel loading states. Honest: every registration line is a measured probe; absence of a subsystem prints as its own line (memory · not available), not as silence. Build: src/cockpit/boot/Registration.svelte, BootColumn.ts (probe orchestration over the existing batch read). Closest prior art: game boot self-tests / aircraft pre-flight checks; structural difference: every line is a real probe with a measured time — it compresses when the system is fast instead of padding when it is slow. Mark: BUILD-NOW (it is the shell’s entry).


11. Interest & interactivity — where the life comes from

[Brief §9. The synthesis engine is the life; motion only ever traces real events.]

  1. The computer speaking (§4) — findings arriving at seams, each earned. A system that visibly derives is interesting for as long as the work is; this is the primary “life” budget.
  2. The bead — a 3px beam-colored pulse that travels the flow’s gutter spine along real causal edges as they are recorded: desk → turn → tool → effect. Implementation: animated offset along the drawn gutter path, compositor-only. It never moves without a corresponding event; when the run stalls, the bead visibly holds (honest stillness beats fake progress).
  3. The sweep ticking — the now edge advancing on real events; the closest thing to a heartbeat, and it is a real one. Under reduced motion, ticks appear without the advance animation.
  4. Live numerals — vertical digit roll (0.8em, 90ms) on real change only; tabular figures so nothing reflows.
  5. Desk physics — channel strips and breakers respond on pointerdown in the same frame (scale 0.994 + press layer); the desk open/close is one 150ms transform. No springs, no overshoot anywhere except the desk snap (one deliberate signature easing).
  6. Hover adds information — full-precision timestamps on sweep hover, value-at-cursor on sparks, provenance on any numeral (LENS-lite footer). Hover never hides an affordance’s existence.
  7. Sound — one opt-in event, off by default: a single short confirmation on run completion, fired only when the tab is unfocused and only on the real run:done event. Justification: it is the one moment a user is legitimately elsewhere; everything ambient is rejected (unbounded sessions make ambient sound a tax). Setting lives in the index (§9.3).
  8. Rejected for fake-motion risk: idle shimmer, breathing gradients, particle ambience, hover parallax, springy tiles — all motion must trace a recorded event or a user gesture (the no-fake-motion law, now a guard: animation utilities accept an event/gesture handle, not a timer).

Mark: bead + sweep tick BUILD-NOW (they ride the spine); the rest lands with its host surface.


12. The visual system — designed from zero: CARBON / LOGBOOK

The GRAPHITE/PAPER discipline survives on its merits — chrome is achromatic, chromatic pixels carry meaning — because it is the same conclusion the dark-cockpit/HPHMI literature reaches independently. Everything else is new: new tokens, new type, new character. The character is instrument glass over a paper logbook: cool carbon surfaces, engraved labels, one electron-beam hue for “live,” and a light theme that is a real paper logbook rather than an inverted dark theme.

New token file: src/cockpit/tokens.css (guard cockpit-tokens-owner.test.ts replaces the old css-token owner — no literal colors/durations in component styles).

WHICH TOKEN FILE DIES — DECIDED HERE, because no document decided it and the resolution existed only in a source comment. This sentence used to read “the old token file dies with the old tree” and named no path, while §13’s deletion list omitted src/styles/ entirely and DESIGN-SPEC-GRAVITY-WELL.md §7 commissioned a full rewrite OF that same file. Three documents, three answers, and both files live at runtime today — src/cockpit/tokens.css through src/cockpit/main.ts, src/styles/tokens.css through a <link> in index.html.

THE DECISION: src/cockpit/tokens.css is the token owner. src/styles/tokens.css is the OLD tree’s and is deleted with it (§13).

It is decided on a measurement rather than a preference, and the measurement is the one nobody had taken — who reads each file:

  declares consumers in src/cockpit/** consumers elsewhere
src/cockpit/tokens.css 208 names the cockpit —
src/styles/tokens.css 230 names zero 225 distinct names read by src/lib/**, 7 by src/App.svelte

The two vocabularies are DISJOINT — the intersection is exactly zero — so there is nothing to collapse, no third file to introduce, and no migration: the old file’s entire readership is the tree §13 already deletes. Neither guard polices the other’s file (css-tokens-owner.test.ts partitions the tree), and both remain correct as written. Until the cutover both files stay, because src/lib/** is still mounted and a token file with live readers is not “old”, it is in use.

What this decision forbids: adding a name to src/styles/tokens.css, and reading one of its names from src/cockpit/**. Either would give the doomed file a reason to survive its own tree, which is how a “temporary” second source of truth becomes permanent.

12.1 Ground (dark default — “carbon”)

--ground-0: #101216;  /* app ground — cool, hue ~250, chroma ≈ 0 */
--ground-1: #15181d;  /* flow bleed rows, sweep housing */
--ground-2: #1b1f25;  /* beats, cells, desk */
--ground-3: #232830;  /* raised: sheets, grammar menu */
--line-1:   #262b33;  /* hairline */
--line-2:   #39404b;  /* structural rule, bezel */
/* light — "logbook": warm paper, real theme, every token re-derived */
--ground-0: #f6f4ef;  --ground-1: #fbfaf7;  --ground-2: #ffffff;
--ground-3: #efece5;  --line-1: #e3dfd6;   --line-2: #c8c2b4;

12.2 Ink, beam, alarm

--ink-1: #e8ebef;  --ink-2: #a6adb8;  --ink-3: #79818d;  --ink-4: #4d545e; /* disabled only */
/* light: #191c20 · #4d545e · #757c86 · #a9aeb6 — all AA on their grounds */

--beam:  #8fd3ff;   /* the ONE live hue — electron-beam blue. light: #0f6fa8 */
--ok:    #5fc78e;   --warn: #d9a84e;   --alarm: #e26a5f;
/* light: #1c7a4c · #8a5c08 · #b5352c */

12.3 Category hues (sweep + beat glyphs)

Event categories get a fresh 8-hue wheel at equal lightness (OKLCH L≈0.72 dark / 0.50 light, chroma 0.10, hues ≥40° apart) mapped from the EVENT_KINDS + ledger category vocabulary by a single table in tokens.css. Never used for chrome; only on sweep bins, beat glyphs, and scope headers. Each ships an --on-* pair.

12.4 Type — engraved instrument, readable logbook

12.5 Shape, space, motion

Mark: BUILD-NOW (tokens are phase 0 of the new tree).


13. Cutover — a fresh tree, and the deletion


14. Build order (ranked) and marks

# What Contents Mark
0 Tokens + shell skeleton tokens.css, Cockpit.svelte, HORIZON/FLOW/SWEEP/DESK geometry, keyboard grammar, one-reveal boot, Registration BUILD-NOW
1 The spine Flow virtualizer, beats (turn/tool/effect/event/check-delta), composer + / grammar, bead, turn seams BUILD-NOW
2 Sweep v1 band + now edge + head/asOf over the streamed window; causal ribbons BUILD-NOW
3 The Switch recency river, reels, honest absences BUILD-NOW
4 Computer v1 client-computable findings (rollup sentence, context projection), ? grammar on existing intelligence blocks; admission controller BUILD-NOW
5 Desk full context strips (read-only until run.compose), breaker rows (read-only until tools.breaker), setting sheet primitive BUILD-NOW render / NEEDS-BACKEND actions
6 Custody effect-beat verbs first (existing git routes), then the room + parcels BUILD-NEXT / NEEDS-BACKEND custody.state
7 Instruments room + monitors uniform cells, no-broken-chart law BUILD-NEXT
8 Settings index + LENS redesign index room, LensCallout BUILD-NEXT
9 Sweep v2 + ARM full-history spectrum, semantic zoom, arm flags/capture NEEDS-BACKEND sweep.spectrum, arm.*, until reads
10 Computer v2 insight.rollup / insight.match / insight.habit findings NEEDS-BACKEND (shapes in §4.9)

Backend needs, consolidated (exact shapes in their sections): run.compose (§3.4) · tools.breaker + next-boundary semantics (§3.5) · insight.rollup / insight.match / insight.habit (§4.9) · custody.state / custody.history (§7.3) · sweep.spectrum + arm.flags + uniform until read param (§6.6). All are ordinary blocks: one declaration each, envelope causality for free.

15. Rejected as novelty-for-novelty’s-sake

16. V2.1 — the corrections, as law

The v2.1 round turned four recurring findings into standing rules. Each rule names its OWNER in the tree — the code that enforces it and the guard that reds a violation — because a law that lives only in a document is a convention (§1: mechanically enforced or it does not exist). Until this section, these laws lived only in code comments; the scout measured that, and this is the fix.

16.1 The mouse-first law

Every actionable keyboard chord has a visible click path, and that path TEACHES the chord. A capability reachable only by chord is invisible to everyone who has not read the grammar; a control that does what a chord does must say so (tooltip derived from the grammar table, platform-true). The converse holds too: a gesture-only capability (drag, middle-click, double-click) states itself in a tooltip on the surface that owns it.

16.2 The rest-visibility floor

A control revealed only by hover does not exist on a device without hover. Every hover-revealed control must also be revealed by focus (keyboard) and be visible at rest under (hover: none) (touch). The floor’s second half — a control that is visible but does not LOOK like a control wears a quiet edge at rest — is a reviewed judgment made owner by owner, deliberately without a guard: an edge scanner would have to crown one CSS spelling as “the affordance” and would manufacture wrong edges (the reasoning, and the remaining un-edged subjects, are recorded in the guard’s own header).

16.3 The no-reload doctrine

“Reload the page” is never the remedy the cockpit prescribes. A deploy under a running page announces itself as one chip and reloads only on the reader’s click; a stale credential re-issues and retries once inside the one fetch choke point; a resume gap loads history in place; a failed room import says “try again” because the next press already is the retry. The one exception is its own proof: the pre-exemption service-worker escape hatch unregisters-then-reloads exactly because that stranded page cannot be freed any other way, and the branch is recorded as removable.

16.4 The rich-rendering defaults

Recorded output renders in the shape the data actually has — and only when the data proves that shape. Files as highlighted code, commands as preserved streams with stderr apart, searches as rows, JSON as one collapsible tree, raster images as pixels inside a byte budget, markdown as prose only for leftover text carrying two distinct block constructs (command stdout is structurally unreachable), bare http(s) URLs in plain streams as links that never change a byte of the text. Everything else falls back to the verbatim string; absence is worded, never faked.

The logbook index

Search the record

Type to search the curated record.

↑↓ move Enter open Esc close