Written back by fix-consistency after registering the workstream. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
11 KiB
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:
make designbook-check— detect the cloud designbook moved (existing llm-connect backend)./design-sync— pull the latest React designbook intodesignbook/.make designbook-sync— record the diff (RecentChanges.md).make ir— re-extract the IR; review their/git diff (the blueprint change).make adapt-lit— regenerate tokens, scaffold new components, emit drift reports.- Resolve drift — fill/adjust Lit behavior guided by
adapters/lit/drift/*.md. make parity-lit— confirm appearance + contract parity.
Add a make designbook-refresh orchestrator for the automatable steps (1–5, 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
maxDiffPixelRatiodiscipline). - 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