baldart 3.9.0 → 3.12.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (38) hide show
  1. package/CHANGELOG.md +93 -0
  2. package/README.md +15 -3
  3. package/VERSION +1 -1
  4. package/framework/.claude/agents/REGISTRY.md +3 -3
  5. package/framework/.claude/agents/code-reviewer.md +47 -11
  6. package/framework/.claude/agents/codebase-architect.md +8 -0
  7. package/framework/.claude/agents/ui-expert.md +355 -43
  8. package/framework/.claude/commands/design-review.md +7 -0
  9. package/framework/.claude/skills/bug/SKILL.md +5 -1
  10. package/framework/.claude/skills/context-primer/SKILL.md +4 -0
  11. package/framework/.claude/skills/design-system-init/SKILL.md +232 -0
  12. package/framework/.claude/skills/design-system-init/scripts/component-spec.template.md +79 -0
  13. package/framework/.claude/skills/frontend-design/SKILL.md +124 -0
  14. package/framework/.claude/skills/lsp-bootstrap/SKILL.md +113 -0
  15. package/framework/.claude/skills/motion-design/reference/accessibility-and-modern-apis.md +114 -0
  16. package/framework/.claude/skills/new/SKILL.md +1 -1
  17. package/framework/.claude/skills/prd/SKILL.md +3 -1
  18. package/framework/.claude/skills/simplify/SKILL.md +6 -0
  19. package/framework/.claude/skills/ui-design/SKILL.md +43 -0
  20. package/framework/agents/code-search-protocol.md +126 -0
  21. package/framework/agents/design-review.md +51 -0
  22. package/framework/agents/design-system-protocol.md +363 -0
  23. package/framework/agents/index.md +4 -0
  24. package/framework/docs/LSP-LAYER.md +405 -0
  25. package/framework/docs/PROJECT-CONFIGURATION.md +17 -0
  26. package/framework/docs/UPGRADE-3.12-UI-COHERENCE.md +268 -0
  27. package/framework/templates/baldart.config.template.yml +22 -0
  28. package/framework/templates/overlays/agents/codebase-architect.lsp-example.md +53 -0
  29. package/package.json +1 -1
  30. package/src/commands/configure.js +69 -0
  31. package/src/commands/doctor.js +55 -0
  32. package/src/utils/lsp-adapters/go.js +29 -0
  33. package/src/utils/lsp-adapters/index.js +49 -0
  34. package/src/utils/lsp-adapters/python.js +42 -0
  35. package/src/utils/lsp-adapters/ruby.js +30 -0
  36. package/src/utils/lsp-adapters/rust.js +26 -0
  37. package/src/utils/lsp-adapters/typescript.js +54 -0
  38. package/src/utils/lsp-installer.js +118 -0
@@ -148,7 +148,9 @@ Before entering the discovery loop, load codebase context using the **context-pr
148
148
  2. Invoke the `Skill` tool with `skill: "context-primer"` passing the keywords
149
149
  (e.g., `args: "prize scanning scratch card wheel"`).
150
150
  3. The context-primer launches `codebase-architect` which searches RAG, docs,
151
- backlog, source code, and git history — returning a compact summary.
151
+ backlog, source code, and git history — returning a compact summary. When
152
+ `features.has_lsp_layer: true`, the symbol-lookup tier is automatically used
153
+ for identifier-shaped queries (transitive via `agents/code-search-protocol.md`).
152
154
  4. Additionally, use `search_docs` MCP tool (if available) with `mode: "hybrid"` for the feature domain
153
155
  to surface related PRDs, ADRs, and specs not covered by context-primer. The
154
156
  active retrieval layer is Obsidian-first LightRAG; use Obsidian hits for
@@ -39,6 +39,12 @@ For each new piece of code in the diff:
39
39
  1. **Start with `${paths.references_dir}/component-registry.md`** — the authoritative inventory of all UI primitives, shared components, hooks, and utility modules. Scan the relevant tables before grepping. Then search for existing utilities and helpers that could replace newly written code in the project's utility roots (e.g. `${paths.components_root}/shared/`, `${paths.components_primitives}/`, and `src/lib/`, `src/hooks/` if they exist), and files adjacent to the changed ones.
40
40
  2. **For each new component**, Grep the codebase for components with similar names, similar prop signatures, or similar JSX structure. Check for copy-pasted layout components (`layout.tsx` files with near-identical structure).
41
41
  3. **For each new function/hook**, search for functions with similar signatures or logic patterns elsewhere. Check for duplicated page-level patterns (similar data fetching, similar error boundaries, similar loading states).
42
+ When `features.has_lsp_layer: true`, run LSP `find-references` on each new exported
43
+ symbol before grepping — it tells you exactly which callsites would need to migrate
44
+ if you replaced the new code with an existing utility (textual grep over identifier
45
+ names overcounts because of collisions). See `framework/agents/code-search-protocol.md`.
46
+ Also use LSP `find-references` on candidate "existing" utilities to confirm they're
47
+ really in use and not abandoned dead code before recommending them as the canonical version.
42
48
  4. **Flag components that wrap the same underlying element** with minor style/prop differences.
43
49
 
44
50
  Classify each finding as:
@@ -32,6 +32,11 @@ Evaluation is always performed by a separate agent with fresh context.
32
32
 
33
33
  ## Prerequisites — BLOCKING reads before ANY design work
34
34
 
35
+ The registry-first cascade below is the consumer view of the SSOT in
36
+ [`framework/agents/design-system-protocol.md`](../../../agents/design-system-protocol.md).
37
+ When the cascade rules diverge between this file and the protocol module,
38
+ the protocol module wins.
39
+
35
40
  These reads are BLOCKING. Resolve paths from `baldart.config.yml` before opening files. If `features.has_design_system: true`, item 1 is the mandatory entry point and skipping it is a protocol violation.
36
41
 
37
42
  1. **MANDATORY / BLOCKING when `features.has_design_system: true`** — read `${paths.design_system}/INDEX.md` (the design-system entry point: component index, authority matrix, token contract, any project-specific theming pairing rules and overlay decision tree).
@@ -141,6 +146,43 @@ Read [references/inventory.md](references/inventory.md).
141
146
  3. Update state file with chosen option, design decisions, component lists.
142
147
  4. Clean up `/tmp/prd-design-<slug>/`.
143
148
 
149
+ ### Step H — Registry Coherence Reconciliation (BLOCKING completion gate)
150
+
151
+ When `features.has_design_system: true`, the design is not complete until the
152
+ component registry reflects every primitive the chosen design depends on. Run
153
+ the **Post-Intervention Coherence Check** defined in
154
+ [`framework/agents/design-system-protocol.md`](../../../agents/design-system-protocol.md)
155
+ § "Post-Intervention Coherence Check".
156
+
157
+ Concretely, walk the UI Element Inventory from Step G and for each item:
158
+
159
+ 1. **Registry-hit confirmed**: the primitive exists in `${paths.design_system}/INDEX.md`
160
+ AND its `components/<Name>.md` spec matches the way the design uses it
161
+ (props, variants, accessibility). If the design uses a variant not yet
162
+ documented, update the spec inline.
163
+ 2. **Source-tree-hit silent primitive**: the primitive exists under
164
+ `${paths.components_primitives}` but not in `INDEX.md`. Add the INDEX entry
165
+ inline (full spec or stub `status: needs-review`, see decision matrix in the
166
+ protocol).
167
+ 3. **New primitive proposed by the design**: it has no source implementation
168
+ AND no spec. Either:
169
+ - scaffold the spec + INDEX entry now as part of the inventory deliverable, OR
170
+ - open a follow-up card and **flag the gap explicitly** in the inventory so
171
+ downstream implementation work cannot proceed without resolution.
172
+ 4. **Token additions**: the design introduces a color / spacing / shadow / motion
173
+ value not present in `${paths.design_system}/tokens-reference.md`. Update the
174
+ reference inline OR open a follow-up token-addition card before approval.
175
+
176
+ Surface every finding in the design handoff with the standard codes
177
+ (`DS_INDEX_DRIFT` / `DS_COMPONENT_STALE` / `DS_TOKENS_DRIFT`). Silent
178
+ reconciliation is forbidden — the user must see the drift that was found and
179
+ how it was resolved (inline vs. follow-up card).
180
+
181
+ This step exists because the design phase is where drift is **cheapest to
182
+ prevent**: catching a duplicate primitive at the mockup stage costs minutes,
183
+ catching it after implementation costs a refactor. The weekly `ds-drift`
184
+ routine is a safety net, not a substitute for this check.
185
+
144
186
  ---
145
187
 
146
188
  ## Design Principles (quick reference)
@@ -153,6 +195,7 @@ These are enforced — read `${paths.ui_guidelines}` for full spec.
153
195
  - **Multi-tenant theming pairing**: when `features.multi_tenant_theming: true`, themed text-token paired with themed bg-token per the project's theming pattern doc
154
196
  - **View State Trinity**: loading (skeletons), error (localized message + retry), empty (CTA). The error language follows `identity.language`.
155
197
  - **Separation of concerns**: UI / business logic / data layers stay separate
198
+ - **Registry coherence (BLOCKING)**: when `has_design_system: true`, every primitive in the chosen design is reconciled with `INDEX.md` + `components/<Name>.md` + `tokens-reference.md` before sign-off (Step H). New primitive ⇒ new spec same change. Modified primitive ⇒ updated spec same change. Silent reuse of undocumented primitive ⇒ INDEX entry added now
156
199
 
157
200
  ---
158
201
 
@@ -0,0 +1,126 @@
1
+ # Code Search Protocol
2
+
3
+ ## Purpose
4
+
5
+ Define a deterministic retrieval hierarchy for agents and skills that need to
6
+ find code (identifiers, references, definitions, similar patterns) inside the
7
+ consumer repo. The goal is to filter noise **before** Claude reads files, not
8
+ after — Grep on a common function name returns thousands of textual matches and
9
+ burns context; LSP returns only the references that point to the same symbol.
10
+
11
+ ## Scope
12
+
13
+ **In**: How agents/skills should choose between RAG, LSP, Grep, and Git when
14
+ searching for code. Fallback rules when a tier is unavailable.
15
+ **Out**: Documentation search (see `agents/llm-wiki-methodology.md`), test
16
+ discovery (see `agents/testing.md`).
17
+
18
+ ## Gating
19
+
20
+ This protocol is **conditional** on `features.has_lsp_layer: true` in
21
+ `baldart.config.yml`. When the flag is `false` or missing, agents fall back to
22
+ the legacy RAG → Grep → Git flow and skip the LSP tier entirely.
23
+
24
+ Adapters for installed servers live under `src/utils/lsp-adapters/`; the
25
+ current set of servers BALDART has wired in this project is recorded at
26
+ `lsp.installed_servers` in `baldart.config.yml`.
27
+
28
+ ## Retrieval Hierarchy (in order)
29
+
30
+ 1. **RAG hybrid** — `search_docs(query, mode: "hybrid")` via the doc-rag MCP if
31
+ available. Best for free-text and conceptual queries ("how does session
32
+ token storage work").
33
+ 2. **LSP symbol search** — when the query is an identifier (function, type,
34
+ class, variable name) and `features.has_lsp_layer: true`. Use the LSP tool
35
+ (`ToolSearch("LSP")` in Claude Code) for:
36
+ - **find references**: every callsite of a symbol across the project.
37
+ - **go to definition**: the single authoritative declaration.
38
+ - **type info / hover**: signature, parameters, return type.
39
+ - **document/workspace symbols**: enumerate top-level symbols.
40
+ 3. **Grep** — for textual patterns that aren't symbols (a comment, a magic
41
+ string, a regex match, a config key, a TODO marker). Also the fallback when
42
+ LSP is unavailable or returns nothing for a symbol that clearly exists.
43
+ 4. **Git log** — `git log --oneline -20 --grep="keyword"` to find when and why
44
+ code changed. Last resort, but cheap when you suspect a regression.
45
+
46
+ ## Query-type discrimination
47
+
48
+ Before picking a tier, classify the query:
49
+
50
+ | Query shape | Start with |
51
+ |----------------------------------------|------------|
52
+ | `handleSubmit`, `UserSchema`, `useAuth`| LSP |
53
+ | `"TODO: encrypt tokens"` | Grep |
54
+ | `/api/v1/users` route handler | Grep then LSP on the handler name |
55
+ | "how is auth wired" | RAG hybrid |
56
+ | "when did we change session storage" | Git log |
57
+ | Mixed (refactor a function used in 5 places) | RAG → LSP find-references |
58
+
59
+ ## Budget
60
+
61
+ - **LSP**: up to **3 calls per task** for symbol resolution. If after 3 calls
62
+ the picture is still unclear, escalate to RAG or read the file directly —
63
+ don't keep ping-ponging through references.
64
+ - **Grep**: existing project budget (typically 15–25 calls per agent).
65
+ - **RAG / Git**: no hard budget, but verify the verdict (`rag_telemetry.verdict`
66
+ for RAG) before relying on it.
67
+
68
+ ## Fallback rules
69
+
70
+ - LSP tool not loaded / plugin missing → silently fall back to Grep with the
71
+ symbol name. Do **not** prompt the user mid-task — the missing tool is a
72
+ setup concern surfaced by `baldart doctor`.
73
+ - LSP returns zero references for a symbol you know exists → fall back to
74
+ Grep; the symbol may live in a file the LSP server hasn't indexed yet (e.g.
75
+ a path excluded by `tsconfig.json`).
76
+ - LSP times out (>8s) → fall back to Grep for this query, log the symptom in
77
+ the agent's reasoning so the user can re-run doctor.
78
+
79
+ ## Examples
80
+
81
+ ### Refactor: rename a function used across the repo
82
+
83
+ 1. RAG hybrid: confirm the function is the right one and not a name collision.
84
+ 2. LSP find-references on the symbol → exact callsite list (file + line +
85
+ column).
86
+ 3. Read each callsite, propose the rename, apply edits.
87
+
88
+ Why this beats Grep: a project with both `handleSubmit` in a form component
89
+ and `handleSubmit` in a CLI utility gets two semantically distinct sets from
90
+ LSP, but a single conflated list from Grep.
91
+
92
+ ### Bug: trace where a value originates
93
+
94
+ 1. RAG hybrid on the symptom (free text).
95
+ 2. LSP go-to-definition on the suspect variable → authoritative source.
96
+ 3. LSP find-references back from the definition → call graph upstream.
97
+ 4. Grep only if LSP cannot resolve (e.g. the value passes through a
98
+ dynamically-typed boundary).
99
+
100
+ ### Cleanup: remove a deprecated helper
101
+
102
+ 1. LSP find-references on the helper. Zero hits → safe to delete.
103
+ 2. Non-zero hits → migrate callsites first, then delete.
104
+
105
+ Skip Grep here: textual matches inside string literals or comments are not
106
+ true callsites and would falsely block the deletion.
107
+
108
+ ## When to skip LSP entirely
109
+
110
+ - Query is a phrase or comment, not a symbol.
111
+ - The project's `lsp.installed_servers` is empty for the relevant language.
112
+ - You are reading a single small file (under 200 lines) — direct Read is
113
+ cheaper than a tool call.
114
+
115
+ ## Maintenance
116
+
117
+ When adding a new language to `src/utils/lsp-adapters/`, no change is required
118
+ here unless the new language has special tooling caveats (e.g. multi-root
119
+ workspaces, monorepos). In that case, append a subsection below.
120
+
121
+ ## See also
122
+
123
+ - `framework/.claude/skills/lsp-bootstrap/SKILL.md` — install + verify flow.
124
+ - `framework/agents/project-context.md` — always-ask / never-assume contract.
125
+ - `framework/.claude/agents/codebase-architect.md` — primary consumer of this
126
+ protocol.
@@ -9,6 +9,23 @@ Define design review process and UI/UX quality standards.
9
9
  **In**: UI review criteria, design consistency, accessibility.
10
10
  **Out**: Implementation details (see agents/coding-standards.md).
11
11
 
12
+ ## Registry-First Pre-Work (BLOCKING when `features.has_design_system: true`)
13
+
14
+ Before walking the checklist below, execute the cascade defined in
15
+ [`framework/agents/design-system-protocol.md`](design-system-protocol.md):
16
+
17
+ 1. Read `${paths.design_system}/INDEX.md` and extract the Authority Matrix for
18
+ every primitive present on the route under review.
19
+ 2. Read `${paths.design_system}/tokens-reference.md` and use it as the SSOT
20
+ when judging color / shadow / radius / spacing decisions.
21
+ 3. For each component visible in the screenshots/DOM, read the corresponding
22
+ `${paths.design_system}/components/<Name>.md` spec.
23
+
24
+ When `features.has_design_system: false`, skip the registry reads and run the
25
+ checklist using `${paths.ui_guidelines}` alone — but flag in the report that
26
+ the absence of a registry is preventing systematic conformance checks, and
27
+ recommend `/design-system-init`.
28
+
12
29
  ## Do
13
30
 
14
31
  - Review designs before implementation
@@ -24,6 +41,19 @@ Define design review process and UI/UX quality standards.
24
41
 
25
42
  ## Design Review Checklist
26
43
 
44
+ ### Design-System Conformance (when `has_design_system: true`)
45
+
46
+ - [ ] Every primitive in the DOM is listed in `${paths.design_system}/INDEX.md`
47
+ - [ ] No reinvented variant of an existing registry primitive
48
+ - [ ] No hardcoded color / shadow / radius / spacing values that bypass
49
+ `${paths.design_system}/tokens-reference.md`
50
+ - [ ] Each component matches its `components/<Name>.md` spec (props, variants,
51
+ a11y hooks)
52
+ - [ ] Authority Matrix respected — no local override of registry-authoritative
53
+ decisions
54
+ - [ ] New primitives introduced in the change ship with their per-component
55
+ spec in the same change
56
+
27
57
  ### Visual Design
28
58
 
29
59
  - [ ] Follows design system/style guide
@@ -170,3 +200,24 @@ Define supported devices:
170
200
  - **Approved with minor changes**: Small tweaks needed
171
201
  - **Needs revision**: Significant changes required
172
202
  - **Rejected**: Fundamental issues, needs redesign
203
+
204
+ ## Report Template
205
+
206
+ Every `/design-review` report MUST include a top-level section
207
+ **Design-System Conformance** with these subsections (when
208
+ `has_design_system: true`):
209
+
210
+ - **Primitives reused** — list of `<Name>` taken from
211
+ `${paths.design_system}/INDEX.md`.
212
+ - **Primitives reinvented** — DOM components that duplicate or overlap with an
213
+ existing registry primitive. HIGH severity.
214
+ - **Tokens bypassed** — hardcoded values that should have used a token from
215
+ `tokens-reference.md`. HIGH severity.
216
+ - **Spec drift** — components in the diff that diverge from their
217
+ `components/<Name>.md`. MEDIUM severity.
218
+ - **New primitives proposed** — components that legitimately need a new
219
+ registry entry, with a one-line justification.
220
+
221
+ When `has_design_system: false`, replace the section with:
222
+ > Design-system conformance check skipped — `features.has_design_system: false`.
223
+ > Run `/design-system-init` to enable systematic conformance checks.
@@ -0,0 +1,363 @@
1
+ # Design-System Protocol
2
+
3
+ ## Purpose
4
+
5
+ Define a deterministic, registry-first discipline for any agent or skill that
6
+ touches a visual surface (component, page, mockup, design review). The goal is
7
+ twofold:
8
+
9
+ 1. **Visual coherence** across the whole product — every UI passes through the
10
+ same canonical inventory of primitives + tokens, never reinvents one.
11
+ 2. **Code economy** — the component registry is interrogated **before**
12
+ implementation, so existing primitives are reused instead of duplicated.
13
+
14
+ This is the textual SSOT for the registry-first protocol. Skills (`ui-design`,
15
+ `frontend-design`, `design-system-init`), agents (`ui-expert`, `code-reviewer`),
16
+ and the `/design-review` command all reference this module instead of
17
+ duplicating the BLOCKING-read cascade.
18
+
19
+ ## Scope
20
+
21
+ **In**: How to discover, reuse, and extend the project component registry
22
+ before producing or reviewing UI. Token contract enforcement. Authority matrix.
23
+ What to do when a primitive is missing.
24
+
25
+ **Out**: Aesthetic direction (see `${paths.ui_guidelines}` and
26
+ `identity.design_philosophy`), motion specs (see `motion-design` skill),
27
+ illustration assets (see `visual-designer` agent).
28
+
29
+ ## Gating
30
+
31
+ This protocol is **conditional** on `features.has_design_system: true` in
32
+ `baldart.config.yml`. When the flag is `false` or missing, the registry reads
33
+ in step 1 below are SKIPPED — agents/skills still respect
34
+ `${paths.ui_guidelines}` but do not block on a registry that does not exist.
35
+
36
+ When the flag is `true`, the registry reads are **BLOCKING**: skipping them is
37
+ a protocol violation and the agent must refuse to proceed.
38
+
39
+ To bootstrap a registry on a project that does not yet have one, invoke the
40
+ `design-system-init` skill (`/design-system-init`).
41
+
42
+ ## Canonical sources (resolve via `baldart.config.yml`)
43
+
44
+ - `${paths.design_system}/INDEX.md` — component index + Canonical Authority
45
+ Matrix + quick MUST rules. Entry point for every UI task.
46
+ - `${paths.design_system}/tokens-reference.md` — human-readable token contract
47
+ (colors, spacing, shadows, radii, motion). Single source of truth for any
48
+ value that would otherwise be hardcoded.
49
+ - `${paths.design_system}/components/<Name>.md` — per-component spec (props,
50
+ variants, accessibility, anti-patterns). One file per primitive.
51
+ - `${paths.design_system}/patterns/*.md` — opt-in pattern docs (theming,
52
+ overlays, motion choreography, multi-tenant pairing rules).
53
+ - `${paths.ui_guidelines}` — brand voice, typography, philosophy. Always read.
54
+ - `${paths.components_primitives}` / `${paths.components_root}` — source roots
55
+ where the registry primitives are actually implemented.
56
+
57
+ ## BLOCKING pre-work (when `has_design_system: true`)
58
+
59
+ Before producing any new UI code, mockup, or design review:
60
+
61
+ 1. **BLOCKING** — read `${paths.design_system}/INDEX.md`. Extract: the
62
+ component index, the Authority Matrix for the surface you are about to
63
+ touch, any pattern docs the index points to.
64
+ 2. **BLOCKING** — read `${paths.ui_guidelines}` for visual language, typography,
65
+ accessibility, and brand voice. The `identity.design_philosophy` (when set)
66
+ is the lens through which these guidelines apply.
67
+ 3. **BLOCKING** — read `${paths.design_system}/tokens-reference.md`. Treat it
68
+ as the SSOT for every color / spacing / shadow / radius / duration value.
69
+ 4. **BLOCKING per primitive in scope** — read the relevant
70
+ `${paths.design_system}/components/<Name>.md`. For every component the task
71
+ will create, modify, or visually depend on.
72
+ 5. **BLOCKING per pattern in scope** — read the relevant
73
+ `${paths.design_system}/patterns/<topic>.md` (e.g. theming pattern when
74
+ `features.multi_tenant_theming: true`).
75
+
76
+ Skipping any of the above when the gating flag is `true` is a protocol
77
+ violation. The correct response to a missing file is to flag it and propose
78
+ adding it via `design-system-init` or a follow-up card — **not** to proceed
79
+ without it.
80
+
81
+ ## Component Discovery Cascade
82
+
83
+ For every visual element the task introduces or touches, walk the cascade in
84
+ order. Stop at the first match.
85
+
86
+ 1. **Registry hit** — `${paths.design_system}/INDEX.md` lists a primitive that
87
+ covers the use case. Use the per-component spec to implement.
88
+ 2. **Source-tree hit** — a component exists under
89
+ `${paths.components_primitives}` (or `${paths.components_root}/shared/*`)
90
+ that is not yet documented in the registry. Use it, then **propose adding
91
+ it to the registry** as a follow-up — the registry is the canonical
92
+ inventory and silent primitives create drift.
93
+ 3. **External catalog candidate** — no in-repo match but a catalog primitive
94
+ (shadcn, 21st.dev, Radix UI, etc.) fits the canonical stack. Use it,
95
+ document it as a new entry in the registry.
96
+ 4. **Create from scratch** — only after 1–3 fail. Any newly created primitive
97
+ MUST be tokens-compliant and must ship with its per-component spec in the
98
+ same change.
99
+
100
+ The cascade is identical for design (mockups, HTML prototypes) and for
101
+ implementation (component code).
102
+
103
+ ## Token Contract
104
+
105
+ When `features.has_design_system: true`, the following are **forbidden** in
106
+ any code or mockup produced under this protocol:
107
+
108
+ - Hardcoded hex / rgb / hsl color literals (use the color tokens).
109
+ - Hardcoded shadow tuples (use the shadow tokens).
110
+ - Hardcoded border-width / border-radius numeric literals (use the radius and
111
+ border tokens).
112
+ - Hardcoded spacing numbers outside the spacing scale (use the spacing tokens).
113
+ - Hardcoded motion durations or easings (use the motion tokens, or escalate to
114
+ the `motion-design` skill).
115
+
116
+ The exact token consumption mechanism (CSS custom properties, Tailwind theme
117
+ extend, theme provider) is project-specific — defer to
118
+ `${paths.design_system}/tokens-reference.md` and the project's chosen
119
+ mechanism.
120
+
121
+ ## Reference Tables (embed)
122
+
123
+ These tables are the SSOT for the *numeric ranges* every agent/skill should
124
+ cite verbatim instead of guessing. They complement
125
+ `${paths.design_system}/tokens-reference.md` (which holds the *project-specific*
126
+ values) by providing the canonical menu of options from which a project
127
+ typically derives its tokens.
128
+
129
+ ### Type scale (base 16px)
130
+
131
+ | Ratio | Name | Use | Example sequence (rounded) |
132
+ |---|---|---|---|
133
+ | 1.125 | Major Second | Dense UI, dashboards | 12 / 14 / 16 / 18 / 20 / 23 / 26 |
134
+ | 1.200 | Minor Third | Default web app | 12 / 14 / 16 / 19 / 23 / 28 / 33 |
135
+ | 1.250 | Major Third | Marketing, landing | 13 / 16 / 20 / 25 / 31 / 39 / 49 |
136
+ | 1.333 | Perfect Fourth | Editorial, blog | 12 / 16 / 21 / 28 / 37 / 50 / 67 |
137
+ | 1.414 | Augmented Fourth | Display-led | 12 / 17 / 24 / 34 / 48 / 67 / 95 |
138
+ | 1.618 | Golden | Hero / poster | 10 / 16 / 26 / 42 / 68 / 110 |
139
+
140
+ Line-height pairing (inverse to size): 12–14px → 1.5 · 16–18px → 1.5 ·
141
+ 20–24px → 1.35 · 28–40px → 1.2 · 48px+ → 1.1. Limit the scale to **6–9
142
+ deliberate steps**. More steps = chaos. Extra hierarchy comes from weight,
143
+ color, and spacing — not from new sizes.
144
+
145
+ ### Color contrast targets (WCAG 2.x + APCA secondary gate)
146
+
147
+ | Case | WCAG 2.x ratio | APCA Lc | Notes |
148
+ |---|---|---|---|
149
+ | Body text (<18pt regular / <14pt bold) | ≥ 4.5 (AA), ≥ 7 (AAA) | ≥ 75 | Reading-flow text |
150
+ | Large text (≥18pt or ≥14pt bold) | ≥ 3 (AA), ≥ 4.5 (AAA) | ≥ 60 | Headlines, large UI labels |
151
+ | UI components / focus indicator | ≥ 3 | ≥ 45 | Borders, icons, focus rings |
152
+ | Disabled / decorative text | exempt | Lc 30–45 | Still must be distinguishable |
153
+ | Placeholder text | ≥ 4.5 if treated as content | ≥ 60 | Many a11y audits flag low-contrast placeholders |
154
+
155
+ WCAG 2.x remains the legal requirement. **APCA is the secondary gate**: it
156
+ captures perceived legibility considering weight, polarity, and size, so a
157
+ project that satisfies WCAG can still have specific text-on-background pairs
158
+ that fail APCA — those are real readability bugs.
159
+
160
+ ### Spacing scale (base-4 vs base-8)
161
+
162
+ | Step | base-4 (px) | base-8 (px) | Typical use |
163
+ |---|---|---|---|
164
+ | 0 | 0 | 0 | reset |
165
+ | 1 | 4 | 8 | icon ↔ label inline |
166
+ | 2 | 8 | 16 | padding-x button sm |
167
+ | 3 | 12 | 24 | padding-x button md, gap between cards |
168
+ | 4 | 16 | 32 | section gap mobile |
169
+ | 5 | 24 | 48 | section gap desktop |
170
+ | 6 | 32 | 64 | hero spacing |
171
+ | 7 | 48 | 96 | landing section |
172
+ | 8 | 64 | 128 | landing hero |
173
+
174
+ **base-4** preferred for dense product UI (dashboards, IDE-like tools);
175
+ **base-8** preferred for marketing / editorial. **Never mix** the two scales
176
+ in the same product — pick one and derive every token from it. Arbitrary
177
+ values outside the scale (`padding: 13px`) are a token violation.
178
+
179
+ ### Density tiers
180
+
181
+ | Tier | Row height | Button md padding-y | Table cell padding | Primary use |
182
+ |---|---|---|---|---|
183
+ | Compact | 28–32px | 4–6px | 6–8px | Power user, data tables, IDE-like surfaces |
184
+ | Cozy | 36–40px | 8–10px | 10–12px | Default web app |
185
+ | Comfortable | 44–48px | 12–14px | 14–16px | Mobile primary, consumer surfaces |
186
+ | Spacious | 56–64px | 16–20px | 20–24px | Marketing, onboarding |
187
+
188
+ **Touch-primary surfaces must use Comfortable or above** (44px = WCAG 2.5.5
189
+ enhanced target). Mixing tiers within the same view is allowed only when the
190
+ information density genuinely demands it (e.g. compact data table inside a
191
+ cozy app shell) — document the exception in the registry.
192
+
193
+ ## Token Cascade: primitive → semantic → component
194
+
195
+ A mature token system has **three layers**, and components consume only the
196
+ top of the cascade:
197
+
198
+ 1. **Primitive tokens** — raw palette / scale values (`color-blue-500`,
199
+ `space-4`, `radius-md`). Stable, machine-generated, named by *what they
200
+ are*. Components must **never reference these directly**.
201
+ 2. **Semantic tokens** — purpose-named aliases (`color-action-primary`,
202
+ `color-surface-elevated`, `color-text-on-action`, `space-section-gap`).
203
+ Resolve to a primitive in the active theme. Named by *what they mean*.
204
+ The theming layer (light / dark / high-contrast / multi-brand) swaps
205
+ semantics → primitives — primitives themselves don't change per theme.
206
+ 3. **Component tokens** (optional) — per-component aliases when a primitive
207
+ appears in many components but a semantic is too generic
208
+ (`button-bg-primary`, `card-shadow-elevated`). Resolve to a semantic.
209
+
210
+ **Why it matters**: components written against semantic tokens become
211
+ theme-agnostic and multi-brand-ready by construction. A brand swap touches
212
+ the semantic-layer mapping only, not the component code. Dark mode is a
213
+ semantic-layer concern (different primitive mappings per theme), **never**
214
+ implemented via `filter: invert()` or naïve color flips — that produces
215
+ washed-out brights, inverted shadows, and inverted images.
216
+
217
+ When the project's `tokens-reference.md` doesn't yet expose a semantic
218
+ layer, propose adding one rather than letting components reach into
219
+ primitives — that drift is the entry door to inconsistent theming.
220
+
221
+ For palette *generation*, prefer **OKLCH** (or LCH) over HSL: it's
222
+ perceptually uniform, so equal lightness numbers across hues read as equal
223
+ brightness, dark/light variants stay tonally consistent, and palette steps
224
+ land at predictable contrast levels. HSL `lighten()` / `darken()` produces
225
+ visually uneven steps because HSL lightness is not perceptual.
226
+
227
+ ## Authority Matrix
228
+
229
+ `${paths.design_system}/INDEX.md` declares, for each primitive, who is
230
+ authoritative over which dimension:
231
+
232
+ - **Visual authority** — colors, spacing, shadows, radii: the registry +
233
+ tokens-reference. Agents/skills may not deviate.
234
+ - **Behavioral authority** — props, variants, accessibility hooks: the
235
+ per-component spec.
236
+ - **Composition authority** — how primitives are combined into patterns: the
237
+ pattern docs.
238
+
239
+ When a task would violate any of these authorities, the agent must:
240
+
241
+ 1. Stop and surface the conflict.
242
+ 2. Propose a registry update (new variant, new token, new pattern) instead of
243
+ bypassing the authority locally.
244
+
245
+ ## When a primitive is missing
246
+
247
+ If the cascade reaches step 3 or 4 (no registry hit, no source-tree hit), the
248
+ agent has two choices:
249
+
250
+ - **Add to the registry** — preferred when the primitive is broadly useful.
251
+ Create the per-component spec, the implementation under
252
+ `${paths.components_primitives}/<Name>`, and an INDEX.md entry in the same
253
+ change.
254
+ - **Local one-off** — only when the use case is genuinely surface-specific
255
+ (e.g. a marketing-page hero illustration). Even then, prefer composing
256
+ existing primitives over hand-rolling a new one. Justify the local choice
257
+ in the change description.
258
+
259
+ Never silently introduce a new component that overlaps with an existing
260
+ registry primitive — that is the exact failure mode this protocol prevents.
261
+
262
+ ## Post-Intervention Coherence Check (BLOCKING completion gate)
263
+
264
+ The BLOCKING pre-work above enforces *reads* before any UI change. This
265
+ section enforces *writes* before completion. **No UI task is considered
266
+ complete** when `features.has_design_system: true` until the registry has
267
+ been verified against the change that was just made.
268
+
269
+ The check runs at end-of-task by the agent that performed the work (`ui-expert`,
270
+ `ui-design`, `frontend-design`, `code-reviewer`). It is **not** delegated to
271
+ the weekly `ds-drift` routine — that routine is a safety net, not the primary
272
+ mechanism. Drift introduced today must be reconciled today, not next Monday.
273
+
274
+ ### What to verify
275
+
276
+ For each item in the diff that touched a visual surface, run these 4 checks:
277
+
278
+ 1. **New primitive ⇒ new spec**: did the change introduce a component under
279
+ `${paths.components_primitives}` that has no
280
+ `${paths.design_system}/components/<Name>.md`? If yes, the spec MUST ship
281
+ in the same change. Missing spec = `DS_INDEX_DRIFT` finding, task blocked.
282
+ 2. **Modified primitive ⇒ updated spec**: did the change alter a primitive's
283
+ props / variants / accessibility behavior? If yes, the corresponding
284
+ `components/<Name>.md` MUST be updated to match. Stale spec =
285
+ `DS_COMPONENT_STALE` finding, task blocked.
286
+ 3. **New / changed token ⇒ updated reference**: did the change introduce or
287
+ modify a token (color, spacing, shadow, radius, motion)? If yes,
288
+ `${paths.design_system}/tokens-reference.md` MUST reflect it. Stale
289
+ reference = `DS_TOKENS_DRIFT` finding, task blocked.
290
+ 4. **Surfaced silent primitive ⇒ added to INDEX**: during the work, did you
291
+ reuse a primitive that exists in the source tree but is **not** in
292
+ `INDEX.md`? If yes, add it to the INDEX in the same change (or open a
293
+ follow-up card if the registry entry requires design judgement beyond
294
+ the current scope). Silent primitive = `DS_INDEX_DRIFT` finding.
295
+
296
+ ### Decision matrix
297
+
298
+ | Situation | Action |
299
+ |---|---|
300
+ | Spec / token update is trivial (variant added, prop renamed, token value tweaked) | Apply inline — same commit as the code change |
301
+ | Spec / token update requires design judgement (new variant semantics, breaking change, accessibility decision) | Open a follow-up card; **document the gap explicitly** in the change description; flag for `code-reviewer` |
302
+ | Reused undocumented primitive that is broadly useful | Add INDEX entry inline; if a full spec needs design work, scaffold a stub spec marked `status: needs-review` |
303
+ | Reused undocumented primitive that is surface-specific | Add INDEX entry with `scope: local` and a 2-line note explaining why no full spec is needed |
304
+ | Introduced a primitive that **duplicates** an existing registry entry | **Stop**. This is the failure mode the cascade exists to prevent. Revert and reuse the existing primitive, or escalate to refactor the existing primitive if the new requirement is legitimately broader |
305
+
306
+ ### Reporting
307
+
308
+ When any of checks 1–4 trip, the agent must surface them explicitly to the
309
+ user before declaring task done — never silent. The recommended phrasing:
310
+
311
+ > Registry coherence check: <N> finding(s)
312
+ > - `DS_INDEX_DRIFT`: <Name> created without INDEX entry → resolved inline
313
+ > - `DS_COMPONENT_STALE`: <Name>.md not updated for variant `xyz` → follow-up CARD-NNNN opened
314
+ > - `DS_TOKENS_DRIFT`: `--color-action-secondary` added without tokens-reference entry → resolved inline
315
+
316
+ This makes drift **visible at the source of introduction**, which is the
317
+ only place it can be cheaply reconciled.
318
+
319
+ ### Interaction with the weekly routine
320
+
321
+ The `ds-drift` routine (`framework/routines/ds-drift.routine.yml`) still
322
+ runs weekly and catches what slips through (e.g. changes made by tools that
323
+ bypass the agents, or by humans editing directly). But the per-intervention
324
+ check above is **first-line**: if it fires correctly, the weekly routine
325
+ should find very little to report.
326
+
327
+ ## Bootstrap (when no registry exists)
328
+
329
+ If `features.has_design_system: false`:
330
+
331
+ - The BLOCKING reads above are skipped.
332
+ - Skills still respect `${paths.ui_guidelines}` and the project's existing
333
+ components under `${paths.components_primitives}`.
334
+ - Recommend `/design-system-init` to the user when the absence of a registry
335
+ is creating obvious drift (token hardcoding, duplicate primitives, divergent
336
+ styling across pages).
337
+
338
+ The `design-system-init` skill scaffolds `INDEX.md`, `tokens-reference.md`,
339
+ and a `components/<Name>.md` file for every primitive already in the codebase,
340
+ then flips `features.has_design_system: true` in `baldart.config.yml`.
341
+
342
+ ## Consumers of this protocol
343
+
344
+ The following files reference this module instead of duplicating its rules:
345
+
346
+ - `framework/.claude/agents/ui-expert.md`
347
+ - `framework/.claude/agents/code-reviewer.md`
348
+ - `framework/.claude/skills/ui-design/SKILL.md`
349
+ - `framework/.claude/skills/frontend-design/SKILL.md`
350
+ - `framework/.claude/skills/design-system-init/SKILL.md`
351
+ - `framework/.claude/commands/design-review.md`
352
+ - `framework/agents/design-review.md`
353
+
354
+ When changing the BLOCKING cascade, change it here — not in the consumers.
355
+
356
+ ## See also
357
+
358
+ - `framework/agents/project-context.md` — always-ask / never-assume contract
359
+ and the `baldart.config.yml` resolution flow.
360
+ - `framework/agents/design-review.md` — design-review workflow and report
361
+ template (uses this protocol's step 0).
362
+ - `framework/.claude/skills/design-system-init/SKILL.md` — bootstrap a
363
+ registry on a project that does not yet have one.