Files
whynot-design/workplans/WHYNOT-WP-0002-designbook-stack-adapters.md
tegwick 4e68a5c51d
Some checks failed
ci / check (push) Has been cancelled
ci / release (push) Has been cancelled
Record state-hub workstream + task IDs for WHYNOT-WP-0002
Written back by fix-consistency after registering the workstream.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-22 22:51:10 +02:00

11 KiB
Raw Blame History

id, type, title, domain, repo, status, owner, topic_slug, created, updated, state_hub_workstream_id
id type title domain repo status owner topic_slug created updated state_hub_workstream_id
WHYNOT-WP-0002 workplan Technology-neutral designbook with stack adapters (Lit reference) infotech whynot-design proposed claude custodian 2026-06-22 2026-06-22 0a3511c1-1771-438b-9364-104d8f0de2f8

Technology-neutral designbook with stack adapters (Lit reference)

Problem

Claude Design's designbook is React-bound (its /design-sync converter generates React components and React-rendered previews; a non-React DS "has nothing for the design agent to build with"). That defeats the idea of a designbook as a technology-neutral UI blueprint. coulomb needs to stay open to different UI stacks (Lit today, others later) while still using one Claude designbook for a consistent appearance.

Approach

Keep React as the interaction surface with Claude Design (use the recommended React designbook — it is what the tool supports), but introduce a technology-neutral intermediate representation (IR) as the actual blueprint, and per-stack adapters that project the IR onto each stack. Lit is the first/reference adapter. Adapters are scaffold + drift-detect, not full behavioral codegen: tokens are fully generated, new components get stubs, changed components get a drift report (never an overwrite), and visual parity is checked against the designbook's own exemplars. Behavior stays hand-authored per stack.

Claude Design  (React designbook — canonical authoring surface)
   │  /design-sync                        [exists]
   ▼
designbook/   (local React mirror: components/<group>/<Name>/{.d.ts,.prompt.md,.html},
   │           tokens/, styles.css, _ds_bundle.js, _ds_manifest.json)
   │  make ir   →  ir/extract  (the pivot)
   ▼
ir/           (technology-neutral blueprint, committed + diffable)
   │  tokens.json   (W3C Design Tokens format)
   │  components/<Name>.json  (contract: props/attrs, variants, slots, events, docs, exemplar)
   │  exemplars/<Name>.{png,html}  (reference render from the designbook preview)
   │  make adapt-lit  →  adapters/lit
   ▼
adapters/lit/ (reference)   tokens → CSS custom props (full gen)
                            new component → <wn-*> stub + contract scaffold
                            changed component → DRIFT REPORT (no overwrite)
                            make parity-lit → visual + contract parity vs exemplar

Directionality is one-way: React → IR → stacks. Lit-side changes do not flow back automatically; a change to the shared language must be made in Claude Design (React) and re-propagated. The Lit components remain hand-authored; the adapter keeps their contract and appearance aligned, it does not own their behavior.

Builds on (already in this repo)

  • designbook/ — local mirror of the Claude Design project + designbook/README.md.
  • make designbook-sync / RecentChanges.md — record what a sync changed.
  • make designbook-check + scripts/check_designbook_staleness.py — llm-connect backend that detects when the cloud designbook moved ahead (the refresh trigger).
  • tokens/*.json, src/styles/*.css, src/elements/*.js — the existing Lit DS, which becomes the first adapter's target/baseline.
  • Playwright visual harness (tests/visual/) — extended for parity in Phase 4.

Phase 0 — Contracts & governance

Establish the durable interfaces before any code, so future stacks slot in cleanly.

Define the IR schema

id: WHYNOT-WP-0002-T01
status: todo
priority: high
state_hub_task_id: "66187d76-3755-4204-ad71-d9fae8ed38ac"

Specify the technology-neutral blueprint. Tokens: adopt the W3C Design Tokens Community Group JSON format ($value/$type) so the token layer is a standard, not a bespoke shape — tokens/*.json already holds the values. Component contract (ir/components/<Name>.json): name, group, description, props (name/type/enum/default/required), prop→attribute mapping (React camelCase prop → Lit attribute/property), slots, events, variant axes, docsRef, exemplarRef. Write ir/SCHEMA.md + a JSON Schema for validation. Decide and document that ir/ is committed (diffable blueprint).

Define the adapter interface

id: WHYNOT-WP-0002-T02
status: todo
priority: high
state_hub_task_id: "6fe8481c-02b3-407d-9b7b-c47f161c0dcd"

Document the contract every stack adapter implements so Vue/Angular/plain-CSS adapters are drop-in: inputs (ir/), outputs (generated artifacts into the stack's source tree, a machine-readable drift report, a parity result), idempotency rules (regenerate tokens

  • stubs; never overwrite hand-authored behavior), and exit codes for CI. Write adapters/ADAPTER_CONTRACT.md.

Governance & propagation doc

id: WHYNOT-WP-0002-T03
status: todo
priority: medium
state_hub_task_id: "97aadf8a-4d56-47d0-b841-d664d0676a53"

Document directionality (React canonical, one-way to stacks, Lit changes round-trip through Claude Design), the drift-resolution workflow (who fills behavior, how a drift report is triaged/closed), and how this extends the existing atelier→repo pipeline. Update DesignSystemIntroduction.md (§5 propagation) and add a rule under .claude/rules/.


Phase 1 — Canonical React designbook source

Establish the React designbook as canonical

id: WHYNOT-WP-0002-T04
status: todo
priority: high
state_hub_task_id: "ed4dd1d4-f649-40f0-83f5-9cbd88622a7b"

The pivot needs a real React source in Claude Design (the current project holds the hand-authored web-component experiment, not a React component bundle). Decide how the canonical React designbook is established and maintained: author a React expression of the wn-* component set in Claude Design (native, /design-sync-compatible), tokens-first then grow components, or adopt an existing React kit. Define how it is pulled into designbook/. Risk/dependency: this is the precondition for IR extraction; scope it deliberately — a minimal token-plus-core-components React designbook is enough to prove the pipeline.


Phase 2 — IR extraction (the pivot)

Build the IR extractor

id: WHYNOT-WP-0002-T05
status: todo
priority: high
state_hub_task_id: "dcdc0b01-756f-4253-9599-e5d5dfbe1083"

Build scripts/ir-extract.mjs: read the designbook/ React mirror — .d.ts (props), .prompt.md (docs), _ds_manifest.json (groups), tokens/ (values), preview .html (exemplar render) — and emit ir/tokens.json (W3C format), ir/components/<Name>.json (per T01 schema), and ir/exemplars/<Name>.*. Validate output against the JSON Schema from T01. Add make ir. ir/ is committed so a re-extract surfaces blueprint changes as a git diff.


Phase 3 — Lit reference adapter

Token generation (full gen)

id: WHYNOT-WP-0002-T06
status: todo
priority: high
state_hub_task_id: "a106c673-e849-4d06-91c9-3f7f63fec2ea"

adapters/lit/: generate CSS custom properties from ir/tokens.json into src/styles/colors_and_type.css (the existing token layer). Fully generated + deterministic; re-running is a no-op when nothing changed. Add make adapt-lit (tokens portion first).

Component scaffold + drift report

id: WHYNOT-WP-0002-T07
status: todo
priority: high
state_hub_task_id: "00ed1aff-7724-4e90-9a51-fd58699480ca"

Extend adapters/lit/: for an IR component with no wn-* counterpart, generate a Lit stub (<wn-*> skeleton + reactive properties from the contract's prop→attribute map + a TODO for behavior). For an existing component, emit a drift report (adapters/lit/drift/<Name>.md): prop/attribute mismatches, missing/extra variants, removed props — never overwrite the hand-authored element. Map React prop types → Lit property declarations. Wire into make adapt-lit.


Phase 4 — Parity verification

Contract + visual parity

id: WHYNOT-WP-0002-T08
status: todo
priority: medium
state_hub_task_id: "1f52ca1f-64a6-4643-992f-f0b4812461a0"

make parity-lit: (a) contract parity — assert each wn-* element's observed attributes/properties match its IR contract (fail on drift); (b) visual parity — render the Lit component and diff against ir/exemplars/<Name> using the existing Playwright harness, emit a parity diff. Produce a single parity result per the adapter contract (T02). This is the gate that confirms Lit actually matches the designbook appearance.


Phase 5 — Keep-up-to-date instruction set

Refresh loop + runbook

id: WHYNOT-WP-0002-T09
status: todo
priority: high
state_hub_task_id: "07e60a34-0c62-4f8b-848b-d3b8d4292a18"

Wire and document the end-to-end refresh sequence so keeping Lit current against the React designbook is one routine:

  1. make designbook-check — detect the cloud designbook moved (existing llm-connect backend).
  2. /design-sync — pull the latest React designbook into designbook/.
  3. make designbook-sync — record the diff (RecentChanges.md).
  4. make ir — re-extract the IR; review the ir/ git diff (the blueprint change).
  5. make adapt-lit — regenerate tokens, scaffold new components, emit drift reports.
  6. Resolve drift — fill/adjust Lit behavior guided by adapters/lit/drift/*.md.
  7. make parity-lit — confirm appearance + contract parity.

Add a make designbook-refresh orchestrator for the automatable steps (15, 7) and a human-in-loop runbook for step 6. Document in .claude/rules/stack-and-commands.md and designbook/README.md.


Phase 6 — Generalization hook (prove extractability)

Second-adapter smoke (validate the boundary)

id: WHYNOT-WP-0002-T10
status: todo
priority: low
state_hub_task_id: "483de131-f580-4031-85df-72cf70a45679"

Sketch a minimal second adapter (plain-CSS utility classes or a Vue stub) that consumes the same ir/ and implements the T02 contract — just enough to prove the IR/adapter boundary holds and the architecture can be lifted into a coulomb-level tool later. Do not finish the second stack; the deliverable is confidence in the seam.


Open questions / risks

  • React designbook bootstrap (T04) is the critical-path dependency — without a real React source, the IR has nothing to extract. Keep its initial scope minimal.
  • Prop→attribute fidelity: React props (objects, render props, callbacks) don't all map to Lit attributes; the contract must mark non-portable props and the adapter must surface them as drift, not silently drop them.
  • Exemplar parity tolerance: web-component vs React rendering will differ at the pixel level; parity needs a sensible diff threshold (reuse maxDiffPixelRatio discipline).
  • One-way constraint: ensure the tooling never tempts a Lit→React back-edit that bypasses Claude Design; governance doc (T03) must make the round-trip explicit.

Registering this workplan

After review, register the workstream from ~/state-hub:

make fix-consistency REPO=whynot-design