# TUI Rebuild — Master Sequence

Context: the Go→Rust parity migration was terminated 2026-07-02 (post-mortem: docs/tmp/rust-tui-continuation-assessment.md). The parity apparatus was removed (−409K LOC, squashed into the single "rust tui foundation" commit). The Go TUI is condemned; the Rust client becomes THE client, built against specs, not against Go output. Keeper code: client-contracts, rpc-client, tui-core (all green with tests), tui-app src, tui-bin live path. Known rewrite targets still standing: the 5-layer runtime loop onion in tui-bin, the 649-type message layer + 9.5K reducer.rs in tui-app. Known gating defect: blocking subscription I/O starves the single work loop → first chat turn hangs (issue #341 class).

Operator decisions to date: spec-driven rebuild; black-box PTY harness is the acceptance mechanism; agents run QA themselves, operator QAs only at dogfood threshold + taste/edge-case passes; Kent workflow orchestration replaces manual babysitting; tasks strictly ordered (cross-task dependency machinery NOT built yet — sequence tasks manually until it exists).

RATIFIED (Nikita, 2026-07-02) — dual render architecture, explicitly operator-wanted (not an agent invention): the ongoing/native-scrollback surface uses crossterm direct output (append-only normal buffer, no framework composition); ALL other surfaces are bounded alt-screen surfaces composed through Ratatui (typed layout, styled spans, chrome, focus affordances) for polished UX. Phase 1 must encode this split in the spec suite — the branch-era spec lines stating it were dropped in the remote-wins rebase, so today AGENTS.md and the tui-design skill are the only carriers.

RATIFIED (Nikita, 2026-07-02) — UX divergence policy: the new TUI MAY diverge from current Go UX, but ONLY in spec-silent zones. Anything a ratified spec specifies is followed to the letter — ironclad, no improve-while-implementing, no interpretation drift. Consequences: (1) Go UX is NOT the default oracle anywhere; (2) spec authors may propose divergent-from-Go designs freely — divergence needs no per-case approval beyond normal spec ratification; (3) once ratified, spec text binds exactly; wanting different behavior means changing the spec with operator ratification first, never bending the implementation.

## Phase 0 — Base hygiene (mechanical, cheap agents)
- [x] Rebase squashed branch onto origin/main — done 2026-07-02, commit e346825c; remote authoritative for all Go/specs/docs (all branch-era non-Rust edits dropped)
- [ ] Decide fate of docs/tmp post-mortem reports in the commit before any push (operator: keep public vs local-only)
- [ ] Optional: `git branch -D rust-harness-pre-squash-backup` once operator is confident

## Phase 1 — Spec suite (strong model + operator review; the real oracle)
- [x] Inventory existing docs/dev/specs — done 2026-07-02, verified report at docs/tmp/tui-spec-inventory.md. Verdicts: ongoing transcript + steering queue covered; onboarding fully unspecified; 10 families partial (flow intent locked, key/overlay/edge semantics live only in Go = free-design zones). Family-list correction: no /help, /auth, /model slash commands exist (help = F1/? hotkey overlay; auth = /login /logout; model has no slash surface).
- RATIFIED (Nikita, 2026-07-02) goal rulings: (1) goal-while-busy — core-runtime-tools spec is RIGHT: `/goal <objective>` allowed while the turn runs, steered as usual; Go TUI + slash-commands.md user docs are drift; Rust implements the spec, user docs fixed when the conforming client ships (Go TUI is frozen, not fixed). (2) workflow goals — user `/goal` control rejected in workflow task sessions; agents may set themselves goals and complete them; both specs amended to say exactly this. (3) Spec authoring order: dogfood-first — startup/attach+auth+pickers → chat core (composer+queue edges) → status line → daily slash overlays (/status /goal /wt /ps, rollback) → onboarding → errors/resize/polish.
- [ ] Author one spec per surface/flow family, behavior-level (layout roles, key semantics, state transitions, error surfacing — not pixel/char assertions). Families: startup/attach + auth bootstrap [DONE — docs/dev/specs/tui-startup.md installed 2026-07-02], onboarding, session/project/workspace pickers [folded into tui-startup.md], ongoing transcript [already covered by ongoing-scrollback-buffer.md], detail pager, composer/input (editor, history, path-reference autocomplete, clipboard image paste) [DONE — docs/dev/specs/tui-chat-core.md installed 2026-07-02, incl. queue/interrupt UX], steering queue + busy interrupts [covered per inventory + tui-chat-core], ask/approval prompts, slash overlays (/status /goal /worktree /ps /rollback /compact; note: no /help //auth //model commands exist — help is a hotkey overlay, auth is /login //logout), background process management, status line, error/notice surfacing, resize/degraded-terminal behavior.
- Batch-6 DONE — docs/dev/specs/tui-terminal-environment.md installed 2026-07-03. Rulings: too-small guard = blank frame below 40×10, app-global at renderer/navstack level (per-surface size checks = architecture violation; Go breaks below min = drift); per-page floor = vertical scroll + infinite-scroll pagination + horizontal wrap; theme auto-detect at startup only; palette-role-only colors; no mouse capture anywhere. ALL SIX PLANNED BATCHES DONE. Families still unspecced: detail pager, ask/approval prompts.
- Batch-5 DONE — docs/dev/specs/tui-onboarding.md installed 2026-07-03 (was fully unspecified). Rulings: Esc = back-one-step (cancel only on first step; Go's cancel-everything = drift); SERVER-SIDE FINALIZE — server writes config.toml + executes imports, client only submits choices, model/provider capabilities server-supplied (needs new server API; Go client-side write = drift). Remaining: batch 6 errors/resize/polish, detail pager, ask/approval prompts.
- Batch-4 DONE — docs/dev/specs/tui-slash-overlays.md installed 2026-07-03 (/status /goal /ps /worktree UX + rollback picker + shared overlay conventions). Rulings: /ps refresh = timer + push only, no manual-refresh key (Go `r` = drift; worktree `r` kept, load-bearing); /status drops "Server: owned by this CLI"; Built-ins list in tui-transcript amended (+/login /questions /goal /worktree+/wt). Remaining families: onboarding (batch 5, fully unspecified), errors/resize/polish (batch 6), detail pager, ask/approval prompts.
- Batch-3 DONE — docs/dev/specs/tui-status-line.md installed 2026-07-03. Rulings: operator-supplied 10-rung space-priority ladder (Go order = drift); `editing` = spinner-word label outranking `goal`; `interrupted` = ordinary notice, no marker concept; transient notices briefly overtake the persisted disconnect notice (Go reversed = drift); notice kinds canonicalized to error/warning/info/success; NO native-write-failure notice (Go `nativeLiveAreaError` = temp debug hack, owner ongoing-scrollback-buffer :: Errors); NO `server owned` segment (embedded-server relic); tui-transcript Rendering line amended per ruling.
- Batch-2 rulings (2026-07-02, in tui-chat-core.md): Ctrl+J newline fallback, codex is the Shift+Enter reference (Go recognition broken = drift); server-supplied history capped at 100; queued pane shows queued above steering; busy Ctrl+C drains both queues into the input (no other removal UI); Esc-Esc arms rollback; clipboard image format OS-specific (tui-transcript :: Input And Queueing line amended per ruling); macOS Ctrl+U delete-line divergence kept.
- Batch-1 rulings with cross-family reach (2026-07-02): TUI embeds NO server (pure client like `kent run`; preflight failure = exit with error) — Go embedded fallback is documented drift; ONE global centralized connection-loss handler → persisted status line, per-surface connection handling banned (binds status-line family); navigation = explicit stack with owned lifecycles (Compose/Decompose-style) in the pure model layer; server supplies UI pre-fills (project name), client never derives from FS; terminal restore is best-effort (ongoing normal-buffer output permanent by design); last-saved auth choice wins, no env-vs-saved prompt.
- [x] Operator ratifies each spec — ALL FAMILIES SPECCED as of 2026-07-03. Batch-7 (final): tui-ask-prompts.md installed (ruling: prompt input never freezes during answer delivery — Go's answerPending freeze = drift; no digit-jump); detail keys + windowed detail transcript added to tui-transcript :: Detail Mode. Phase 1 COMPLETE: tui-startup, tui-chat-core, tui-status-line, tui-slash-overlays, tui-onboarding, tui-terminal-environment, tui-ask-prompts + pre-existing ongoing-scrollback-buffer/tui-transcript coverage. Spec suite uncommitted — awaiting operator commit decision (also still uncommitted: batch 1-2 era spec edits, goal rulings in workflow-orchestration + core-runtime-tools).

## Phase 2 — PTY QA harness (first engineering deliverable; parallel with Phase 1)
- [ ] Single command UX: `./scripts/tui-qa.sh <scenario>` (or kent-integrated equivalent). Builds on .kent/qa/qa-harness.sh (HOME-isolated server, omlx models).
- [ ] Mechanics: spawn isolated server → run tui-bin in a PTY (tmux or portable-pty) → scripted key sequences per scenario → capture ANSI screens + final transcript → assert spec-level expectations (structure/behavior, not literal styled bytes) → write artifacts dir (screens, keys, server log) per run.
- [ ] Scenario definitions are data (one file per flow), not per-scenario harness code. No production plumbing: the harness drives only the real binary.
- [ ] Certify the harness against the CURRENT binary's one working area (startup selection) to prove the loop before depending on it.

RATIFIED (Nikita, 2026-07-03) — pre-fanout platform sequence: layers A–E below replace the old thin Phases 3–4. Each layer is its own planning-workflow cycle (plan doc, red/green TDD, review). A is serial and carries the kill-gate; B/C are pure-client and proceed without a server while the harness matures; D waits on A (connection handling on a starving loop is untestable); fan-out (flow families) starts only after E.

RULED (Nikita, 2026-07-04) — nuke, don't operate: tui-app + tui-bin deleted whole-crate on rust-harness (~100K LOC, zero crate-level tests, sentinel/string-ID violations throughout; "cut anything you don't like, or what smells, idgaf"; quality bar: "Rust tui will be impeccable. Code is dirt cheap, architecture and product quality are priceless."). Keepers standing: client-contracts, rpc-client, test-support, manifest-check. No binary exists until Platform A ships one; BUI-181 certifies its harness against its own pre-nuke branch. rust-harness merges to main via PR so Kent workflow tasks (main-based only) can drive everything from Platform A onward. Demolition record: docs/dev/rust/tui-demolition-plan.md.

RULED (Nikita, 2026-07-04, second pass) — tui-core nuked whole-crate too. Trigger: transcript module encoded port-era assumptions (hardcoded 24-char divider constant next to a width-parameterized divider fn = dual source of truth; string-typed group identity; port-shaped 4-way rendering split) and its test suite was literal-output pinning (banned class). Nikita chose "nuke all of tui-core" over keeping input/: the editor + unicode width-cursor semantics + ratified Go golden die with it; Platform C rebuilds the text-editing core from scratch. Consequences: syntect/pulldown-cmark/unicode-* deps pruned; all four RUSTSEC deny.toml ignores + dependency_policy.rs chain guards removed (syntect left the tree); size-guard baseline down to 2 rows. OPEN: docs/dev/specs/tui-chat-core.md still names the deleted tui-core width-cursor fixture as the cluster-behavior authority — spec edit needs Nikita's explicit wording; Platform C must recreate an equivalent executable fixture as the authority the spec points to.

RE-RATIFIED (Nikita, 2026-07-04, PM-mode grilling) — infra-first resequence: no product surface exists until the platform is done ("build out the infrastructure first, even if we delay dogfoodability"). New order: A (loop) → D pulled forward (network/errors are headless, no UI dependency) → B (terminal) → C (shell + design system) → E → families, with the SESSION PICKER/startup as the first family and chat as a later family on the proven platform ("50+% of tui's code is specific to the chat loop; all other surfaces are trivial but build upon the scaffolding"). The one-time 15-minute kill-gate ceremony is dead: replaced by a small continuously-running loop-soak harness test that lands with A and runs in the tui suite forever (Nikita: one-time cert goes stale, "further edits will introduce regressions"; lead-agent counter, accepted: unit tests cannot catch emergent loop starvation, so the pressure test must exist from A and be continuous). Long omlx unattended runs move to per-family dogfood certification.

## Phase 3 — Platform A: loop viability (serial; lean well-designed modules + unit tests + the continuous soak)
- [ ] Build the runtime loop + effect runtime from first principles (the old onion is deleted, not a reference): subscription I/O lives off the reducer/work loop behind channels; structured concurrency only (no detached tasks); one composition, no layering onion.
- [ ] Generalize the result as the platform effect runtime: typed channel contract between the sync reducer and I/O workers, cancellation, and the single-flight frozen-mutation primitive (owner: tui-slash-overlays :: shared conventions) that every overlay RPC will use.
- [ ] Recreate the tui-bin crate as a walking-skeleton binary only (connects, subscribes, renders streamed events as raw ongoing lines; NO composer, NO product transcript, NO chat surface — nothing an agent could mistake for the product); restore build.sh's TUI binary artifact output.
- [ ] Gate: continuous loop-soak harness test (~2 min, in the tui suite permanently): harness drives the skeleton against a server streaming events at realistic timing; input responsiveness stays bounded; no hang, no crash. Every later phase and family keeps passing it.

## Phase 4 — Platform D: server connectivity (pulled forward 2026-07-04; headless, needs only Platform A's loop)
- [ ] RPC client hardening + protocol-version gate.
- [ ] Connection lifecycle: ONE global connection-loss handler → persisted notice (per-surface handling banned), reconnect.
- [ ] Streaming projection: subscription → clientui DTO → append-only writer; exactly-once seq/rehydration contract implemented client-side.
- [ ] Error taxonomy + surfacing policy (moved here from the app-shell layer: typed-error-at-crate-boundary → fatal exit / persisted notice / transient notice / inline field error; notice rendering itself stays in Platform C).
- [ ] Pagination adapter: infinite-scroll bounded windows over the RPC paging contract (per-page floor, edge paging, windowed detail transcript).
- [ ] Launch paths + startup preflight validation (server reachable, protocol version, auth gate). Client-side config is near-nil by the thin-client rulings — endpoint/launch-path resolution + CLI args only; a client config reader beyond that = drift (operator-confirmed 2026-07-03).
- [ ] Contract reconciliation: KENT-192 codegen decision lands here at the latest; the 14 deferred codex drift findings on PR #501 (incl. UUID-typed IDs) are owned by this phase.

## Phase 5 — Platform B: terminal substrate (no server dependency; harness-certifiable standalone)
- [ ] Terminal driver, single owner: raw mode; normal-buffer↔alt-screen transitions (dual render architecture); DEC private-mode discipline (?1007 off, no mouse capture); bell; best-effort restore on exit; panic handler restores the terminal BEFORE printing the report; suspend/resume around external processes ($VISUAL/$EDITOR fallback, edit-detach, /ps `o`).
- [ ] Input decoding: typed key events incl. Shift+Enter recognition (codex = reference impl; keyboard-protocol negotiation + Ctrl+J fallback), bracketed paste, clipboard text + image, multi-key timing (Esc-Esc 500ms window).
- [ ] Timer/scheduler service: notice expiry, spinner ticks, 1s resize-rehydration debounce, Esc-Esc window — one typed facility, no per-feature timer arms.
- [ ] Theme tokens: palette roles only + background auto-detection at startup (owner: tui-terminal-environment).

## Phase 6 — Platform C: app shell + design system (pure model; testable without server)
- [ ] Keymap/semantic-action layer — subsumes the old message-layer-consolidation phase: context-dependent key → typed action, families register bindings; per-key-per-state Dispatch/Message pairs die, reducer.rs + 649-type message layer shrink, file-size guard baseline shrinks with them. Rationale unchanged: every family touches this layer; consolidating first makes parallel family work merge-clean.
- [ ] Navigation stack + owned lifecycles (Compose/Decompose-style) + app-global 40×10 too-small guard at renderer/navstack level (per-surface size checks = architecture violation).
- [ ] ui-kit widgets: lists w/ ID-stable selection, dialogs/confirms w/ focus cycling, scroll containers, the 10-rung priority-space layout engine (status ladder), text-input view.
- [ ] Shared text-editing core (pure model; widgets only draw — behavior-owning widgets banned): rebuilt from scratch (the old tui-core input/editor + unicode tables + width-cursor golden were nuked 2026-07-04); recreate a grapheme/width/cursor executable fixture as the authority tui-chat-core.md points to, editing keys, history integration, native-cursor position. Consumers: composer, onboarding text steps, ask freeform, goal editor, worktree name entry.
- [ ] Notice service: kinds error/warning/info/success, transient-overtakes-persisted, replace-vs-queue, expiry (owner: tui-status-line). Status line renders it; every family posts into it.
- [ ] Notice-kind rendering consumes the Platform D error taxonomy (taxonomy owned there; presentation here).
- [ ] Test-support crate: key-driving harness for the pure model + typed render-model assertions (structure/behavior, never literal styled bytes).

## Phase 7 — Platform E: fan-out enablers
- [ ] Slash-command registry: parse, complete, dispatch (the overlays themselves are Phase 8 families).
- [ ] Diagnostics: client logging to file (never the TTY), panic report path — prerequisite for debuggable unattended cert runs.
- [ ] Kent workflow graph + scenario-definition data format (see workflow section below; may be pulled earlier alongside BUI-181 if convenient).

## Phase 8 — Flow families (parallelizable; Kent workflow-orchestrated)
- [ ] One Kent task per family, created in dependency order (manually sequenced until task dependencies exist). Each runs the workflow below. Family order (re-ratified 2026-07-04): SESSION PICKER/startup FIRST (exercises the full bounded-surface platform stack with trivial domain logic), then chat/composer core on the proven platform, then status line → detail pager → slash overlays → processes/rollback/worktree → onboarding/auth → polish; exact tail order grilled at ticket time.
- [ ] Per-family dogfood certification = the long unattended omlx-backed run (for chat: turns render, keys respond, no hang — the old kill-gate scenario lives here now), artifacts attached.
- [ ] Dogfood threshold = launcher/attach + chat + status + the operator's daily slash flows certified → operator switches daily usage to the Rust client; Go TUI deletion becomes a scheduled phase.

## Kent workflow graph (author in Phase 2, alongside harness)
Nodes: backlog/start → implement (agent role: coder; completion: shell_command) → qa (agent role: qa, new_session — fresh eyes, no implementer bias) → review (code_review role, new_session) → done (terminal). 
Edges/transitions:
- start→implement: prompt carries family name + spec path + plan path.
- implement→qa, transition "qa" with params: `flows_changed`, `harness_scenarios` (scenario ids to run), `plan_file_path`. Transition description: "Implementation complete AND you ran the harness scenarios yourself successfully."
- qa→implement, transition "qa_failed" with param `findings` (context: continue_session on implement side is not possible across roles — use compact_and_continue_session).
- qa→review, transition "qa_passed" with param `artifact_dir` (harness evidence location).
- review→implement, transition "needs_changes" with `findings`; review→done, transition "approve".
- requires-approval: ONLY on qa→review for the first task of each phase (operator spot-checks artifacts), relaxed later if trust holds.
Completion mode: shell_command everywhere (agents have shell; avoids cache invalidation on continue transitions).
Validation: `kent workflow validate --mode execution` before first task.

## Crate map (RATIFIED Nikita 2026-07-04 — feature crates + core crates; each crate is created BY its phase, never pre-stubbed)
- `kent-runtime` (Phase A): the FlowMVI-analog core — store/reducer contract, typed intents/effects, bounded channels, structured side-effect execution, single-flight primitive. Zero product types, zero terminal deps (compiler-enforced via its dependency list).
- `kent-tui` (Phase A): the `:app` — composition root + the one binary target; walking skeleton first.
- Threading RATIFIED: Kotlin-dispatcher shape. Main dispatcher = main thread loop (input → sync reducer step → render; reducer lives ON main — two-role model, not three threads); IO dispatcher = tokio runtime on worker thread(s) in std::thread::scope, current_thread first, pool upgrade is a builder one-liner. Reducer has no runtime handle in scope — blocking from it is structurally impossible. AGENTS.md "main thread is render and input only" wording to be amended to its intent ("no blocking/I-O on main") — needs Nikita's sign-off text.
- `kent-network` (Phase D): hardened transport + connection lifecycle + reconnect; absorbs rpc-client. `client-contracts` = domain-core until KENT-192 codegen replaces it.
- `kent-terminal` (Phase B): terminal driver, input decoding, timers; ALSO owns grapheme/display-width metrics + generated unicode tables (renderer needs cell-width as much as the editor; mislocated in old input module).
- `kent-navigation`, `kent-uikit` (Phase C): navstack+lifecycles; design system + widgets + theme. Text-EDITING behavior (cursor/selection/word-nav/kill-buffer/history) = pure-model module INSIDE kent-uikit; graduates to own crate only if crate-worthy size or non-UI dependent appears (Nikita: no crate unless ~2K+ LOC).
- `kent-feature-*` (Phase 8 families): one crate per feature, pure model + render projection; app composes.
- Naming: `kent-` prefix mandatory (flat crates.io namespace collision guard + grep-ability).
- Build-speed stance: small crates IMPROVE incremental builds (crate = incremental+parallelism unit); keep inter-crate APIs concrete-typed to avoid cross-crate monomorphization bloat.

## Standing constraints for every phase
- Spec silent → stop and ask; never mine Go code for intent.
- No new tracking artifacts/manifests; progress = certified-flow list only.
- Guards green (lint_policy incl. 700-line cap); extend guards, don't write prose rules.
- Docs (docs/) updated when user-facing behavior lands, per repo policy.
