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.
- package/CHANGELOG.md +93 -0
- package/README.md +15 -3
- package/VERSION +1 -1
- package/framework/.claude/agents/REGISTRY.md +3 -3
- package/framework/.claude/agents/code-reviewer.md +47 -11
- package/framework/.claude/agents/codebase-architect.md +8 -0
- package/framework/.claude/agents/ui-expert.md +355 -43
- package/framework/.claude/commands/design-review.md +7 -0
- package/framework/.claude/skills/bug/SKILL.md +5 -1
- package/framework/.claude/skills/context-primer/SKILL.md +4 -0
- package/framework/.claude/skills/design-system-init/SKILL.md +232 -0
- package/framework/.claude/skills/design-system-init/scripts/component-spec.template.md +79 -0
- package/framework/.claude/skills/frontend-design/SKILL.md +124 -0
- package/framework/.claude/skills/lsp-bootstrap/SKILL.md +113 -0
- package/framework/.claude/skills/motion-design/reference/accessibility-and-modern-apis.md +114 -0
- package/framework/.claude/skills/new/SKILL.md +1 -1
- package/framework/.claude/skills/prd/SKILL.md +3 -1
- package/framework/.claude/skills/simplify/SKILL.md +6 -0
- package/framework/.claude/skills/ui-design/SKILL.md +43 -0
- package/framework/agents/code-search-protocol.md +126 -0
- package/framework/agents/design-review.md +51 -0
- package/framework/agents/design-system-protocol.md +363 -0
- package/framework/agents/index.md +4 -0
- package/framework/docs/LSP-LAYER.md +405 -0
- package/framework/docs/PROJECT-CONFIGURATION.md +17 -0
- package/framework/docs/UPGRADE-3.12-UI-COHERENCE.md +268 -0
- package/framework/templates/baldart.config.template.yml +22 -0
- package/framework/templates/overlays/agents/codebase-architect.lsp-example.md +53 -0
- package/package.json +1 -1
- package/src/commands/configure.js +69 -0
- package/src/commands/doctor.js +55 -0
- package/src/utils/lsp-adapters/go.js +29 -0
- package/src/utils/lsp-adapters/index.js +49 -0
- package/src/utils/lsp-adapters/python.js +42 -0
- package/src/utils/lsp-adapters/ruby.js +30 -0
- package/src/utils/lsp-adapters/rust.js +26 -0
- package/src/utils/lsp-adapters/typescript.js +54 -0
- 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.
|