Want the real thing? The live demo replays a real session and lets you drive the real view.
Factory screens
The approved design for flywheel factory (issue #583): a k9s-style terminal UI for a person inspecting the factory by hand and working out what happened and why. Agents keep using the CLI and --json. Most of it is on main now: the layout, navigation and search, the unit's why and timeline, the pulse and metrics dashboards with their drill-downs, the frozen factory, colours and skins, and the actions on a unit. Every screen is drawn at a 110-column terminal with example data; a shipped screen shows the keys and columns the code has (The factory view describes each).
The badge on each screen says what exists today: shipped on main, building in a unit now, planned in the design only.
Navigation mapUnitsUnit · why + timelineUnit · logTreePulseMetricsMetric drill-downFlow chartAndonSearchFrozenFleetHelp
Three levels, one path. Enter goes down a level, Esc goes up, - jumps to the last view, [ ] walk the command history, C-a lists every view and alias. The breadcrumbs at the bottom always show the path. The factory and unit levels are shipped; the fleet level above them (:ctx) is planned.
fleet ──Enter──▶ factory (one ledger) ──Enter──▶ unit ──keys──▶ why · explain · brief · log · checkpoints · findings · events :ctx (planned) :units :workers :lines :andon :events :tree :pulse :metrics :health :learnings :checkpoints :s <text> ▲ ▲ │ └────────── Esc ────────┴──────────────── Esc ──────────────┘
The home screen. The header shows context on the left, the last 24 hours' numbers in the middle and the keys valid here on the right. Every row is drawn in the colour of its state; a row whose cells changed since the last read is drawn bold for two refreshes. Keys never wait: the view redraws from the data it has while the ledger is read in the background.
repo flywheel-main · main throughput 7/24h ▂▃▅▇▅▃▂ <:> view <[ ]> history <N/A/S/C> sort factory running wip 3 </> filter <ctrl-a> views <?> help lead lead-claude-c60c5d · workers 3/4 first-pass 71% <esc> back <enter> why <q> quit health 2m ago andons 1 spend 24h $18.40 <-> last view <l> log <ctrl-e> header flywheel v0.39.0 workers 3/4 busy <ctrl-g> crumbs <ctrl-w> wide <ctrl-r> reload ── Units(all)[6] ↑stage ───────────────────────────────────────────────────────────────────────────────────── TASK STAGE ATT SESSION MODEL STEPS AGE STATE WHY > o572c building r1 fw-o572c claude-opus-5-5 41 9m running building: attempt r1, 41 steps, running for 9m. f1 building r1 fw-f1 claude-opus-5-5 18 3m running building: attempt r1, 18 steps, running for 3m. m1 building r1 fw-m1 claude-opus-5-5 27 12m stalled stalled: attempt r1, no output for 12m (timeout 10m) k2 planned – – – 0 1m waiting blocked: needs k1, which has not landed. k1 passed r1 fw-k1 claude-opus-5-5 83 1h done passed, awaiting landing. o572b landed r1 fw-o572b claude-opus-5-5 128 3h done landed as 154e556 (PR #584). reloaded units
- The WHY column is one plain sentence per unit, built from the same facts
recoveruses, so it is deterministic; the frame cuts it, the unit's detail has it whole. - Colours (dark skin): cyan running, green passed or done, yellow waiting, planned or needs correction, red failed or stalled, magenta suspended or frozen, dim landed.
factory.skinpicksdark,lightornone. - The middle column shows only while the whole key menu fits beside it; a narrow terminal drops it first.
Opening a unit starts with the answer: its state and the reason, then the timeline with every gap of more than five minutes labelled. A single key switches the tab; J opens the first need that has not landed.
repo flywheel-main · main throughput 7/24h ▂▃▅▇▅▃▂ <w> why <c> checkpoints <j/k> scroll factory running wip 3 <d> explain <F> findings <esc> back <y> brief <e> events <f> fullscreen <l> log <J> need <?> help ── Why o526 ───────────────────────────────────────────────────────────────────────────────────────────────── landed as a9a2f09 (PR #535). timeline: 09-02 08:41:07 planned planned brief .flywheel/briefs/o526.txt by lead-claude-c60c5d 09-02 08:42:30 dispatched dispatched r1 to claude (claude-opus-5-5) 09-02 08:43:02 worker_plan worker plan recorded (.flywheel/runs/o526.r1.plan) ·· 15m attempt r1 running 09-02 08:58:40 finished finished r1: rate-limited, step 23, $0.54 ·· 42m waiting for the rate-limit reset at 09:40 UTC 09-02 09:40:12 dispatched dispatched c1 to claude (claude-opus-5-5), resuming the session ·· 51m attempt c1 running 09-02 10:31:55 finished finished c1: stop, step 70, $2.16 09-02 10:33:20 validated validated c1: gates 1-5 pass 09-02 10:41:03 inspected inspected c1: pass by lead-claude-c60c5d ·· 1h12m idle 09-02 11:53:47 landed landed a9a2f09 (PR #535) total 3h12m · touch 1h41m · flow efficiency 53% units o526 why
The unit's events as readable lines, following a running unit as lines arrive. Scrolling up pauses that; G follows again. w wraps long lines, t hides or shows the timestamps, f goes fullscreen (hiding the header and crumbs, as here).
── Log o572c ──────────────────────────────────────────────────────────────────────────────────────────────── 13:05:12 o572c planned brief .flywheel/briefs/o572c.txt by lead-claude-c60c5d (claude-opus-5-5) 13:06:40 o572c dispatched r1 to claude (claude-opus-5-5) 13:06:52 o572c started r1 13:07:31 o572c worker plan recorded (.flywheel/runs/o572c.r1.plan) ▌
Which unit waits on which, like k9s xray: each open unit no other open unit needs is a root, its needs are its children. A landed need is a leaf, a cycle is cut and marked cycle. Enter opens the unit, l its log.
── Tree(all)[8] ───────────────────────────────────────────────────────────────────────────────────────────── UNIT STAGE > k4 planned ├─ k3 planned │ └─ k2 planned │ └─ k1 passed └─ m2 building └─ m1 landed f2 planned └─ f1 building units tree
The factory at a glance over a window (1 24h, 2 7d, 3 30d): six panels, three columns at 110 cells or wider. The arrows or h j k l move the ▶ between panels, and Enter opens the panel's metric. Each trend arrow compares with the previous window of equal length.
── Pulse 7d ───────────────────────────────────────────────────────────────────────────────────────────────── ▶ FLOW QUALITY RELIABILITY landed 31 ▂▃▅▇▆▅▇ ↑ first-pass 71% ↑ andons 9 ▃▁▂▅▂▁▁ ↓ wip 4 ▅▆▇▅▄▆▄ → rework 0.29 ↓ MTTR 18m ↓ lead p50/90 2h40m/6h05m ↓ gate fail 6% ↓ frozen 1h12m ↑ finds/unit 1.8 → paused 3h40m ↓ COST CAPACITY BY MODEL spend $96.10 ▃▄▅▇▆▄▅ ↑ utilization 62% ↑ opus-5-5 ████████████ $2.63 $81 per landed $3.10 ↓ idle 38% ↓ sonnet-5 █████ $1.05 $12 tokens/step 1.9k → haiku-4-5 ██ $0.44 $3.10 units pulse
Every metric as a table row: value, trend and change against the previous window, and its one-line definition from metrics.md. 1 2 3 pick the window, N sorts by metric, / filters, Enter opens the drill-down. The same numbers print with flywheel stats --metrics.
── Metrics 7d(all)[24] ────────────────────────────────────────────────────────────────────────────────────── FAMILY METRIC VALUE TREND Δ PREV DEFINITION flow throughput 31/wk ▂▃▅▇▆▅▇ +24% units landed flow WIP 4 ▅▆▇▅▄▆▄ 0 dispatched…passed, not landed flow lead time p50 2h40m ▆▅▅▄▄▃▃ −35m first planned → landed flow flow efficiency 53% ▄▄▅▅▅▆▅ +4pt touch ÷ cycle quality first-pass yield 71% ▅▅▆▆▇▆▇ +6pt passed on r1, no correction quality rework rate 0.29 ▅▄▄▃▃▃▂ −0.08 corrections per landed unit quality gate fail rate 6% ▂▃▁▂▁▁▁ −2pt failed readings ÷ readings reliability andons 9 ▃▁▂▅▂▁▁ −3 signals + unclean finishes reliability MTTR 18m ▆▅▄▄▃▃▂ −6m andon → cleared cost spend $96.10 ▃▄▅▇▆▄▅ +$11 worker + review cost cost cost / landed $3.10 ▆▅▅▄▄▃▃ −12% spend ÷ landed units capacity utilization 62% ▄▅▇▇▆▅▆ +9pt busy ÷ max_parallel · window units metrics
Every number opens to its chart and then to its evidence: the exact units behind it. The value, trend, change and definition come first, then h the chart (a histogram with p50 and p90 for lead, queue and touch time and MTTR; a control chart with the mean and ±2σ for cycle time; bars for a breakdown) or u the units, worst first. Enter on a unit opens its why and timeline; Esc comes back to the same row. Here, lead time: its chart, then its units.
── Metric lead time 7d ────────────────────────────────────────────────────────────────────────────────────── lead time 2h40m ↓ −35m · first planned → landed <1h ██████ 6 1-2h ██████████ 10 2-4h ████████ 8 ▲ p50 2h40m 4-8h █████ 5 ▲ p90 6h05m >8h ██ 2 units pulse lead time
── Metric lead time 7d ────────────────────────────────────────────────────────────────────────────────────── lead time 2h40m ↓ −35m · first planned → landed TASK VALUE GROUP > o457c lead 9h12m landed d5 lead 8h40m landed o572a lead 5h55m landed units pulse lead time units
The wip drill-down draws the work in progress over the window as a flow (StackedFlow). A band that widens is work piling up. The chart primitive stacks several series; the drill-down draws the one wip series today, and a band per stage is the design.
── Metric wip 7d ──────────────────────────────────────────────────────────────────────────────────────────── wip 4 → · units dispatched, running, finished or passed at the window's end 6 ┤ ████ ┤ ████ ██████████ ████ ┤ ██████████████████████████████████ ████████████ ┤ ███████████████████████████████████████████████████████████████ 0 └──────────────────────────────────────────────────────────────── █ wip
The units that stopped the line, each row in the colour of its state. Enter opens the unit's why, l its log. A severity and a next-action column are the design, not built.
── Andon(all)[3] ──────────────────────────────────────────────────────────────────────────────────────────── TASK AGE STATE > o581 12m stalled d5 31m failed o577 2h capped 48k units andon
Hunting a cause: one case-insensitive search across the ledger, the run logs, the reports and the briefs, one row per matching line with about 40 characters each side. Enter on an event opens the unit's log at the match; on any other result, the unit's explain tab. It stops at 500 results.
── Search "could not resolve host"(all)[3] ────────────────────────────────────────────────────────────────── SOURCE TASK ATTEMPT LINE EXCERPT > event o572a – 4812 …git push failed (rc=128): fatal: Could not resolve host: github.com event o572d – 4907 …git fetch failed (rc=128): fatal: Could not resolve host: github… log m1 r1 – …go: downloading … could not resolve host proxy.golang.org… units search
When every model's tokens run out, the factory freezes itself (reason tokens-exhausted) and thaws when they return, resuming each stopped unit in its own session. flywheel suspend and flywheel resume do the same by hand (see Freeze and resume). The header says FROZEN since and until when, one line per paused model, and each suspended unit says why.
repo flywheel-main · main <:> view <enter> why <?> help factory FROZEN since 13:35 until 15:00 by lead-claude-c60c5d: tokens-exhausted </> filter <l> log <q> quit paused claude-opus-5-5 until 15:00 <esc> back <N/A/S/C> sort paused claude-sonnet-5 until 15:20 lead lead-claude-c60c5d · workers 0/4 · landed today 7 · $18.40 ── Units(all)[4] ──────────────────────────────────────────────────────────────────────────────────────────── TASK STAGE ATT SESSION MODEL STEPS AGE STATE WHY o572c finished r1 fw-o572c claude-opus-5-5 41 25m suspended suspended: frozen by suspend at 13:35 UTC; it thaws at 15:00 UTC. f1 finished r1 fw-f1 claude-opus-5-5 18 25m suspended suspended: frozen by suspend at 13:35 UTC; it thaws at 15:00 UTC. m1 finished r1 fw-m1 claude-opus-5-5 27 25m suspended suspended: frozen by suspend at 13:35 UTC; it thaws at 15:00 UTC. k2 planned – – – 0 2h waiting queued: its needs are met, but the factory is frozen by suspend at 13:35… units
Every factory on the machine, like k9s contexts. This screen is in flywheel factory now: :ctx lists every factory in the fleet, Enter switches the whole view to it, and --ctx <name> starts there. The fleet is also on the CLI: flywheel fleet add, list and status keep a registry of factory roots, find every ledger under them (worktrees included) and print one merged table with NAME, KIND, EVENTS, RUNNING, PASSED, FINISHED, ANDON, STATE, HEALTH and LAST (see Fleet). The fleet learnings queue and fleet watch are shipped too.
── Fleet[5] ───────────────────────────────────────────────────────────────────────────────────────────────── NAME KIND RUNNING PASSED LANDED/7d FIRST-PASS ANDON STATE HEALTH flywheel-main root 3 1 31 71% 1 running 2m shop-main2 root 2 0 18 64% 2 running 4m shop-perf-394 root 0 0 9 78% 0 FROZEN until 15:00 6m shop root 0 0 0 – 0 idle none badge root 1 0 4 50% 0 paused: opus until 15:00 9m fleet registry ~/.config/flywheel/fleet.json
Every key and every view in one place: ? shows the keys (one scrolling list in the view, grouped here), C-a lists every view and alias.
── Help ───────────────────────────────────────────────────────────────────────────────────────────────────── MOVE VIEWS FILTER · SORT UNIT j k down / up :u units :w workers /re regex w why + timeline g G top / bottom :l lines :a andon /!re inverse d explain PgUp/Dn page :e events :t tree /-f x fuzzy y brief Enter open :p pulse :m metrics N sort by name l log (w wrap t time) Esc back :h health :lr learnings A sort by age c checkpoints - last view :c checkpoints S sort by stage F findings e events [ ] history :s x search :q quit C sort by cost J first unmet need METRICS SCREEN f fullscreen 1 2 3 24h / 7d / 30d C-e header C-g crumbs G last line / follow h j k l pulse panel C-w wide C-r reload h u chart / units ACTIONS (each asks y/N; off with --readonly) v validate i inspect r resume x withdraw space mark Z suspend R resume factory :result output .flywheel/hotkeys.json
Example data. Build order on #583, shipped: k1 layout, k2 navigation and search, k3 unit detail, m1 metrics engine (flywheel stats --metrics), m2 charts, k4 pulse and metrics, k6 feel (instant keys, colours, skins), the freeze and flywheel schedule, flywheel fleet add, list and status, f2 the fleet learnings queue, f3 fleet watch, f4 the fleet screen (:ctx), and k5 actions, marks, --readonly and hotkeys.