Skip to main content

tui-verify

Verifies that the design-data TUI (sdk/tui) renders correctly and behaves as expected by driving it with the three-tier verification strategy: (1) deterministic in-process buffer assertions, (2) live rmux + asciinema screen capture, and (3) visual asciinema/agg or Ghostty + screencapture for pixel-level fidelity. Use when asked to verify, test, or confirm the design-data TUI renders or behaves correctly, check TUI layout at a specific window size, capture TUI screen contents or screenshots, or assert that a TUI change looks right.

Source facts

Repository
adobe/spectrum-design-data
Last source activity
October 12, 2026 at 22:07
Detected SKILL.md language
English
Stars
156
Forks
36

Install options

The review-first prompt is selected by default. You can switch to a direct command or download a local copy.

Review the source files

Read SKILL.md and any companion files shown by SkillsMP before deciding whether to install.

File Explorer
3 files

Showing SKILL.md

SKILL.md
Source instructions · Read-only preview
name
tui-verify
description
Verifies that the design-data TUI (sdk/tui) renders correctly and behaves as expected by driving it with the three-tier verification strategy: (1) deterministic in-process buffer assertions, (2) live rmux + asciinema screen capture, and (3) visual asciinema/agg or Ghostty + screencapture for pixel-level fidelity. Use when asked to verify, test, or confirm the design-data TUI renders or behaves correctly, check TUI layout at a specific window size, capture TUI screen contents or screenshots, or assert that a TUI change looks right.
license
Apache-2.0
compatibility
Designed for Claude Code in the spectrum-design-data repo. Tier 1 requires Rust/Cargo and the design-data CLI built (cargo build -p design-data-cli). Tier 2 requires rmux 0.3.x on PATH. Tier 3 (asciinema) requires asciinema 3.x and agg on PATH. Tier 3 (Ghostty) requires macOS, Ghostty 1.3.0+, Screen Recording TCC permission, and GetWindowID on PATH.
# TUI verification (3-tier strategy) The `design-data` TUI (`sdk/tui`) has a purpose-built verification stack. Choose the **lowest** tier that answers your question — Tier 1 is fastest and most exact, Tier 3 is the only one that catches visual/glyph issues. ``` Tier 1 render_to_buffer / TestBackend ← deterministic, no terminal, CI backbone Tier 2 rmux + capture-pane ← real binary, live screen text Tier 3 asciinema + agg / Ghostty ← pixel image for glyph/colour verification ``` ## Prerequisites * **All tiers**: `cargo build -p design-data-cli --release` (or `moon run :build`) so the `design-data` binary is on PATH / in `sdk/target/release/`. * **Tier 2**: `rmux` 0.3.x on PATH (`brew install rmux`). * **Tier 3 (asciinema)**: `asciinema` 3.x + `agg` on PATH (`brew install asciinema agg`). * **Tier 3 (Ghostty)**: Ghostty 1.3.0+, macOS Screen Recording permission granted to the controlling terminal, and `GetWindowID` (`brew install smokris/getwindowid/getwindowid`). *** ## 1. Tier 1 — in-process buffer assertions (default) `render_to_buffer(&mut model, w, h)` builds a ratatui `TestBackend` at an exact size, draws once, and returns the `Buffer` for cell-level assertions. No terminal emulator. All 200+ existing tests use this pattern. **Run the full suite** (always start here): ```bash cargo test -p design-data-tui # or: moon run :test ``` **Add a targeted assertion** — follow the patterns in [`references/tier1-test-api.md`](references/tier1-test-api.md) (source: `sdk/tui/tests/render.rs`, `sdk/tui/tests/common/mod.rs`): ```rust use common::{render_to_buffer, make_graph_with_tokens, update_ctx}; #[test] fn my_new_feature_renders_label() { let graph = make_graph_with_tokens(&["accent-color"]); let ctx = update_ctx(&graph); let mut model = Model::new(); update(&mut model, Message::PaletteSubmit("query property=accent-color".into()), &ctx); let buf = render_to_buffer(&mut model, 80, 24); // assert specific cell or scan rows: assert_eq!(buf.cell((0, 0)).unwrap().symbol(), "▶"); } ``` **Layout at a specific size** — the committed breakpoints are documented in [`references/tier1-test-api.md`](references/tier1-test-api.md#layout-breakpoints-sdktuitestslayoutrs) (source: `sdk/tui/tests/layout.rs`): | Size | What to check | | ---------- | ------------------------------------------------------------------------ | | `120 × 36` | Spectrum/auto-demo target — logo + all panels visible | | `80 × 24` | Standard small terminal — no overflow, table readable | | `80 × 33` | Logo present (content area = 31 rows, the exact threshold) | | `80 × 32` | Logo absent — name/hint/prompt/commands still render (content = 30 rows) | | `10 × 5` | Narrow — should not panic | | `1 × 33` | Very narrow at logo threshold height — should not panic | *** ## 2. Tier 2 — live real binary via rmux (ad-hoc verification) Use when Tier 1 isn't enough: mouse capture, truecolor Spectrum theme, a real TTY interaction the in-process harness can't simulate. **Generic runner — simplest path:** ```bash bash tools/demo/auto/verify-tui.sh \ --dataset packages/design-data \ --steps path/to/steps.txt ``` Step file format (one directive per line): ``` # Comments are ignored send : type query property=accent-color send Enter wait accent-color expect accent-color refute Error ``` Directives: `send KEY` (rmux key name), `type TEXT` (typed with 60 ms animation delay), `literal TEXT` (send text with no key interpretation, no animation), `wait REGEX` (block until pattern appears, 120 s timeout), `quiet [N]` (wait until pane stable for N polls), `expect REGEX` (assert present), `refute REGEX` (assert absent), `capture` (print current screen to stdout), `sleep N` (sleep N seconds). The runner prints the pane contents after each `capture` or `expect`/`refute` — read those to visually confirm layout. Exit code is 0 only when all assertions pass. **Escape hatch — source `rmux-drive.sh` directly for a custom one-off:** ```bash source tools/demo/auto/lib/rmux-drive.sh start_session dd-verify "design-data packages/design-data --theme spectrum --no-resume-wizard" wait_for dd-verify "commands" 30 # wait for home screen send_literal dd-verify ":" type_keys dd-verify "query property=accent-color" send_keys dd-verify "Enter" wait_for dd-verify "accent-color" assert_contains dd-verify "accent-color" "token row present" capture dd-verify # print for agent to read print_summary verify end_session dd-verify ``` See [`references/tier2-rmux-api.md`](references/tier2-rmux-api.md) for the full helper reference (source: `tools/demo/auto/lib/rmux-drive.sh`). **Moon task** (runs locally, not CI — rmux needs a real PTY): ```bash moon run demo:tui-verify -- --dataset packages/design-data --steps my-steps.txt ``` *** ## 3. Tier 3 — visual / pixel capture Use only when Tier 1 can't answer the question: glyph widths, wide-char alignment, Spectrum truecolor swatch colours, box-drawing rendering, font fallback. **asciinema + agg (deterministic GIF — use this first):** Record a flow inside the rmux pane (same way `auto-demo.sh` does): ```bash source tools/demo/auto/lib/rmux-drive.sh start_session dd-vis # Inside the pane: wrap the binary in asciinema rec send_keys dd-vis "asciinema rec /tmp/out.cast --cols 120 --rows 36 --overwrite -- design-data packages/design-data --theme spectrum --no-resume-wizard" Enter wait_for dd-vis "commands" 30 send_literal dd-vis ":" type_keys dd-vis "query property=accent-color" send_keys dd-vis "Enter" wait_for dd-vis "accent-color" 10 send_keys dd-vis "q" wait_quiet dd-vis end_session dd-vis # Render to GIF — same agg invocation as split-cast.py uses: agg /tmp/out.cast /tmp/out.gif --cols 120 --rows 36 # Claude can then read the GIF: # Read tool: /tmp/out.gif ``` **Ghostty + screencapture (real-terminal pixels, macOS only):** ```bash # 1. Open Ghostty with a pinned cell size (window-width/height are in cells): osascript -e 'tell application "Ghostty" to activate' # Or launch from CLI; set window-width = 120, window-height = 36 in Ghostty config. # 2. Drive input via AppleScript: osascript <<'EOF' tell application "Ghostty" set t to focused terminal of selected tab of front window input text ":query property=accent-color" to t send key "return" to t end tell EOF sleep 0.5 # let the frame render # 3. Capture the window to PNG: WIN_ID=$(GetWindowID Ghostty "") # or pass partial title screencapture -l"$WIN_ID" -o /tmp/tui.png # Claude reads the image: # Read tool: /tmp/tui.png ``` **Caveats for Tier 3:** * `agg` GIF uses its own renderer/font — faithful for layout, not for "does it look exactly like Ghostty." * Ghostty + `screencapture` requires Screen Recording TCC permission on the controlling terminal. It is **not deterministic** across machines/DPI/fonts (good on-demand spot check, poor committed golden). * Images support only **fuzzy assertions** ("logo fits", "columns aligned", "swatch is indigo") — not cell-exact. Prefer Tier 1 for exactness. *** ## Conventions * **asciinema, not VHS.** The `tools/demo/videos/` pipeline uses VHS for video manifests — do not touch it. The `tools/demo/auto/` pipeline uses asciinema — use that. * **rmux, not tmux.** The `rmux-drive.sh` library expects `rmux` on PATH. * The binary takes its terminal size from the real terminal (or rmux pane geometry). To test at a fixed size in the real binary, set the rmux pane with `RMUX_COLS`/`RMUX_ROWS` in `rmux-drive.sh` (default 120×36). For exact sizes in tests use `TestBackend` (Tier 1). * `--replay <ndjson>` mode (`sdk/cli/src/main.rs:92`) draws the final buffer and exits deterministically — useful for golden-file diffing without a live pane. ## Gotchas * **Budget**: `tests/budget.rs` enforces an 800-LOC cap on every `src/` file and checks no `async` appears in `view*.rs`. New render tests go in `tests/` (no cap there). * **`Message` size**: every `Message` variant must be ≤ 128 bytes (`tests/budget.rs`). Box large payloads. * **Rmux session names must be unique.** If a previous run left a session alive, `start_session` kills it automatically — but check for orphans with `rmux ls` if a test behaves oddly. * **Screen Recording permission** for Ghostty + `screencapture`: System Settings → Privacy & Security → Screen Recording → enable the terminal running the script.
View on GitHub