ResearchShared TUI Extraction

03 - Target Repository

03 - Target Repository

Repository shape

tailrocks/termrock
|- Cargo.toml
|- crates/
|  |- termrock/
|  |  `- src/
|  |     |- input/
|  |     |- interaction/
|  |     |- layout/
|  |     |- osc/
|  |     |- runtime/
|  |     |- scroll/
|  |     |- style/
|  |     |- crossterm/       # optional feature
|  |     |- text/
|  |     `- widgets/
|  `- termrock-lookbook/
|     |- src/lib.rs
|     `- src/bin/termrock-lookbook.rs
|- docs/
|  |- content/docs/components/
|  `- public/component-previews/
|- fixtures/renders/
|- examples/{direct,tea,component,flux,buffer_only,crossterm_managed,crossterm_manual}.rs
`- xtask or scripts for docs and render conformance

Start with two packages: the reusable component crate and a lookbook package that exposes the story/render library plus its CLI. Do not create a third CLI crate only to wrap the lookbook. Add a public testing crate only after two consumers require the same TestBackend, event fixtures, or golden-render helpers.

The repository is public and is created empty without an auto-generated seed commit. Filtered donor history stays in a dedicated clone until the neutral standalone head passes the pre-publish history/license/secret scan and local build. The first push publishes only main, with the reviewed head above the inherited history; donor branches, donor tags, and the raw filtered tip are never advertised.

The Fumadocs application lives in the same repository. Component source, stories, generated SVGs, docs pages, and their verification gate therefore advance in one change unit and cannot drift across repositories: one signed direct-main commit during bootstrap, then one normal TermRock PR after the roadmap completes. This atomicity applies to new TermRock commits; imported donor commits remain unmodified provenance.

Public API rules

  1. Pure components. Rendering receives state/data/area/theme and performs no I/O.
  2. Semantic styling. Consumers select a theme and brand data; private palette details are not application APIs.
  3. No product models. Public types never mention agent, job, trace, connection, credential, workspace, or database.
  4. Data-driven actions. Tabs, buttons, hints, menus, and badges accept stable IDs, labels, state, and policy from the consumer.
  5. Complete keyboard path. Mouse interaction may mirror actions, but focus, keyboard activation, and visible hints remain complete.
  6. Stable geometry. Dynamic labels, hover, selection, loading, and errors cannot shift fixed controls unpredictably.
  7. Executor restraint. Widgets and state do not require Tokio, and the base crate has no async-runtime dependency. The executor-neutral base runtime module is optional by use, covers update/view/subscription contracts and the frame driver, and is referenced by no widget; Tokio integration stays consumer-owned.
  8. Controlled dependencies. MSRV and Ratatui/Crossterm support are published and tested.
  9. Two-consumer graduation. Product-local components remain local until a second concrete consumer needs the same neutral contract.
  10. One renderer. Public components target Ratatui directly; do not create a lowest-common-denominator renderer abstraction.
  11. Modern-terminal baseline. Components assume a Ghostty-class truecolor terminal with OSC 8/22/52 support; the library ships no capability-degradation or detection code, while tiny/empty rectangles remain valid panic-free inputs.
  12. Typed escapes only. Widgets never return raw escape bytes; hyperlink regions, pointer shapes, and clipboard writes are typed osc requests with pure encoders, and the consumer owns emission.

Theme and identity

Use semantic tokens rather than a globally hardcoded application palette:

Theme
  surface / elevated_surface / backdrop
  foreground / muted / disabled
  accent / selection / focus
  border / border_focused
  success / warning / danger / info
  link / link_hover

Ship the current phosphor style as Theme::tailrocks_phosphor(). For the initial revision line, Theme::default() and a new builder resolve to that preset, preserving donor fixtures and making the shared Tailrocks visual vocabulary convenient without shipping a fixed header. A consumer provides product name/mark and may select or override semantic tokens. Consistency comes from component behavior and meaning, not every application rendering an identical brand header. The phosphor preset reproduces the donor's exact color values so jackin❯ migration fixtures stay byte-identical; product-specific tokens (Capsule menu states, brand block, debug amber, rain colors) remain jackin❯-local constants layered above the semantic theme.

Runtime contract

The donor's TEA model is valuable:

event -> Message -> pure update -> state + typed effects
                                      |
                                      v
                              consumer effect adapter

The shared project exposes the donor's executor-neutral dirty/redraw state, typed update results, subscriptions with std-channel and closure adapters, component/view traits, and the persistent drive_frame plus one-shot drive_render frame drivers in the base runtime module. The module is optional by use rather than a Cargo feature. It exposes no self-executing effect envelope and does not prescribe one product's root Model, effect executor, persistence, daemon, or Tokio task tree. Standard Ratatui Widget/StatefulWidget rendering remains independent, no widget references runtime, and Tokio integration stays consumer-owned. Modal outcomes and focus ownership remain in interaction, their single canonical module.

The repository includes compile-checked direct, TEA, component-oriented, Flux, buffer-only, manually managed Crossterm, and TermRock-managed Crossterm examples. Every example uses the same public widgets and interaction types while defining its own root state and routing, proving that TermRock supports application patterns and optional convenience instead of prescribing either.

The base termrock crate depends on ratatui-core, following Ratatui's guidance for widget-library authors. Every component, state, logical action, outcome, theme, and buffer-rendering contract works with default-features = false. The optional crossterm feature adds event conversion, CrosstermBackend integration, and a managed terminal-session builder for raw mode, alternate screen, mouse capture, cursor, and restoration. It does not add alternative components or change base behavior. The lookbook enables that feature; a buffer-only consumer does not compile a terminal backend. The library has no Tokio feature.

See 06 - Public API and refactoring for the module graph, widget conventions, theme structure, terminal-session contract, and module-by-module refactoring ledger. See 09 - Component redesign catalog for the Ratatui TEA/component boundary and the replacement contract for every donor component file.

Git-first consumption

crates.io publication is not required before the first consumer migrates. Cargo supports direct Git dependencies by branch or exact revision:

[dependencies]
termrock = { git = "https://github.com/tailrocks/termrock.git", rev = "<full-commit-sha>" }
[dependencies]
termrock = { git = "https://github.com/tailrocks/termrock.git", branch = "feature/new-component" }

During this roadmap's bootstrap, the single jackin❯ implementation PR never uses the branch form. TermRock work is pushed directly to main, and every jackin❯ checkpoint pins the tested full commit through rev, commits Cargo.lock, and records the checkpoint in the PR. The branch form becomes a collaboration pointer only after the roadmap completes: a consumer may then develop a component fix on a trusted Tailrocks branch or fork and exercise it immediately. The exact commit remains the build identity because a later update of a branch dependency can advance it; a branch name is never the security or reproducibility boundary.

The supported post-bootstrap cross-repository loop is:

  1. create the component improvement on a branch in the shared repository or a trusted fork;
  2. test the consumer against that branch while iterating;
  3. pin the tested full commit SHA in the consumer before merging or deploying it;
  4. open the shared-project PR without waiting for a crate release;
  5. after the change lands upstream, repin the consumer to the canonical commit and remove any temporary fork dependency.

This lets a product unblock itself without tracking mutable code. A temporary pin to an unmerged fork commit must name an owner and follow-up; untrusted forks, floating default branches, and automated branch advancement are not accepted dependency policies.

Lookbook model

The shared lookbook owns neutral canonical states for every public component. Consumers own composition stories:

termrock-lookbook
  panel, tabs, list, input, dialogs, status, theme states

jackin conformance
  agents, roles, workspaces, containers, OnePassword, console layouts

Future consumer conformance (outside this roadmap)
  product-owned compositions and effects

The lookbook package exposes one documented CLI with stable conceptual operations:

termrock-lookbook terminal
termrock-lookbook list
termrock-lookbook render --out docs/public/component-previews
termrock-lookbook check --dir docs/public/component-previews

Extraction may preserve the donor flags temporarily, but termrock-lookbook owns the long-term terminal, list, render, and check contract. The harness exercises minimum, normal, and wide terminal sizes; long/wide Unicode; keyboard focus; non-color states; loading/empty/error/disabled variants; and terminal-control sanitization.

Fumadocs component catalog

The documentation site is a product surface of the shared project, not an afterthought. Use Fumadocs' current MDX composition model: MDX pages render through shared components, while generated SVG files are served as static assets and may use an image-preview wrapper for consistent sizing and zoom behavior.

Every public component page includes:

  • purpose and appropriate use;
  • Rust API and focused usage examples;
  • keyboard, focus, mouse, non-color, Unicode, and narrow-terminal behavior;
  • theme tokens and consumer-owned inputs;
  • canonical default, focused, disabled, empty, loading, error, and edge-case SVG states where applicable;
  • the corresponding lookbook story ID and CLI commands for terminal preview and regeneration.

The CLI generates a manifest alongside SVGs so docs navigation and component coverage can be checked mechanically. Generated previews are committed for static hosting and reviewable diffs. CI runs the lookbook check, docs build, type checks, tests, and internal-link checks; a public component without a neutral story, generated preview, and catalog page is incomplete.

The catalog also owns the neutral interaction conventions the components implement — the W3C-style tab pattern, focusability and hover-scroll rules, dialog/backdrop layering, hint discipline, and the navigation model — extracted from jackin❯'s TUI design pages and debranded. The layering page documents how consumers compose the shared primitives; TermRock does not implement a modal stack, parent-chain lifecycle, or application router. Component behavior alone does not make two products consistent, so the conventions governing composition travel with the components. jackin❯ keeps product-specific composition and policy decisions, linking to the external convention pages instead of duplicating them.

When jackin❯ migrates, the external site becomes the canonical component API catalog. jackin keeps only product-specific TUI design decisions, composition guidance, and conformance stories; it removes the generic lookbook CLI, neutral component pages, and duplicate generated SVG assets after parity passes.

Governance

API additions require:

  • a second-consumer case or clearly foundational primitive;
  • neutral naming and no consumer dependency;
  • unit tests plus interactive/deterministic lookbook states;
  • keyboard, focus, Unicode, narrow-terminal, and non-color validation;
  • semver impact and migration notes;
  • dependency/license review.

Consumers pin semver releases or immutable revisions. Branch dependencies are allowed for cross-repository iteration but are replaced by an exact revision before a consumer change becomes durable. The shared project publishes a compatibility matrix and does not coordinate adoption by requiring every Tailrocks repository to follow its default branch or wait for crates.io.

Ratatui/Crossterm upgrades propagate shared-project-first: because public types come from ratatui-core, each Ratatui bump is a breaking termrock change that lands with regenerated fixtures and a migration note, after which jackin❯ repins as the compatibility oracle. Future adopters follow the same policy through their own separately scoped changes. No consumer upgrades Ratatui ahead of the library, and exactly one Ratatui/Crossterm pair is supported per revision line. Issue routing follows reproducibility: defects reproducible with a neutral story belong to the shared repository, product-state defects to the consumer, with cross-links when behavior spans both.

Repository governance has one explicit bootstrap exception: while this roadmap's single jackin❯ PR is open, every new TermRock-authored commit after the recorded imported-history boundary is DCO-signed and buildable, and green checkpoints push directly to main without TermRock PRs. Imported donor commits are preserved provenance rather than retroactively signed standalone builds. After the final tag/checkpoint, TermRock enables its normal protected-main, branch, and pull-request workflow before the roadmap closes.

Repository CI, caching, dependency policy, render/catalog coverage, and release automation are specified in 07 - Repository engineering. The generated extraction inventory and parity gates are specified in 08 - Migration evidence and gates.

On this page