Replies: 6 comments
Pre-adoption housekeepingBefore this RFC moves from Draft to Adopted, a few open questions from Section 6 have been resolved or tracked: Q6 resolved — crate placement: single
|
|
Resolving Q5 — theming default Decision: terminal-native colors by default, with Rationale: the TUI is additive; fighting the user's terminal theme on launch creates friction for the majority of users who have already configured their environment. Spectrum colors are available for those who want a branded experience, but they should never be forced. This unblocks M5 polish without affecting M0–M4. No code change needed — this is a UX policy captured here and in Status update: the two hard/soft prerequisites are now closed:
M0 ( |
Adopted ✓All prerequisites are cleared; moving this RFC from Draft to Adopted. Prerequisites landed: Open questions resolved:
Open questions Q1–Q4 remain open per the RFC body — none are blocking M0. Tracking infrastructure created:
|
Q4 closed — MCP
|
| Tool | Wizard screen |
|---|---|
start_authoring_session |
initialise session on disk |
authoring_session_step_intent |
Screen 1 — intent + suggestions |
authoring_session_step_classification |
Screen 2 — layer / schema |
authoring_session_step_values |
Screen 3 — values / alias |
authoring_session_commit |
Screen 4 — write to file |
authoring_session_cancel |
discard session |
authoring_session_get |
inspect current state |
authoring_session_list |
enumerate active sessions |
State lives in Rust core (sdk/core/src/authoring/session.rs) as atomic JSON files, shared between the TUI and the new CLI subcommand. The MCP tools shell out to authoring-session — same pattern as every other tool in the server.
RFC #973 status after this PR:
Q3 — wizard draft persistence✅ (feat(sdk/tui): persist wizard draft across restarts (Q3 of RFC #973) #994)Q4 — MCP start_authoring_session parity✅ (feat(sdk,mcp): add MCP authoring-session tools (RFC #973 Q4) #995)- Q1 —
suggest_tokenreuse-banner threshold (scoring calibration) — still open - Q2 — wizard for foundation/structure layers (scope expansion) — still open
|
Q1 closed — PR #996 Calibrated
Also wired the RFC §3.10 reuse-first banner into TUI Screen 1 — it now appears in accent color above the suggestions table when |
RFC #973 — Shipped ✓All milestones and open questions are now resolved. Epic #980 is closed. Milestones landed:
Open questions resolved:
One item explicitly out of scope for v1 and deferred to a future RFC: a wizard for foundation/structure layer authoring (§5 + §6 Q2). If there's designer demand for that surface, it should open a new discussion rather than reopen this one.
|
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Interactive TUI & Token Authoring Wizard
1. Summary
Add a fourth transport to the
design-datatoolchain — an interactive TUI (design-data tui) built on Ratatui + crossterm, living as a new crate atsdk/tui/alongside the existingsdk/cli/. The TUI consumes the same resolver, validator, and query crates that already power the subcommand CLI and the MCP server; no spec changes, no IPC, no JSON round-trip.The flagship command is a four-screen token-authoring wizard that exercises the eventual
write_tokenoperation and makes the cascade, mode-set behavior, and rationale capture legible to designers through use. The wizard is the demo flagship; the surrounding TUI is the surface that makes everyday agent-surface operations (resolve, query, validate, describe, suggest, diff) feel like a session rather than a series of one-shot invocations.2. Problem statement
The agent-readable surface (RFC-C / Phase 8) defines a CLI, an MCP server, and a Claude Code Agent Skill — all backed by the same resolver, validator, and query implementations. The existing
design-dataCLI is normative for headless and agent use: JSON when stdout is not a TTY, human-friendly when it is.That leaves a gap. The "human-friendly when TTY" mode of a subcommand CLI is fundamentally non-stateful — every invocation re-parses the manifest, re-loads the cascade, and emits one shot of output. For three audiences this is the wrong shape:
resolve_token,query_tokens, andvalidate_usagecalls without restart cost.Non-goals
design-data validate ./tokensmust keep working.3. Proposed solution
Two parts: the TUI shell (§3.1–§3.7) and the token-authoring wizard that runs inside it (§3.8–§3.17).
3.1 Stack choice
Ratatui + crossterm, in the existing Cargo workspace, as a new crate at
sdk/tui/(sibling tosdk/cli/).Rationale:
sdk/core/src/report.rs,cascade::resolve,query::filter,validate::validate_*). A Rust TUI calls those crates directly — no IPC, no JSON round-trip, no shelling out todesign-data. This collapses the feedback loop the TUI exists to provide.3.2 Companion crates
ratatuicrosstermtui-inputtui-textareanucleosimilararboardsyntect3.3 Layout model
Three persistent regions, plus a transient modal layer for the wizard and other multi-step flows.
Primer header is populated once at session start by calling the
primeroperation against the dataset path. It re-renders only when the manifest changes (e.g. the user switches datasets via:open).Active view is owned by whichever command produced the current output. Each tool-catalog operation maps to a view type:
resolve_tokenquery_tokensvalidate_usagerule_id/severity, withinstance_pathjump-todescribe_componentsuggest_tokenget_guidancediff_datasetsDiffReportwith semantic-diff coloringPalette prompt is the universal entry point. Empty buffer + first keystroke opens a fuzzy command list; typing
/switches to query-expression mode; typing:is explicit command mode. Up/down arrows recall history (in-memory ring buffer, 100 entries, persisted to~/.local/state/design-data/historybetween sessions).3.4 State model
DatasetHandlewraps the same resolver/query/validate handles thatsdk/cli/uses. Loaded once at startup or on:open <path>; subsequent commands are cheap.3.5 Key bindings (initial proposal)
:/EscTab/Shift-Tab↑/↓Enterygthentgthenc?Ctrl-C/q(when palette empty)The
g-prefixed bindings are deliberately Helix/Kakoune-flavored — designers who already use modal editors get an accelerator; everyone else uses the palette.3.6 Manifest awareness
The spec is normative on this: when a manifest is present,
query_tokensandresolve_tokenMUST respectinclude/excludeand apply manifest overrides before returning results. The TUI surfaces this in two ways::manifest) opens aManifestSwitchmodal that lists discoverable manifests in the dataset.spectrum-webmanifest").Swapping manifests without restart is a deliberate demo affordance — it shows the same authoring session producing different results for different consumers, which is the core value prop of manifest-based filtering.
3.7 Output mode parity
The spec's TTY/non-TTY rule applies to the subcommand CLI. The TUI inverts it: we are always in a TTY, so every view is fully expressive (syntax-highlighted JSON, collapsible trees, color-coded diagnostics, mouse-scrollable tables).
For demos and bug reports, every view supports
y a(yank all) which copies the underlying JSON payload to the clipboard — the exact bytes the non-TTY CLI would have emitted. This keeps the TUI and CLI semantically equivalent for any given command, while letting the TUI render that payload however it wants.3.8 Wizard framing
The wizard is the first non-trivial command in the TUI and the demo flagship. It is a guided front-end for the eventual
write_tokenoperation, which is RECOMMENDED-not-NORMATIVE in v1 and marked Phase 8.x / not yet implemented.Design goal: a designer authoring their first product-layer token should finish the wizard understanding why their token landed where it did. The wizard succeeds if a designer who completes it once can do the same thing in
:new tokenwithout the wizard the second time.3.9 The seven implicit decisions
A token authored "the right way" satisfies, in roughly this order:
validate_usageclean on the proposed fragmentDoing these as seven sequential screens is the obvious move and the wrong one — too long, designers abandon. The wizard collapses these into four screens with progressive disclosure and smart defaults.
3.10 Screen 1 — Intent
Purpose: Make creating a duplicate token harder than reusing one.
Single text field: "What is this token for?" Free-form natural language.
As the user types (debounced ~250ms), the wizard calls
suggest_tokenwith the current text plus any property hint inferred from the words. Results render below the input as a ranked list with their cascade context.If the top result has a confidence above a threshold (TBD — depends on
suggest_token's scoring; initially we can use a simple cosine-similarity threshold over name-object fields), the wizard surfaces a banner:The "alias to existing" path short-circuits the rest of the wizard — it goes straight to Screen 4 (rationale + confirm) with the alias pre-filled. This is the reuse-first path.
The "create new" path continues to Screen 2.
Spec dependencies:
suggest_token(RECOMMENDED in v1). If not yet implemented, the wizard falls back to a fuzzy match overquery_tokensresults — degraded but functional.3.11 Screen 2 — Classification
Purpose: Make the naming system visible by making name assembly live.
Three regions on one screen:
The live preview panel updates on every field change. It shows the assembled token name, the file it would be written to, and the cascade position relative to existing foundation/structure layers.
Live validation runs each time a field changes — diagnostics from
validate_usage(Layer 1 and Layer 2 persdk/core/src/report.rs) render inline below the relevant field, not in a global footer. This is the part that turns the wizard into a teaching tool: aSPEC-NNNdiagnostic with its message next to the field that caused it.Name-object fields are populated from the primer's
taxonomyFields. Vocabulary autocomplete pulls from each field's declared values.3.12 Screen 3 — Values across modes
Purpose: Make mode-set thinking visible by making the matrix concrete.
A table whose rows are mode-set combinations derived from the primer's
modeSets. For a typical Spectrum dataset:Every cell defaults to
alias, pre-populated withsuggest_tokenresults scoped to that mode-set combination. The designer's job is to confirm or override, not author from scratch.Switching a row from
aliastoliteralrequires the designer to fill in a value — and the cell turns subtly different (background tint or marker) to signal the divergence. This visual nudge is intentional: literal values in a product extension should feel exceptional, not routine.Spec dependencies:
resolve_token(NORMATIVE) for previewing what each alias resolves to in that mode-set context. The wizard callsresolve_tokenper row to populate a small "resolves to" hint next to the alias name.3.13 Screen 4 — Rationale & confirm
Purpose: Capture the why, validate the whole, preview the write.
Three stacked regions:
Rationale (multi-line text, required, no character limit but soft-warned over ~280 chars):
This text gets recorded in two places per Product context — Agent capture behavior: the token's inline
rationalefield and the product-context document'soverrides[].rationaleorextensions.tokens[].rationale.Diagnostics — a final
validate_usagerun on the assembled fragment. Any errors block the confirm button; warnings show but don't block.Diff preview — what's about to change on disk. Two diffs side by side: the new/modified token file, and the
product-context.jsonupdate. Rendered withsimilar-driven coloring.Confirm writes. Cancel discards. Both leave a history entry so the wizard can be resumed with
:wizard last.3.14 Wizard state model
The state survives across screens; Tab/Shift-Tab jumps between screens once they've been touched (so power users can fly past Screen 1 if intent is already clear).
3.15 What the wizard exercises in the write path
When the user confirms, the wizard calls
write_token(Phase 8.x, eventually) with:The implementation gates this behind
--allow-writeuntilwrite_tokenlands insdk/core/. Pre-write_token, the confirm step emits a JSON payload to a temp file and offers:diffagainst the dataset — enough to demo the full wizard flow without a real write path.3.16 Failure modes worth designing explicitly
suggest_tokenimplementation yet → fall back toquery_tokensfuzzy match; banner says "showing existing tokens (suggestion ranking unavailable).":wizard resumereopens at the last screen. State is not persisted to disk across sessions in v1.3.17 Demo storyline
The storyline the wizard is built backward from:
This is what M3 has to deliver.
4. Phased plan
sdk/tui/, primer header, palette opens & closescargo run -p design-data-tui ./fixtures/spectrumshows the primer header and an empty active viewquery_tokensend-to-end:query background-color/*returns a filtered table; up/down navigates;yyanks selected rowresolve_token,describe_component,validate_usageviews:palette autocompletes operation nameswrite_tokenintegrationproduct-context.json; gated behind--allow-writeuntilwrite_tokenlands insdk/core/5. Out of scope (for v1)
write_token) is owned by RFC-C / Phase 8 follow-ups.6. Open questions
7. References
RFC family touch points
describe_componentview consumes this contractSpec dependencies
sdk/core/src/report.rs— diagnostic shape for the validate viewsdk/cli/src/main.rs— sibling crate sharing coreEcosystem
8. How to engage
sdk/tui/vssdk/tui-core/+sdk/tui-wizard/) and theDatasetHandleshape are the load-bearing decisions; push back if either looks wrong.suggest_tokenandwrite_tokenland per Phase 8 plans. If those plans shift, the wizard's degraded paths (§3.16) may need to grow.All reactions