ctx-cc 3.5.0 → 4.0.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 (71) hide show
  1. package/README.md +34 -289
  2. package/agents/ctx-arch-mapper.md +5 -3
  3. package/agents/ctx-auditor.md +5 -3
  4. package/agents/ctx-concerns-mapper.md +5 -3
  5. package/agents/ctx-criteria-suggester.md +6 -4
  6. package/agents/ctx-debugger.md +5 -3
  7. package/agents/ctx-designer.md +488 -114
  8. package/agents/ctx-discusser.md +5 -3
  9. package/agents/ctx-executor.md +5 -3
  10. package/agents/ctx-handoff.md +6 -4
  11. package/agents/ctx-learner.md +5 -3
  12. package/agents/ctx-mapper.md +4 -3
  13. package/agents/ctx-ml-analyst.md +600 -0
  14. package/agents/ctx-ml-engineer.md +933 -0
  15. package/agents/ctx-ml-reviewer.md +485 -0
  16. package/agents/ctx-ml-scientist.md +626 -0
  17. package/agents/ctx-parallelizer.md +4 -3
  18. package/agents/ctx-planner.md +5 -3
  19. package/agents/ctx-predictor.md +4 -3
  20. package/agents/ctx-qa.md +5 -3
  21. package/agents/ctx-quality-mapper.md +5 -3
  22. package/agents/ctx-researcher.md +5 -3
  23. package/agents/ctx-reviewer.md +6 -4
  24. package/agents/ctx-team-coordinator.md +5 -3
  25. package/agents/ctx-tech-mapper.md +5 -3
  26. package/agents/ctx-verifier.md +5 -3
  27. package/bin/ctx.js +168 -27
  28. package/commands/brand.md +309 -0
  29. package/commands/design.md +304 -0
  30. package/commands/experiment.md +251 -0
  31. package/commands/help.md +57 -7
  32. package/commands/metrics.md +1 -1
  33. package/commands/milestone.md +1 -1
  34. package/commands/ml-status.md +197 -0
  35. package/commands/monitor.md +1 -1
  36. package/commands/train.md +266 -0
  37. package/commands/visual-qa.md +559 -0
  38. package/commands/voice.md +1 -1
  39. package/hooks/post-tool-use.js +39 -0
  40. package/hooks/pre-tool-use.js +93 -0
  41. package/hooks/subagent-stop.js +32 -0
  42. package/package.json +9 -3
  43. package/plugin.json +45 -0
  44. package/skills/ctx-design-system/SKILL.md +572 -0
  45. package/skills/ctx-ml-experiment/SKILL.md +334 -0
  46. package/skills/ctx-ml-pipeline/SKILL.md +437 -0
  47. package/skills/ctx-orchestrator/SKILL.md +91 -0
  48. package/skills/ctx-review-gate/SKILL.md +111 -0
  49. package/skills/ctx-state/SKILL.md +100 -0
  50. package/skills/ctx-visual-qa/SKILL.md +587 -0
  51. package/src/agents.js +109 -0
  52. package/src/auto.js +287 -0
  53. package/src/capabilities.js +171 -0
  54. package/src/commits.js +94 -0
  55. package/src/config.js +112 -0
  56. package/src/context.js +241 -0
  57. package/src/handoff.js +156 -0
  58. package/src/hooks.js +218 -0
  59. package/src/install.js +119 -51
  60. package/src/lifecycle.js +194 -0
  61. package/src/metrics.js +198 -0
  62. package/src/pipeline.js +269 -0
  63. package/src/review-gate.js +244 -0
  64. package/src/runner.js +120 -0
  65. package/src/skills.js +143 -0
  66. package/src/state.js +267 -0
  67. package/src/worktree.js +244 -0
  68. package/templates/PRD.json +1 -1
  69. package/templates/config.json +1 -237
  70. package/workflows/ctx-router.md +0 -485
  71. package/workflows/map-codebase.md +0 -329
@@ -0,0 +1,32 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * CTX SubagentStop Hook
5
+ * Records agent completion in .ctx/STATE.json when a subagent finishes.
6
+ * Installed to .claude/hooks/ctx-subagent-stop.js
7
+ */
8
+
9
+ import fs from 'fs';
10
+ import path from 'path';
11
+
12
+ const stateFile = path.join(process.cwd(), '.ctx', 'STATE.json');
13
+
14
+ try {
15
+ if (!fs.existsSync(stateFile)) process.exit(0);
16
+
17
+ const state = JSON.parse(fs.readFileSync(stateFile, 'utf-8'));
18
+ const history = state.agentHistory || [];
19
+
20
+ // Mark last incomplete invocation as completed
21
+ for (let i = history.length - 1; i >= 0; i--) {
22
+ if (!history[i].completedAt) {
23
+ history[i].completedAt = new Date().toISOString();
24
+ break;
25
+ }
26
+ }
27
+
28
+ state.session = { ...state.session, lastActivity: new Date().toISOString() };
29
+ fs.writeFileSync(stateFile, JSON.stringify(state, null, 2) + '\n');
30
+ } catch {
31
+ // Non-fatal — don't block on state errors
32
+ }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "ctx-cc",
3
- "version": "3.5.0",
4
- "description": "CTX 3.3 (Continuous Task eXecution) - AI that learns your preferences. Learning system, predictive planning, self-healing deployments (Sentry/LogRocket), voice control for hands-free development.",
3
+ "version": "4.0.0",
4
+ "description": "CTX 4.0 Intelligent workflow orchestration for Claude Code. 21 subagents, 3 skills, deterministic hooks. Phase-based lifecycle with autonomous execution.",
5
5
  "keywords": [
6
6
  "claude",
7
7
  "claude-code",
@@ -29,10 +29,16 @@
29
29
  "src/",
30
30
  "commands/",
31
31
  "agents/",
32
+ "skills/",
33
+ "hooks/",
32
34
  "references/",
33
35
  "templates/",
34
- "workflows/"
36
+ "plugin.json"
35
37
  ],
38
+ "scripts": {
39
+ "test": "node --test test/*.test.js",
40
+ "setup": "node bin/ctx.js"
41
+ },
36
42
  "engines": {
37
43
  "node": ">=18.0.0"
38
44
  },
package/plugin.json ADDED
@@ -0,0 +1,45 @@
1
+ {
2
+ "name": "ctx",
3
+ "version": "4.0.0",
4
+ "description": "CTX — Intelligent workflow orchestration for Claude Code. 21 specialized agents, phase-based lifecycle, two-stage review gate, autonomous execution.",
5
+ "author": "jufjuf",
6
+ "license": "MIT",
7
+ "homepage": "https://github.com/jufjuf/CTX",
8
+ "repository": "https://github.com/jufjuf/CTX",
9
+ "keywords": [
10
+ "workflow",
11
+ "orchestration",
12
+ "multi-agent",
13
+ "development",
14
+ "productivity"
15
+ ],
16
+ "components": {
17
+ "agents": "agents/",
18
+ "commands": "commands/",
19
+ "skills": "skills/",
20
+ "hooks": "hooks/"
21
+ },
22
+ "hooks": {
23
+ "SubagentStop": [
24
+ {
25
+ "command": "node .claude/hooks/ctx-subagent-stop.js"
26
+ }
27
+ ],
28
+ "PreToolUse": [
29
+ {
30
+ "command": "node .claude/hooks/ctx-pre-tool-use.js"
31
+ }
32
+ ],
33
+ "PostToolUse": [
34
+ {
35
+ "command": "node .claude/hooks/ctx-post-tool-use.js"
36
+ }
37
+ ]
38
+ },
39
+ "settings": {
40
+ "reviewGate": true,
41
+ "tddMode": "off",
42
+ "maxReviewCycles": 3,
43
+ "maxAutoIterations": 5
44
+ }
45
+ }
@@ -0,0 +1,572 @@
1
+ ---
2
+ name: ctx-design-system
3
+ description: |
4
+ WHEN: Design system creation, design token management, brand kit updates, token export (CSS/SCSS/JS/Tailwind), theme switching, design system audit for unused/missing tokens.
5
+ WHEN NOT: Individual component design, general coding tasks, non-visual work, functional bug fixes, API work.
6
+ ---
7
+
8
+ # CTX Design System — Token Management & Living Design System
9
+
10
+ You manage the design system as a living, versioned artifact. Tokens are the single source of truth for all visual decisions. Every color, dimension, duration, and typography value flows from here.
11
+
12
+ ## Token Format: W3C DTCG 2025.10
13
+
14
+ All tokens follow the W3C Design Token Community Group specification. Every token entry uses:
15
+
16
+ ```json
17
+ {
18
+ "token-name": {
19
+ "$type": "color",
20
+ "$value": "#1a1a2e",
21
+ "$description": "Purpose of this token in the system",
22
+ "$extensions": {
23
+ "ctx-design-system": {
24
+ "tier": "primitive",
25
+ "category": "brand",
26
+ "deprecated": false,
27
+ "figma-variable-id": "VariableID:123:456"
28
+ }
29
+ }
30
+ }
31
+ }
32
+ ```
33
+
34
+ ### Valid $type Values
35
+
36
+ | Type | $value format | Example |
37
+ |------|--------------|---------|
38
+ | `color` | hex, oklch(), p3() | `"oklch(0.45 0.18 264)"` |
39
+ | `dimension` | px, rem, em | `"16px"` |
40
+ | `duration` | ms, s | `"200ms"` |
41
+ | `fontFamily` | array of strings | `["Inter", "system-ui", "sans-serif"]` |
42
+ | `fontWeight` | number | `500` |
43
+ | `fontSize` | px or rem | `"1rem"` |
44
+ | `lineHeight` | unitless or px | `"1.5"` |
45
+ | `letterSpacing` | em | `"0.02em"` |
46
+ | `shadow` | composite object | see Shadow section |
47
+ | `border` | composite object | see Border section |
48
+ | `typography` | composite object | see Typography section |
49
+
50
+ ### Composite Token Types
51
+
52
+ **Typography composite:**
53
+ ```json
54
+ {
55
+ "heading-xl": {
56
+ "$type": "typography",
57
+ "$value": {
58
+ "fontFamily": "{font.family.display}",
59
+ "fontSize": "{font.size.5xl}",
60
+ "fontWeight": "{font.weight.bold}",
61
+ "lineHeight": "{font.line-height.tight}",
62
+ "letterSpacing": "{font.tracking.tight}"
63
+ }
64
+ }
65
+ }
66
+ ```
67
+
68
+ **Shadow composite:**
69
+ ```json
70
+ {
71
+ "elevation-md": {
72
+ "$type": "shadow",
73
+ "$value": [
74
+ { "offsetX": "0", "offsetY": "4px", "blur": "6px", "spread": "-1px", "color": "oklch(0 0 0 / 0.10)" },
75
+ { "offsetX": "0", "offsetY": "2px", "blur": "4px", "spread": "-2px", "color": "oklch(0 0 0 / 0.10)" }
76
+ ]
77
+ }
78
+ }
79
+ ```
80
+
81
+ **Border composite:**
82
+ ```json
83
+ {
84
+ "subtle": {
85
+ "$type": "border",
86
+ "$value": {
87
+ "width": "{border.width.1}",
88
+ "style": "solid",
89
+ "color": "{color.border.default}"
90
+ }
91
+ }
92
+ }
93
+ ```
94
+
95
+ ---
96
+
97
+ ## Three-Tier Token Architecture
98
+
99
+ Tokens flow in one direction: primitive → semantic → component. Never reference a component token from a semantic token. Never reference semantic from primitive.
100
+
101
+ ```
102
+ PRIMITIVE Raw values, no semantic meaning
103
+ blue-500, space-4, ms-200, weight-600
104
+
105
+ ↓ aliases reference primitives
106
+
107
+ SEMANTIC Purposeful names, mode-aware
108
+ color-text-primary, space-content-gap, duration-transition
109
+
110
+ ↓ aliases reference semantic tokens
111
+
112
+ COMPONENT Component-scoped tokens
113
+ button-background, input-border-focus, card-padding
114
+ ```
115
+
116
+ ### When to Add a Token
117
+
118
+ - Add to **primitive** when you need a new raw value not yet in the scale.
119
+ - Add to **semantic** when a primitive is being used for a specific purpose across 2+ components.
120
+ - Add to **component** when a value is unique to a single component and unlikely to be shared.
121
+
122
+ ---
123
+
124
+ ## File Organization
125
+
126
+ ```
127
+ tokens/
128
+ ├── primitive.tokens.json # Raw scale values — no aliases
129
+ ├── semantic.tokens.json # Purpose aliases — references primitives
130
+ ├── component.tokens.json # Component-scoped — references semantic
131
+ └── themes/
132
+ ├── light.tokens.json # Light mode overrides (semantic values only)
133
+ └── dark.tokens.json # Dark mode overrides (semantic values only)
134
+ ```
135
+
136
+ ### tokens/primitive.tokens.json
137
+
138
+ Complete primitive scale. Groups: `color`, `dimension`, `font`, `duration`, `easing`.
139
+
140
+ ```json
141
+ {
142
+ "$schema": "https://design-tokens.org/schema.json",
143
+ "color": {
144
+ "gray": {
145
+ "$type": "color",
146
+ "50": { "$value": "oklch(0.985 0.002 247)", "$description": "Near white" },
147
+ "100": { "$value": "oklch(0.965 0.004 247)" },
148
+ "200": { "$value": "oklch(0.922 0.008 247)" },
149
+ "300": { "$value": "oklch(0.865 0.014 247)" },
150
+ "400": { "$value": "oklch(0.780 0.022 247)" },
151
+ "500": { "$value": "oklch(0.680 0.028 247)" },
152
+ "600": { "$value": "oklch(0.560 0.030 247)" },
153
+ "700": { "$value": "oklch(0.440 0.028 247)" },
154
+ "800": { "$value": "oklch(0.320 0.022 247)" },
155
+ "900": { "$value": "oklch(0.200 0.014 247)" },
156
+ "950": { "$value": "oklch(0.130 0.010 247)", "$description": "Near black" }
157
+ },
158
+ "brand": {
159
+ "$type": "color",
160
+ "50": { "$value": "oklch(0.970 0.025 264)" },
161
+ "500": { "$value": "oklch(0.520 0.180 264)", "$description": "Primary brand hue" },
162
+ "600": { "$value": "oklch(0.450 0.185 264)" },
163
+ "700": { "$value": "oklch(0.380 0.175 264)" }
164
+ }
165
+ },
166
+ "dimension": {
167
+ "space": {
168
+ "$type": "dimension",
169
+ "0": { "$value": "0px" },
170
+ "1": { "$value": "4px" },
171
+ "2": { "$value": "8px" },
172
+ "3": { "$value": "12px" },
173
+ "4": { "$value": "16px" },
174
+ "5": { "$value": "20px" },
175
+ "6": { "$value": "24px" },
176
+ "8": { "$value": "32px" },
177
+ "10": { "$value": "40px" },
178
+ "12": { "$value": "48px" },
179
+ "16": { "$value": "64px" },
180
+ "20": { "$value": "80px" },
181
+ "24": { "$value": "96px" }
182
+ },
183
+ "radius": {
184
+ "$type": "dimension",
185
+ "none": { "$value": "0px" },
186
+ "sm": { "$value": "4px" },
187
+ "md": { "$value": "8px" },
188
+ "lg": { "$value": "12px" },
189
+ "xl": { "$value": "16px" },
190
+ "full": { "$value": "9999px" }
191
+ }
192
+ },
193
+ "font": {
194
+ "size": {
195
+ "$type": "fontSize",
196
+ "xs": { "$value": "0.75rem" },
197
+ "sm": { "$value": "0.875rem" },
198
+ "base": { "$value": "1rem" },
199
+ "lg": { "$value": "1.125rem" },
200
+ "xl": { "$value": "1.25rem" },
201
+ "2xl": { "$value": "1.5rem" },
202
+ "3xl": { "$value": "1.875rem" },
203
+ "4xl": { "$value": "2.25rem" },
204
+ "5xl": { "$value": "3rem" }
205
+ },
206
+ "weight": {
207
+ "$type": "fontWeight",
208
+ "regular": { "$value": 400 },
209
+ "medium": { "$value": 500 },
210
+ "semibold":{ "$value": 600 },
211
+ "bold": { "$value": 700 }
212
+ },
213
+ "family": {
214
+ "sans": { "$type": "fontFamily", "$value": ["Inter", "system-ui", "sans-serif"] },
215
+ "display": { "$type": "fontFamily", "$value": ["Cal Sans", "Inter", "sans-serif"] },
216
+ "mono": { "$type": "fontFamily", "$value": ["JetBrains Mono", "Menlo", "monospace"] }
217
+ }
218
+ },
219
+ "duration": {
220
+ "$type": "duration",
221
+ "instant": { "$value": "0ms" },
222
+ "fast": { "$value": "100ms" },
223
+ "normal": { "$value": "200ms" },
224
+ "slow": { "$value": "300ms" },
225
+ "slower": { "$value": "500ms" }
226
+ }
227
+ }
228
+ ```
229
+
230
+ ### tokens/semantic.tokens.json
231
+
232
+ Semantic tokens reference primitives using `{path.to.token}` syntax. Values are objects with `light` and `dark` keys when mode-aware.
233
+
234
+ ```json
235
+ {
236
+ "$schema": "https://design-tokens.org/schema.json",
237
+ "color": {
238
+ "background": {
239
+ "page": { "$type": "color", "$value": { "light": "{color.gray.50}", "dark": "{color.gray.950}" }, "$description": "Root page background" },
240
+ "surface": { "$type": "color", "$value": { "light": "{color.gray.100}", "dark": "{color.gray.900}" }, "$description": "Card, panel surfaces" },
241
+ "overlay": { "$type": "color", "$value": { "light": "{color.gray.200}", "dark": "{color.gray.800}" }, "$description": "Overlay, popover background" }
242
+ },
243
+ "text": {
244
+ "primary": { "$type": "color", "$value": { "light": "{color.gray.900}", "dark": "{color.gray.50}" } },
245
+ "secondary": { "$type": "color", "$value": { "light": "{color.gray.600}", "dark": "{color.gray.400}" } },
246
+ "disabled": { "$type": "color", "$value": { "light": "{color.gray.400}", "dark": "{color.gray.600}" } },
247
+ "on-accent": { "$type": "color", "$value": { "light": "#ffffff", "dark": "#ffffff" }, "$description": "Text on accent backgrounds" }
248
+ },
249
+ "border": {
250
+ "default": { "$type": "color", "$value": { "light": "{color.gray.200}", "dark": "{color.gray.700}" } },
251
+ "strong": { "$type": "color", "$value": { "light": "{color.gray.400}", "dark": "{color.gray.500}" } }
252
+ },
253
+ "interactive": {
254
+ "default": { "$type": "color", "$value": { "light": "{color.brand.500}", "dark": "{color.brand.600}" }, "$description": "Primary interactive (buttons, links)" },
255
+ "hover": { "$type": "color", "$value": { "light": "{color.brand.600}", "dark": "{color.brand.500}" } },
256
+ "focus": { "$type": "color", "$value": { "light": "{color.brand.500}", "dark": "{color.brand.500}" }, "$description": "Focus ring color — must achieve 3:1 against background" }
257
+ }
258
+ },
259
+ "space": {
260
+ "component-gap": { "$type": "dimension", "$value": "{dimension.space.4}", "$description": "Gap between components within a section" },
261
+ "section-gap": { "$type": "dimension", "$value": "{dimension.space.12}", "$description": "Gap between sections" },
262
+ "content-inset": { "$type": "dimension", "$value": "{dimension.space.6}", "$description": "Inner padding for cards and panels" }
263
+ },
264
+ "transition": {
265
+ "interactive": {
266
+ "$type": "duration",
267
+ "$value": "{duration.normal}",
268
+ "$description": "Standard duration for hover/focus transitions"
269
+ }
270
+ }
271
+ }
272
+ ```
273
+
274
+ ### tokens/component.tokens.json
275
+
276
+ Component tokens reference semantic tokens. Kept minimal — only add when a component deviates from semantic defaults.
277
+
278
+ ```json
279
+ {
280
+ "$schema": "https://design-tokens.org/schema.json",
281
+ "button": {
282
+ "background": { "$type": "color", "$value": "{color.interactive.default}" },
283
+ "background-hover":{ "$type": "color", "$value": "{color.interactive.hover}" },
284
+ "text": { "$type": "color", "$value": "{color.text.on-accent}" },
285
+ "min-height": { "$type": "dimension", "$value": "44px", "$description": "WCAG 2.2 AA touch target — do not reduce" },
286
+ "min-width": { "$type": "dimension", "$value": "44px", "$description": "WCAG 2.2 AA touch target — do not reduce" },
287
+ "padding-x": { "$type": "dimension", "$value": "{dimension.space.4}" },
288
+ "padding-y": { "$type": "dimension", "$value": "{dimension.space.3}" },
289
+ "radius": { "$type": "dimension", "$value": "{dimension.radius.md}" }
290
+ },
291
+ "input": {
292
+ "background": { "$type": "color", "$value": "{color.background.surface}" },
293
+ "border": { "$type": "color", "$value": "{color.border.default}" },
294
+ "border-focus": { "$type": "color", "$value": "{color.interactive.focus}" },
295
+ "text": { "$type": "color", "$value": "{color.text.primary}" },
296
+ "min-height": { "$type": "dimension", "$value": "44px" },
297
+ "padding-x": { "$type": "dimension", "$value": "{dimension.space.3}" },
298
+ "radius": { "$type": "dimension", "$value": "{dimension.radius.md}" }
299
+ },
300
+ "card": {
301
+ "background": { "$type": "color", "$value": "{color.background.surface}" },
302
+ "border": { "$type": "color", "$value": "{color.border.default}" },
303
+ "padding": { "$type": "dimension", "$value": "{space.content-inset}" },
304
+ "radius": { "$type": "dimension", "$value": "{dimension.radius.lg}" }
305
+ }
306
+ }
307
+ ```
308
+
309
+ ### tokens/themes/dark.tokens.json
310
+
311
+ Theme files override semantic token values for a given mode. Only include tokens that differ from the default (light) mode.
312
+
313
+ ```json
314
+ {
315
+ "$schema": "https://design-tokens.org/schema.json",
316
+ "color": {
317
+ "background": {
318
+ "page": { "$type": "color", "$value": "{color.gray.950}" },
319
+ "surface": { "$type": "color", "$value": "{color.gray.900}" }
320
+ },
321
+ "text": {
322
+ "primary": { "$type": "color", "$value": "{color.gray.50}" },
323
+ "secondary": { "$type": "color", "$value": "{color.gray.400}" }
324
+ }
325
+ }
326
+ }
327
+ ```
328
+
329
+ ---
330
+
331
+ ## Color Spaces
332
+
333
+ Use modern color spaces for superior gamut coverage and perceptual uniformity:
334
+
335
+ **Oklch** — preferred for scales and accessible colors:
336
+ ```
337
+ oklch(lightness chroma hue / alpha)
338
+ oklch(0.520 0.180 264) /* brand blue */
339
+ ```
340
+ - Lightness 0–1 (perceptually uniform, use for contrast calculation)
341
+ - Chroma 0–0.4 (0 = gray, higher = more saturated)
342
+ - Hue 0–360 (same as HSL hue)
343
+
344
+ **Display P3** — for wide-gamut displays (Safari, Chrome on modern hardware):
345
+ ```
346
+ color(display-p3 0.18 0.47 0.89)
347
+ ```
348
+
349
+ **CSS fallback pattern:**
350
+ ```css
351
+ /* Always provide sRGB fallback first */
352
+ color: rgb(46 120 227);
353
+ color: oklch(0.52 0.18 264); /* wider gamut where supported */
354
+ color: color(display-p3 0.18 0.47 0.89); /* widest gamut */
355
+ ```
356
+
357
+ ---
358
+
359
+ ## Export Targets
360
+
361
+ Run the following exports after any token change. Use Style Dictionary or token-transformer.
362
+
363
+ ### CSS Custom Properties
364
+
365
+ ```css
366
+ /* brand-assets/tokens.css */
367
+ :root {
368
+ /* Primitive */
369
+ --color-gray-50: oklch(0.985 0.002 247);
370
+ --color-brand-500: oklch(0.52 0.18 264);
371
+ --space-4: 16px;
372
+ --font-size-base: 1rem;
373
+
374
+ /* Semantic — light mode defaults */
375
+ --color-background-page: var(--color-gray-50);
376
+ --color-text-primary: var(--color-gray-900);
377
+ --color-interactive-default: var(--color-brand-500);
378
+ }
379
+
380
+ [data-theme="dark"] {
381
+ --color-background-page: var(--color-gray-950);
382
+ --color-text-primary: var(--color-gray-50);
383
+ }
384
+ ```
385
+
386
+ ### SCSS Variables
387
+
388
+ ```scss
389
+ /* brand-assets/tokens.scss */
390
+ $color-gray-50: oklch(0.985 0.002 247);
391
+ $color-brand-500: oklch(0.52 0.18 264);
392
+ $color-background-page: var(--color-background-page);
393
+ $space-4: 16px;
394
+ $button-min-height: 44px;
395
+ ```
396
+
397
+ ### JS Constants
398
+
399
+ ```js
400
+ /* brand-assets/tokens.js */
401
+ export const tokens = {
402
+ color: {
403
+ gray: { 50: 'oklch(0.985 0.002 247)', 900: 'oklch(0.20 0.014 247)' },
404
+ brand: { 500: 'oklch(0.52 0.18 264)' },
405
+ background: { page: 'var(--color-background-page)' },
406
+ text: { primary: 'var(--color-text-primary)' }
407
+ },
408
+ space: { 4: '16px', 6: '24px', 8: '32px' },
409
+ button: { minHeight: '44px' }
410
+ };
411
+ ```
412
+
413
+ ### Tailwind Config
414
+
415
+ ```js
416
+ /* brand-assets/tailwind.config.js */
417
+ module.exports = {
418
+ theme: {
419
+ extend: {
420
+ colors: {
421
+ brand: { 500: 'oklch(0.52 0.18 264)', 600: 'oklch(0.45 0.185 264)' },
422
+ background: { page: 'var(--color-background-page)', surface: 'var(--color-background-surface)' },
423
+ text: { primary: 'var(--color-text-primary)', secondary: 'var(--color-text-secondary)' },
424
+ border: { default: 'var(--color-border-default)' },
425
+ interactive:{ default: 'var(--color-interactive-default)', hover: 'var(--color-interactive-hover)' }
426
+ },
427
+ spacing: {
428
+ 'component-gap': 'var(--space-component-gap)',
429
+ 'content-inset': 'var(--space-content-inset)'
430
+ },
431
+ borderRadius: {
432
+ sm: '4px', md: '8px', lg: '12px', xl: '16px'
433
+ },
434
+ fontFamily: {
435
+ sans: ['Inter', 'system-ui', 'sans-serif'],
436
+ display: ['Cal Sans', 'Inter', 'sans-serif'],
437
+ mono: ['JetBrains Mono', 'Menlo', 'monospace']
438
+ }
439
+ }
440
+ }
441
+ };
442
+ ```
443
+
444
+ ---
445
+
446
+ ## Figma Sync
447
+
448
+ ### Read Tokens from Figma Variables
449
+
450
+ Pull current Figma variable values and reconcile with token files:
451
+
452
+ ```javascript
453
+ // 1. Fetch all Figma variable collections
454
+ const collections = await mcp__figma__get_variable_defs({ fileKey: figmaFileKey });
455
+
456
+ // 2. For each collection, extract token values
457
+ collections.forEach(collection => {
458
+ collection.variables.forEach(variable => {
459
+ const tokenPath = figmaNameToTokenPath(variable.name);
460
+ const value = variable.resolvedValuesByMode[collection.defaultModeId];
461
+ // Map to DTCG format and write to appropriate tier file
462
+ });
463
+ });
464
+ ```
465
+
466
+ ### Write Tokens to Figma
467
+
468
+ After token changes, push updated values back to Figma variables to keep design and code in sync:
469
+
470
+ ```javascript
471
+ // Update a Figma variable value
472
+ await mcp__figma__update_variable({
473
+ fileKey: figmaFileKey,
474
+ variableId: token.$extensions['ctx-design-system']['figma-variable-id'],
475
+ value: resolveTokenValue(token.$value)
476
+ });
477
+ ```
478
+
479
+ ### Figma Name → Token Path Mapping
480
+
481
+ | Figma Variable Name | Token Path |
482
+ |--------------------|-----------|
483
+ | `Color/Gray/500` | `color.gray.500` |
484
+ | `Semantic/Background/Page` | `color.background.page` |
485
+ | `Component/Button/Min Height` | `button.min-height` |
486
+
487
+ ---
488
+
489
+ ## Design System Audit
490
+
491
+ Run these checks before any token release.
492
+
493
+ ### 1. Unused Token Detection
494
+
495
+ ```bash
496
+ # Find all CSS custom property references in source
497
+ grep -r "var(--" src/ --include="*.tsx" --include="*.css" | \
498
+ grep -oP 'var\(--[\w-]+\)' | sort | uniq > .ctx/audit/used-tokens.txt
499
+
500
+ # Compare against token export
501
+ diff .ctx/audit/used-tokens.txt brand-assets/all-tokens.txt
502
+ ```
503
+
504
+ ### 2. Missing Semantic Mappings
505
+
506
+ Verify every primitive token used in components has a semantic alias:
507
+ - If `color.gray.500` appears in `component.tokens.json`, that is a violation — reference `color.text.secondary` instead.
508
+
509
+ ### 3. Accessibility Violations
510
+
511
+ Check contrast ratios for all text/background token pairs:
512
+
513
+ ```javascript
514
+ function relativeLuminance(oklch) {
515
+ // Convert oklch → linear sRGB → luminance
516
+ const rgb = oklchToLinearRGB(oklch);
517
+ return 0.2126 * rgb.r + 0.7152 * rgb.g + 0.0722 * rgb.b;
518
+ }
519
+
520
+ function contrastRatio(l1, l2) {
521
+ const lighter = Math.max(l1, l2);
522
+ const darker = Math.min(l1, l2);
523
+ return (lighter + 0.05) / (darker + 0.05);
524
+ }
525
+
526
+ // Required: text 4.5:1, UI components 3:1
527
+ const pairs = [
528
+ { fg: 'color.text.primary', bg: 'color.background.page', required: 4.5 },
529
+ { fg: 'color.text.secondary', bg: 'color.background.page', required: 4.5 },
530
+ { fg: 'color.text.on-accent', bg: 'color.interactive.default', required: 4.5 },
531
+ { fg: 'color.border.default', bg: 'color.background.page', required: 3.0 }
532
+ ];
533
+ ```
534
+
535
+ ### 4. Audit Report Format
536
+
537
+ Write to `.ctx/audit/TOKEN_AUDIT.md`:
538
+
539
+ ```markdown
540
+ # Token Audit — [ISO-8601]
541
+
542
+ ## Summary
543
+ - Total tokens: {n}
544
+ - Unused tokens: {n}
545
+ - Missing semantic mappings: {n}
546
+ - Contrast violations: {n}
547
+
548
+ ## Unused Tokens
549
+ | Token | Last Used | Action |
550
+ |-------|-----------|--------|
551
+ | color.gray.150 | never | Remove |
552
+
553
+ ## Contrast Violations
554
+ | Pair | Ratio | Required | Status |
555
+ |------|-------|----------|--------|
556
+ | text.disabled on bg.page | 2.8:1 | 4.5:1 | FAIL |
557
+
558
+ ## Missing Semantic Mappings
559
+ | Primitive | Used In | Should Become |
560
+ |-----------|---------|---------------|
561
+ | color.gray.500 | button.tokens | color.border.strong |
562
+ ```
563
+
564
+ ---
565
+
566
+ ## Operational Rules
567
+
568
+ - Never delete a token that is currently exported and deployed without a deprecation period.
569
+ - Mark deprecated tokens with `"deprecated": true` in `$extensions` before removal.
570
+ - Increment version in BRAND_KIT.md header on every token release.
571
+ - All token changes must pass the audit before export.
572
+ - Theme files may only reference semantic-tier tokens, never primitives.