loki-mode 6.75.3 → 6.76.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 (74) hide show
  1. package/SKILL.md +2 -2
  2. package/VERSION +1 -1
  3. package/autonomy/loki +659 -0
  4. package/dashboard/__init__.py +1 -1
  5. package/docs/INSTALLATION.md +1 -1
  6. package/mcp/__init__.py +1 -1
  7. package/mcp/magic_tools.py +471 -0
  8. package/mcp/server.py +13 -0
  9. package/package.json +1 -1
  10. package/references/magic-modules-patterns.md +634 -0
  11. package/skills/00-index.md +1 -0
  12. package/skills/magic-modules.md +205 -0
  13. package/web-app/dist/assets/{AdminPage-D4QSV6Zi.js → AdminPage-DwVUK4v9.js} +1 -1
  14. package/web-app/dist/assets/{Avatar-88MlpLO5.js → Avatar-B7gqhcg3.js} +1 -1
  15. package/web-app/dist/assets/{Badge-DbGjLr4i.js → Badge-DA3xNJAS.js} +1 -1
  16. package/web-app/dist/assets/{Button-sp_FVGZj.js → Button-BPXURLaK.js} +1 -1
  17. package/web-app/dist/assets/{ComparePage-p2ENnfa7.js → ComparePage-B0JQMhKG.js} +1 -1
  18. package/web-app/dist/assets/GitHubIssuesPanel-D38-fy29.js +12 -0
  19. package/web-app/dist/assets/{GitHubPRsPanel-Bi_yrcAE.js → GitHubPRsPanel-DLPcW3N0.js} +2 -2
  20. package/web-app/dist/assets/{HomePage-BB83YPiX.js → HomePage-CzeoS2V_.js} +3 -3
  21. package/web-app/dist/assets/{LoginPage-BXUudCJ9.js → LoginPage-DqCzxsfx.js} +1 -1
  22. package/web-app/dist/assets/MagicPage-CBLqpa55.js +31 -0
  23. package/web-app/dist/assets/{MetricsPage-CX0Ahy-_.js → MetricsPage-CPYQR0zr.js} +1 -1
  24. package/web-app/dist/assets/{NotFoundPage-C4JqatEk.js → NotFoundPage-B62u4iCs.js} +1 -1
  25. package/web-app/dist/assets/{ProjectPage-t5J2XAJT.js → ProjectPage-DNujSl6j.js} +67 -72
  26. package/web-app/dist/assets/{ProjectsPage-Bzpz1clk.js → ProjectsPage-uHG7kxB-.js} +1 -1
  27. package/web-app/dist/assets/{SettingsPage-y_yl8FvH.js → SettingsPage-BaQJbOgL.js} +1 -1
  28. package/web-app/dist/assets/{ShowcasePage-B7d6pzMq.js → ShowcasePage-DQR_e-kg.js} +1 -1
  29. package/web-app/dist/assets/{SystemSettingsPage-C4tR33KU.js → SystemSettingsPage-C_Q_1WK4.js} +1 -1
  30. package/web-app/dist/assets/{TeamsPage-DIOCfZIP.js → TeamsPage-DOFErDqX.js} +1 -1
  31. package/web-app/dist/assets/{TemplatesPage-DlKyapXX.js → TemplatesPage-Ty72hILN.js} +1 -1
  32. package/web-app/dist/assets/{TerminalOutput-Czg-ZC2k.js → TerminalOutput-DqOVnR1p.js} +7 -12
  33. package/web-app/dist/assets/{activity-h1wU9a0L.js → activity-BgBZ4s4c.js} +1 -1
  34. package/web-app/dist/assets/{bell-Bu8lsWOp.js → bell-C-UezVWi.js} +1 -1
  35. package/web-app/dist/assets/{bot-rWO7KjkQ.js → bot-D70fEnm5.js} +1 -1
  36. package/web-app/dist/assets/{check-BWp8L5Cy.js → check-CBohulxQ.js} +1 -1
  37. package/web-app/dist/assets/{chevron-left-Bw4I1yGm.js → chevron-left-C-emzUhB.js} +1 -1
  38. package/web-app/dist/assets/{circle-alert-C37PKXiC.js → circle-alert-8SRY0_GX.js} +1 -1
  39. package/web-app/dist/assets/{clock-DDScLol4.js → clock-mfq4XnPQ.js} +1 -1
  40. package/web-app/dist/assets/{cloud-DaYKPLaM.js → cloud-DpRM7T8t.js} +1 -1
  41. package/web-app/dist/assets/code-xml-1N2Ui-4c.js +6 -0
  42. package/web-app/dist/assets/{copy-DKIRv0VK.js → copy-LXquTgzI.js} +1 -1
  43. package/web-app/dist/assets/{database-CYZBHz51.js → database-S1dyXnuT.js} +1 -1
  44. package/web-app/dist/assets/{dollar-sign-CydJu0kl.js → dollar-sign-CRqk0dW5.js} +1 -1
  45. package/web-app/dist/assets/{file-code-corner-DqZ9gpdv.js → file-code-corner-B99CwY_6.js} +1 -1
  46. package/web-app/dist/assets/{file-plus-CzeFJWp3.js → file-plus-DZ5qnz5b.js} +1 -1
  47. package/web-app/dist/assets/{folder-open-4YWk08dP.js → folder-open-DBCm7yuF.js} +1 -1
  48. package/web-app/dist/assets/{git-commit-horizontal-wbqFPNID.js → git-commit-horizontal-DM1ERuNd.js} +1 -1
  49. package/web-app/dist/assets/{globe-Cby-g5Yb.js → globe-B7xEJSL_.js} +1 -1
  50. package/web-app/dist/assets/{hammer-BNScgGdp.js → hammer-Cgi3LTuS.js} +1 -1
  51. package/web-app/dist/assets/{index-6Z4B0I6r.js → index-BN52-GQT.js} +22 -17
  52. package/web-app/dist/assets/index-BfZSDej1.css +1 -0
  53. package/web-app/dist/assets/{layers-XfssQc5V.js → layers-Bi8RPIBC.js} +1 -1
  54. package/web-app/dist/assets/{lightbulb-EhnzRw7M.js → lightbulb-Doc_n8JX.js} +1 -1
  55. package/web-app/dist/assets/{loader-circle-BA0QIVGA.js → loader-circle-BB932A7A.js} +1 -1
  56. package/web-app/dist/assets/{lock-BABtHe6K.js → lock-Bt6gpMrs.js} +1 -1
  57. package/web-app/dist/assets/{mail-Dokiey5S.js → mail-BuzAu1IP.js} +1 -1
  58. package/web-app/dist/assets/{package-DbJyS1Ft.js → package-BE5FHxQ8.js} +1 -1
  59. package/web-app/dist/assets/{plus-BcAN8Kaj.js → plus-CNqABexN.js} +1 -1
  60. package/web-app/dist/assets/{refresh-cw-B3dG1-Sb.js → refresh-cw-34B13ztx.js} +1 -1
  61. package/web-app/dist/assets/{rotate-ccw-Cs1Phctm.js → rotate-ccw-CrD2QB29.js} +1 -1
  62. package/web-app/dist/assets/{save-DsrNCZrP.js → save-DsJcqdnI.js} +1 -1
  63. package/web-app/dist/assets/{server-CpN2GX4G.js → server-BcgRMArA.js} +1 -1
  64. package/web-app/dist/assets/{shield-alert-CKJ1pzCz.js → shield-alert-DLYLdVJ0.js} +1 -1
  65. package/web-app/dist/assets/{trash-2-C9vZqTqw.js → trash-2-Cc-VTvzt.js} +1 -1
  66. package/web-app/dist/assets/{trending-down-BNLTrF5P.js → trending-down-CrDpO2a_.js} +1 -1
  67. package/web-app/dist/assets/{trending-up-DmFIdVOc.js → trending-up-CNVsmM3G.js} +1 -1
  68. package/web-app/dist/assets/upload-LuDuB7Wc.js +6 -0
  69. package/web-app/dist/assets/{usePolling-vUlY-o6P.js → usePolling-C8rvc-CG.js} +1 -1
  70. package/web-app/dist/assets/{user-Dh00W8De.js → user-BT79cI-o.js} +1 -1
  71. package/web-app/dist/index.html +2 -2
  72. package/web-app/server.py +120 -0
  73. package/web-app/dist/assets/GitHubIssuesPanel-DBbBTG9w.js +0 -17
  74. package/web-app/dist/assets/index-CVM4A1Fw.css +0 -1
@@ -0,0 +1,634 @@
1
+ # Magic Modules Patterns Reference
2
+
3
+ Detailed reference for the Magic Modules system: spec format, freshness protocol, debate protocol, registry schema, design tokens, MCP tools, worked examples, and troubleshooting.
4
+
5
+ ---
6
+
7
+ ## 1. Origin and Credits
8
+
9
+ Magic Modules is an adaptation of two Google Labs experiments. The spec format, the debate protocol, and the integration with Loki Mode's RARV cycle are re-implemented for this codebase. Credit for the underlying ideas belongs to the original authors.
10
+
11
+ | Project | Author | Contribution | Link |
12
+ |---------|--------|--------------|------|
13
+ | MagicModules | Roman Nurik (Google Labs) | Spec-first component generation, markdown specs as source of truth, SHA-based freshness check, single-source registry | [github.com/romannurik/MagicModules](https://github.com/romannurik/MagicModules) |
14
+ | MoMoA | Reto Meier (Google Labs) | Multi-persona debate, conflicting expert critique, consensus with HITL escalation | [github.com/retomeier/momoa](https://github.com/retomeier/momoa) |
15
+
16
+ This adaptation is not a copy. Differences from the originals:
17
+
18
+ - Specs are stored per project in `.loki/magic/specs/` rather than a global registry
19
+ - Generation supports both React and Web Components (the originals target one stack at a time)
20
+ - Debate integrates with Loki's HITL system and dashboard notifications
21
+ - Registry entries participate in the Loki knowledge graph and memory consolidation
22
+
23
+ ---
24
+
25
+ ## 2. Spec Format Reference
26
+
27
+ Specs are authored in Markdown with a YAML front matter block. The spec is the source of truth -- the implementation is a derived artifact.
28
+
29
+ ### Template
30
+
31
+ ```markdown
32
+ ---
33
+ name: Button
34
+ target: both # react | webcomponent | both
35
+ version: 1
36
+ tags: [form, action, primary]
37
+ design_tokens:
38
+ color_primary: token.color.accent
39
+ radius: token.radius.md
40
+ font: token.font.body
41
+ a11y_level: AA # A | AA | AAA
42
+ stability: stable # experimental | beta | stable
43
+ owner: team-ui
44
+ ---
45
+
46
+ # Button
47
+
48
+ ## Purpose
49
+ A primary action trigger. Used when a user needs to commit to a single most-important action on a screen.
50
+
51
+ ## Props
52
+ | Name | Type | Default | Description |
53
+ |------|------|---------|-------------|
54
+ | `label` | string | required | Visible label text |
55
+ | `onClick` | function | required | Handler for activation |
56
+ | `variant` | 'primary' \| 'secondary' \| 'ghost' | 'primary' | Visual weight |
57
+ | `loading` | boolean | false | Shows spinner, disables click |
58
+ | `disabled` | boolean | false | Non-interactive state |
59
+ | `iconLeft` | ReactNode \| slot | null | Optional leading icon |
60
+
61
+ ## Behavior
62
+ - Click or Enter or Space activates the button
63
+ - While `loading` is true, clicks are suppressed and a spinner replaces `iconLeft`
64
+ - `disabled` sets `aria-disabled=true` and blocks pointer events
65
+ - The component never manages its own loading state -- it is controlled via the `loading` prop
66
+
67
+ ## Accessibility
68
+ - Uses a native `<button>` element (React) or `role="button"` (WC)
69
+ - Focus ring is visible and uses `token.color.focus`
70
+ - `loading` announces via `aria-busy=true`
71
+ - `disabled` uses `aria-disabled` rather than the `disabled` attribute to keep focus reachable
72
+
73
+ ## Visual
74
+ - Height: token.spacing.height.md
75
+ - Padding: token.spacing.x.md
76
+ - Radius: token.radius.md
77
+ - Primary variant uses token.color.accent on token.color.accent-contrast
78
+ - Transitions respect `prefers-reduced-motion`
79
+
80
+ ## Test Expectations
81
+ - Renders the label
82
+ - Calls onClick on click, Enter, and Space
83
+ - Does not call onClick when `loading` or `disabled`
84
+ - Announces busy state to screen readers when loading
85
+ - Focus ring visible when keyboard-focused
86
+
87
+ ## Notes
88
+ <!-- Free-form notes for downstream maintainers -->
89
+ ```
90
+
91
+ ### Spec Authoring Rules
92
+
93
+ 1. The YAML block is required. Missing fields fail the generation gate.
94
+ 2. The `## Props` table drives TypeScript types. Column order is fixed: name, type, default, description.
95
+ 3. Any token reference must be of the form `token.*` and must resolve through the token resolution order.
96
+ 4. The `a11y_level` field is consumed by the A11y Advocate persona to calibrate severity.
97
+ 5. Free-form `## Notes` sections are preserved in the generated file as a header comment block for maintainers.
98
+
99
+ ---
100
+
101
+ ## 3. Freshness Protocol
102
+
103
+ Every spec has a content hash. Every generated file carries that hash. Regeneration is a function of equality.
104
+
105
+ ### Hash Computation
106
+
107
+ ```
108
+ spec_hash = sha256(
109
+ normalize(front_matter_yaml) + "\n" +
110
+ strip_comments(markdown_body) + "\n" +
111
+ serialize(resolved_tokens)
112
+ )[:12]
113
+ ```
114
+
115
+ Normalization removes whitespace differences and sorts map keys so cosmetic edits don't trigger regeneration. Token resolution is included so a token change invalidates dependents.
116
+
117
+ ### Header Marker
118
+
119
+ Every generated file begins with:
120
+
121
+ ```typescript
122
+ // LOKI-MAGIC-HASH: a1b2c3d4e5f6
123
+ // Component: Button (target=react, spec version=1)
124
+ // Generated by loki magic on 2026-04-18T10:00:00Z
125
+ // Do not edit directly. Edit .loki/magic/specs/Button.md and run `loki magic update`.
126
+ ```
127
+
128
+ For Web Components:
129
+
130
+ ```javascript
131
+ /* LOKI-MAGIC-HASH: a1b2c3d4e5f6
132
+ Component: Button (target=webcomponent, spec version=1)
133
+ Generated by loki magic on 2026-04-18T10:00:00Z
134
+ Do not edit directly. Edit .loki/magic/specs/Button.md and run `loki magic update`. */
135
+ ```
136
+
137
+ ### Regeneration Triggers
138
+
139
+ A component is stale when any of the following is true:
140
+
141
+ | Condition | Action |
142
+ |-----------|--------|
143
+ | File hash marker != registry hash | Regenerate |
144
+ | File missing but registry entry exists | Regenerate |
145
+ | Registry entry missing but spec exists | Create registry entry and generate |
146
+ | Spec removed but file exists | Warn and list as orphan; do not auto-delete |
147
+ | Token referenced by spec changed | Regenerate all specs using that token |
148
+
149
+ ### Forcing Regeneration
150
+
151
+ ```bash
152
+ # Force all components regardless of freshness
153
+ loki magic update --force
154
+
155
+ # Force a specific component
156
+ loki magic update --only Button --force
157
+
158
+ # Regenerate only stale components (default behavior)
159
+ loki magic update
160
+ ```
161
+
162
+ ---
163
+
164
+ ## 4. Debate Protocol
165
+
166
+ Debate is the quality gate for generated code. It runs after generation and before the code is committed to the repository.
167
+
168
+ ### Structure
169
+
170
+ ```
171
+ Round 1: Initial critique
172
+ Each persona independently reviews the generated code.
173
+ Output: per-persona critique with severity (info | warn | block)
174
+
175
+ Round 2: Cross-response
176
+ Each persona reads the other personas' critiques and responds.
177
+ May concede, counter-argue, or flag contradictions.
178
+ Output: per-persona response + adjusted severity
179
+
180
+ Round 3: Proposal
181
+ Personas converge on a merged set of changes or declare deadlock.
182
+ Output: unified diff OR escalation notice
183
+ ```
184
+
185
+ ### Persona Prompts
186
+
187
+ All persona prompts share a common header that includes the spec, the generated code, prior round outputs, and the project design tokens. The persona-specific body follows:
188
+
189
+ #### Creative Developer
190
+
191
+ > You care about UX polish, delight, and modern patterns. Look for missed opportunities: missing hover states, abrupt transitions, unclear affordances, inconsistent motion curves. You value taste. Severity is `warn` unless the issue creates an immediate UX failure (e.g., a control the user cannot discover), in which case `block`.
192
+
193
+ #### Conservative Engineer
194
+
195
+ > You care about stability, conventions, edge cases, and backwards compatibility. Look for untyped props, missing error boundaries, hidden state, implicit coupling, race conditions, and cases where a component controls state it should accept as a prop. Severity is `block` for type safety violations, missing required error handling, or breaking changes to a stable component.
196
+
197
+ #### A11y Advocate
198
+
199
+ > You care about WCAG 2.1 AA compliance and assistive tech. Verify: semantic HTML, keyboard operation, focus order, visible focus indicators, sufficient color contrast, aria labels on icon-only controls, aria-live for dynamic regions, reduced-motion support. Severity follows the spec's `a11y_level` field: AA -> block on AA failures, AAA -> block on AAA failures, A -> block only on A failures.
200
+
201
+ #### Performance Engineer
202
+
203
+ > You care about bundle size, render cost, reflows, and network. Flag: unbounded lists without virtualization, inline object/function props that defeat memoization, synchronous layout reads during render, unnecessary re-renders, large imports (check bundle impact), missing lazy boundaries. Severity is `warn` for small components (<100 LOC), `block` for render-hot components (lists, tables, dashboards).
204
+
205
+ ### Consensus Rules
206
+
207
+ | Round 3 Outcome | Action |
208
+ |-----------------|--------|
209
+ | All personas agree on diff | Apply diff; component passes debate |
210
+ | Majority agrees, minority concedes | Apply diff; record minority's `info` notes |
211
+ | Split vote, no block | Apply diff that resolves all `warn` items; leave `info` items as code comments |
212
+ | Any unresolved `block` | Escalate to HITL |
213
+ | Personas contradict each other and cannot reconcile | Escalate to HITL |
214
+
215
+ ### HITL Escalation
216
+
217
+ When debate deadlocks:
218
+
219
+ 1. A dashboard notification is raised with the debate transcript
220
+ 2. The component is marked `status: debate_blocked` in the registry
221
+ 3. The regeneration is not applied; the previous implementation remains
222
+ 4. The user resolves by either editing the spec (changes the hash, triggers a new debate) or manually overriding via `loki magic debate <name> --accept round-3`
223
+
224
+ ### Debate Persistence
225
+
226
+ Every debate transcript is written to `.loki/magic/debates/<component>-<hash>.json`:
227
+
228
+ ```json
229
+ {
230
+ "component": "Button",
231
+ "spec_hash": "a1b2c3d4e5f6",
232
+ "started_at": "2026-04-18T10:00:00Z",
233
+ "completed_at": "2026-04-18T10:01:23Z",
234
+ "rounds": [
235
+ {"round": 1, "personas": { "creative": {...}, "conservative": {...}, "a11y": {...}, "performance": {...} }},
236
+ {"round": 2, "personas": { ... }},
237
+ {"round": 3, "outcome": "consensus", "diff": "..."}
238
+ ],
239
+ "final_severity": "warn",
240
+ "applied": true
241
+ }
242
+ ```
243
+
244
+ Debate transcripts participate in episodic memory so the system can surface prior rationale when a similar component is generated later.
245
+
246
+ ---
247
+
248
+ ## 5. Registry Schema
249
+
250
+ `.loki/magic/registry.json` is the single source of truth for what components exist, what their freshness state is, and what targets they support.
251
+
252
+ ### Top-Level Shape
253
+
254
+ ```json
255
+ {
256
+ "version": 1,
257
+ "updated_at": "2026-04-18T10:00:00Z",
258
+ "components": {
259
+ "Button": { ... },
260
+ "PricingCard": { ... }
261
+ },
262
+ "orphans": [
263
+ "generated/react/UnusedThing.tsx"
264
+ ]
265
+ }
266
+ ```
267
+
268
+ ### Component Entry
269
+
270
+ ```json
271
+ {
272
+ "name": "Button",
273
+ "spec_path": ".loki/magic/specs/Button.md",
274
+ "spec_hash": "a1b2c3d4e5f6",
275
+ "spec_version": 1,
276
+ "targets": ["react", "webcomponent"],
277
+ "generated": {
278
+ "react": {
279
+ "path": ".loki/magic/generated/react/Button.tsx",
280
+ "hash": "a1b2c3d4e5f6",
281
+ "generated_at": "2026-04-18T10:00:00Z"
282
+ },
283
+ "webcomponent": {
284
+ "path": ".loki/magic/generated/webcomponent/Button.js",
285
+ "hash": "a1b2c3d4e5f6",
286
+ "generated_at": "2026-04-18T10:00:00Z"
287
+ }
288
+ },
289
+ "tests": {
290
+ "react": ".loki/magic/generated/tests/Button.test.tsx",
291
+ "webcomponent": ".loki/magic/generated/tests/Button.spec.ts"
292
+ },
293
+ "snapshots": [
294
+ ".loki/magic/snapshots/Button--primary.png",
295
+ ".loki/magic/snapshots/Button--secondary.png",
296
+ ".loki/magic/snapshots/Button--loading.png"
297
+ ],
298
+ "tags": ["form", "action", "primary"],
299
+ "a11y_level": "AA",
300
+ "stability": "stable",
301
+ "owner": "team-ui",
302
+ "last_debate": {
303
+ "hash": "a1b2c3d4e5f6",
304
+ "outcome": "consensus",
305
+ "severity": "warn",
306
+ "transcript": ".loki/magic/debates/Button-a1b2c3d4e5f6.json"
307
+ },
308
+ "hotspot_score": 0.23,
309
+ "co_change_with": ["Icon", "Spinner"]
310
+ }
311
+ ```
312
+
313
+ ### Field Reference
314
+
315
+ | Field | Type | Purpose |
316
+ |-------|------|---------|
317
+ | `spec_hash` | string(12) | Current spec content hash |
318
+ | `spec_version` | int | Bumped manually when breaking spec changes occur |
319
+ | `targets` | string[] | Which stacks this component supports |
320
+ | `generated.<target>.hash` | string(12) | Hash of the spec that generated this file |
321
+ | `tags` | string[] | Free-form tags for filtering in `loki magic list` |
322
+ | `a11y_level` | enum | Drives A11y persona severity |
323
+ | `stability` | enum | `experimental` skips some debate rounds; `stable` runs full debate |
324
+ | `last_debate` | object | Reference to the most recent debate transcript |
325
+ | `hotspot_score` | float | Derived from git history; drives extra debate rounds |
326
+ | `co_change_with` | string[] | Components that historically change in the same commit |
327
+
328
+ ### Freshness Check Logic
329
+
330
+ ```
331
+ for component in registry.components:
332
+ for target in component.targets:
333
+ file = component.generated[target]
334
+ if not exists(file.path):
335
+ mark_stale(component, reason="file_missing")
336
+ elif read_hash_header(file.path) != component.spec_hash:
337
+ mark_stale(component, reason="hash_mismatch")
338
+ elif file.hash != component.spec_hash:
339
+ mark_stale(component, reason="registry_drift")
340
+ ```
341
+
342
+ ---
343
+
344
+ ## 6. Design Token System
345
+
346
+ Design tokens are the shared vocabulary that keeps generated components visually consistent with the rest of the Loki surfaces.
347
+
348
+ ### Token File Shape
349
+
350
+ `.loki/magic/tokens.json`:
351
+
352
+ ```json
353
+ {
354
+ "color": {
355
+ "accent": "#6d28d9",
356
+ "accent-contrast": "#ffffff",
357
+ "focus": "#a78bfa",
358
+ "text-primary": "#111827",
359
+ "surface": "#ffffff"
360
+ },
361
+ "spacing": {
362
+ "x": { "sm": "0.5rem", "md": "1rem", "lg": "1.5rem" },
363
+ "y": { "sm": "0.25rem", "md": "0.5rem", "lg": "0.75rem" },
364
+ "height": { "sm": "1.75rem", "md": "2.25rem", "lg": "2.75rem" }
365
+ },
366
+ "radius": {
367
+ "sm": "0.25rem",
368
+ "md": "0.375rem",
369
+ "lg": "0.5rem",
370
+ "full": "9999px"
371
+ },
372
+ "font": {
373
+ "body": "system-ui, -apple-system, sans-serif",
374
+ "mono": "ui-monospace, SFMono-Regular, monospace"
375
+ },
376
+ "motion": {
377
+ "fast": "120ms",
378
+ "base": "200ms",
379
+ "slow": "320ms",
380
+ "ease-standard": "cubic-bezier(0.4, 0, 0.2, 1)"
381
+ }
382
+ }
383
+ ```
384
+
385
+ ### Resolution Order
386
+
387
+ 1. Spec-local overrides (in the YAML front matter under `design_tokens:`)
388
+ 2. Project overrides (`.loki/magic/tokens.json`)
389
+ 3. Extracted defaults (computed by `loki magic tokens extract`)
390
+ 4. Built-in Loki defaults (shipped with the CLI)
391
+
392
+ ### Extraction
393
+
394
+ `loki magic tokens extract` scans:
395
+
396
+ - `web-app/src/` and `dashboard-ui/` for Tailwind config and CSS variables
397
+ - `web-app/src/**/*.css` for `:root` declarations
398
+ - Existing React components for recurring inline style values
399
+
400
+ It prefers the most frequent values and writes them to `.loki/magic/tokens.json` with a `source: extracted` marker so subsequent edits are not clobbered.
401
+
402
+ ---
403
+
404
+ ## 7. MCP Tool Reference
405
+
406
+ `mcp/magic_tools.py` exposes seven tools. Each signature, input schema, and return schema is documented below.
407
+
408
+ ### `magic_generate`
409
+
410
+ Generate a new component from a description or a reference to a screenshot.
411
+
412
+ ```python
413
+ magic_generate(
414
+ name: str,
415
+ description: str | None = None,
416
+ target: Literal["react", "webcomponent", "both"] = "both",
417
+ from_image: str | None = None, # absolute path to a PNG/JPG
418
+ tags: list[str] = [],
419
+ run_debate: bool = True,
420
+ ) -> {
421
+ "component": str,
422
+ "spec_path": str,
423
+ "generated": dict[str, str],
424
+ "debate_outcome": "consensus" | "warn" | "blocked" | "skipped"
425
+ }
426
+ ```
427
+
428
+ ### `magic_update`
429
+
430
+ Regenerate stale components.
431
+
432
+ ```python
433
+ magic_update(
434
+ only: list[str] | None = None, # names; default all
435
+ force: bool = False,
436
+ run_debate: bool = True,
437
+ ) -> {
438
+ "regenerated": list[str],
439
+ "skipped": list[str],
440
+ "blocked": list[str]
441
+ }
442
+ ```
443
+
444
+ ### `magic_list`
445
+
446
+ List registry entries.
447
+
448
+ ```python
449
+ magic_list(
450
+ target: str | None = None,
451
+ tag: str | None = None,
452
+ stale_only: bool = False,
453
+ ) -> list[dict]
454
+ ```
455
+
456
+ ### `magic_debate`
457
+
458
+ Run a debate on an existing component.
459
+
460
+ ```python
461
+ magic_debate(
462
+ name: str,
463
+ rounds: int = 3,
464
+ personas: list[str] | None = None, # default: all four
465
+ accept: str | None = None, # "round-2" or "round-3" to force-accept
466
+ ) -> {
467
+ "outcome": "consensus" | "warn" | "blocked",
468
+ "transcript_path": str,
469
+ "applied": bool
470
+ }
471
+ ```
472
+
473
+ ### `magic_registry_stats`
474
+
475
+ Return registry health counters.
476
+
477
+ ```python
478
+ magic_registry_stats() -> {
479
+ "total": int,
480
+ "by_target": dict[str, int],
481
+ "stale": int,
482
+ "orphans": int,
483
+ "debate_blocked": int,
484
+ "last_updated": str
485
+ }
486
+ ```
487
+
488
+ ### `magic_tokens_extract`
489
+
490
+ Extract design tokens from the codebase.
491
+
492
+ ```python
493
+ magic_tokens_extract(
494
+ sources: list[str] | None = None, # default: web-app/src, dashboard-ui
495
+ overwrite: bool = False,
496
+ ) -> {
497
+ "tokens_written": int,
498
+ "path": str
499
+ }
500
+ ```
501
+
502
+ ### `magic_snapshot`
503
+
504
+ Capture a visual regression snapshot.
505
+
506
+ ```python
507
+ magic_snapshot(
508
+ name: str,
509
+ variants: list[str] | None = None, # default: all variants in spec
510
+ ) -> {
511
+ "snapshots": list[str]
512
+ }
513
+ ```
514
+
515
+ ---
516
+
517
+ ## 8. Worked Examples
518
+
519
+ ### Example 1: Generating a simple Button component
520
+
521
+ ```bash
522
+ loki magic generate Button \
523
+ --target both \
524
+ --description "Primary action button with label, loading state, and optional leading icon"
525
+ ```
526
+
527
+ What happens:
528
+
529
+ 1. The CLI writes `.loki/magic/specs/Button.md` using the spec template. The description is fed to Sonnet to produce the Props table, Behavior, Accessibility, and Visual sections.
530
+ 2. Spec hash is computed. Registry entry is created.
531
+ 3. Generation runs for both `react` and `webcomponent` targets in parallel.
532
+ 4. Vitest and Playwright test files are produced under `.loki/magic/generated/tests/`.
533
+ 5. A four-persona debate runs. Result: `consensus` with two `warn` items (contrast on ghost variant, missing reduced-motion guard).
534
+ 6. Debate diff is applied. Final files committed to the registry.
535
+
536
+ Result structure:
537
+
538
+ ```
539
+ .loki/magic/
540
+ specs/Button.md
541
+ generated/react/Button.tsx
542
+ generated/webcomponent/Button.js
543
+ generated/tests/Button.test.tsx
544
+ generated/tests/Button.spec.ts
545
+ debates/Button-a1b2c3d4e5f6.json
546
+ registry.json (updated)
547
+ ```
548
+
549
+ ### Example 2: Generating from a screenshot (Claude Vision path)
550
+
551
+ ```bash
552
+ loki magic generate PricingCard \
553
+ --target react \
554
+ --from-image ./mockups/pricing.png \
555
+ --tags marketing billing
556
+ ```
557
+
558
+ What happens:
559
+
560
+ 1. Claude Vision analyzes the image. The output is a structured description: visual elements, their hierarchy, text content, and inferred layout.
561
+ 2. The structured description is converted into a spec. Design tokens are chosen from the nearest matches in the token file.
562
+ 3. The user is shown the generated spec for review before generation proceeds. The user may edit the spec; the hash is recomputed.
563
+ 4. Generation, test creation, and debate proceed as in Example 1.
564
+
565
+ Notes:
566
+
567
+ - Vision extraction is a best-effort starting point. The spec is meant to be edited.
568
+ - Only images that pass a sanity check (readable text, identifiable controls) are accepted; otherwise the user is prompted to provide a description.
569
+
570
+ ### Example 3: Running a debate on a complex component
571
+
572
+ ```bash
573
+ loki magic debate DataTable --rounds 3
574
+ ```
575
+
576
+ What happens:
577
+
578
+ 1. The latest generated files for `DataTable` are loaded along with the current spec.
579
+ 2. Round 1: each persona produces an independent critique. Performance Engineer flags unbounded row rendering. A11y Advocate flags missing row-group semantics. Conservative Engineer flags an implicit dependency on the parent container's width.
580
+ 3. Round 2: Creative Developer concedes on the a11y point; Performance Engineer proposes virtualization.
581
+ 4. Round 3: personas converge on a diff adding `react-virtuoso` for rows, `role="rowgroup"` wrappers, and an explicit `width` prop.
582
+ 5. Diff is applied. A new generated file is written with a new hash. The registry is updated. The transcript is persisted.
583
+
584
+ If the A11y Advocate had flagged a `block`-severity contrast failure and no persona proposed a fix, the component would be marked `debate_blocked` and HITL would be requested.
585
+
586
+ ---
587
+
588
+ ## 9. Troubleshooting
589
+
590
+ | Symptom | Likely Cause | Fix |
591
+ |---------|-------------|-----|
592
+ | `LOKI-MAGIC-HASH` header missing | File edited manually or created outside the generator | Restore the header or regenerate with `loki magic update --only <name> --force` |
593
+ | Regeneration keeps triggering | Token file churn or whitespace differences in spec | Run `loki magic tokens extract --overwrite` once to stabilize; review spec for comment noise |
594
+ | Debate escalates every time | Spec is under-specified in a way that makes one persona block | Expand the Accessibility or Behavior section with explicit choices |
595
+ | Orphan listed in registry | Generated file has no matching spec | Either delete the file or restore its spec from git history |
596
+ | Generated component does not match codebase style | Tokens not extracted or overridden | Run `loki magic tokens extract`, then `loki magic update --force` |
597
+ | `magic_generate` returns `blocked` | Round 3 deadlock | Inspect `.loki/magic/debates/<component>-<hash>.json`; resolve by editing the spec or `--accept round-3` |
598
+ | React and WC variants drift | Spec was edited after only one target regenerated | Run `loki magic update --only <name>` to rebuild all declared targets |
599
+ | Registry stats show many stale | Token change invalidated many specs | Run `loki magic update` to regenerate all dependents |
600
+ | Spec version bumped but hash unchanged | Manual version bump without content edit | Add a meaningful change, or leave the version unchanged |
601
+ | Tests fail after regeneration | Generated tests reflect new behavior the spec describes | Update the consuming code to match the new API, or revise the spec to preserve old behavior |
602
+
603
+ ---
604
+
605
+ ## 10. Comparison to Competitors
606
+
607
+ Magic Modules fills the visual-component-generation gap in Loki Mode. The table below compares the approach to adjacent tools.
608
+
609
+ | Tool | Spec-First | Multi-Persona Debate | Design Tokens | Dual Target (React + WC) | Registry with Freshness | Open Source |
610
+ |------|-----------|---------------------|---------------|-------------------------|------------------------|-------------|
611
+ | **Loki Magic Modules** | Yes | Yes (4 personas) | Yes (extracted + overridable) | Yes | Yes (SHA hashes) | Yes |
612
+ | MagicModules (Nurik) | Yes | No | Partial | React only | Yes | Yes |
613
+ | MoMoA (Meier) | No (code-first) | Yes | No | React only | No | Yes |
614
+ | Replit Agent Design Canvas | Visual canvas | No | Partial | React only | No | No |
615
+ | bolt.new Visual Inspector | No (prompt-first) | No | No | React only | No | No |
616
+ | Cursor Compose | No | No | No | Depends on user | No | No |
617
+ | v0 by Vercel | Prompt-first, editable preview | No | Partial | React only | No | Partial (hosted) |
618
+
619
+ Key differentiators:
620
+
621
+ - **Spec-first with debate** is unique. Other tools are either spec-first without critique, or code-first without a durable spec.
622
+ - **Dual target generation** means a single spec can produce both a React component for the dashboard and a Web Component for Purple Lab.
623
+ - **Registry with freshness** lets the system detect drift and regenerate automatically, which none of the prompt-first competitors offer.
624
+ - **Deep integration with RARV and quality gates** means generated components participate in the same review lifecycle as hand-written code.
625
+
626
+ ---
627
+
628
+ ## See Also
629
+
630
+ - `skills/magic-modules.md` -- skill module loaded by agents when the task matches magic-modules triggers
631
+ - `skills/healing.md` -- hook patterns that protect generated files from silent manual edits
632
+ - `skills/documentation.md` -- how component specs feed into generated documentation
633
+ - `references/memory-system.md` -- how debate transcripts become episodic memory
634
+ - `references/quality-control.md` -- how debate relates to the broader code review pool
@@ -30,6 +30,7 @@
30
30
  | OpenSpec delta context, brownfield modifications | `openspec-integration.md` |
31
31
  | MiroFish market validation, `--mirofish` flag | `mirofish-integration.md` |
32
32
  | Writing/updating documentation, `loki docs` | `documentation.md` |
33
+ | Component generation, `loki magic`, spec-driven UI | `magic-modules.md` |
33
34
  | Legacy healing, modernization, archaeology | `healing.md` |
34
35
  | Plan deepening, knowledge extraction | `compound-learning.md` |
35
36