@noemuch/bridge-ds 2.3.0 → 2.5.1
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/.claude-plugin/plugin.json +31 -0
- package/.cursor-plugin/plugin.json +26 -0
- package/.mcp.json +12 -0
- package/CHANGELOG.md +93 -0
- package/CLAUDE.md +84 -0
- package/README.md +25 -10
- package/lib/cli.js +107 -134
- package/lib/mcp-setup.js +32 -28
- package/lib/scaffold.js +6 -3
- package/package.json +10 -3
- package/skills/design-workflow/SKILL.md +70 -17
- package/skills/design-workflow/references/actions/design.md +63 -12
- package/skills/design-workflow/references/actions/done.md +21 -3
- package/skills/design-workflow/references/actions/learn.md +147 -0
- package/skills/design-workflow/references/actions/quick.md +80 -0
- package/skills/design-workflow/references/actions/review.md +14 -3
- package/skills/design-workflow/references/actions/spec.md +24 -0
- package/skills/design-workflow/references/actions/sync.md +176 -0
- package/skills/design-workflow/references/figma-api-rules.md +112 -0
- package/skills/design-workflow/references/knowledge-base/README.md +18 -1
- package/skills/design-workflow/references/knowledge-base/schemas/assets.md +6 -0
- package/skills/design-workflow/references/knowledge-base/schemas/components.md +6 -0
- package/skills/design-workflow/references/knowledge-base/schemas/learnings.md +250 -0
- package/skills/design-workflow/references/knowledge-base/schemas/text-styles.md +6 -0
- package/skills/design-workflow/references/knowledge-base/schemas/validation.md +6 -0
- package/skills/design-workflow/references/knowledge-base/schemas/variables.md +6 -0
- package/skills/design-workflow/references/onboarding.md +51 -9
- package/skills/design-workflow/references/quality-gates.md +51 -2
- package/skills/design-workflow/references/templates/screen-template.md +12 -0
- package/skills/design-workflow/references/templates/spec-template.md +12 -0
- package/skills/design-workflow/references/transport-adapter.md +210 -0
package/lib/mcp-setup.js
CHANGED
|
@@ -3,45 +3,49 @@ const path = require('path');
|
|
|
3
3
|
const os = require('os');
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
|
-
* Check
|
|
7
|
-
*
|
|
6
|
+
* Check which Figma MCP transports are configured in Claude Code settings.
|
|
7
|
+
* Returns { console: boolean, official: boolean }
|
|
8
|
+
* - console: figma-console-mcp is configured
|
|
9
|
+
* - official: Official Figma MCP (mcp.figma.com or "figma"/"claude.ai Figma")
|
|
8
10
|
*/
|
|
9
11
|
function checkMcp() {
|
|
12
|
+
const result = { console: false, official: false };
|
|
13
|
+
|
|
10
14
|
const locations = [
|
|
11
|
-
// User-level Claude Code settings
|
|
12
15
|
path.join(os.homedir(), '.claude.json'),
|
|
13
|
-
|
|
16
|
+
path.join(os.homedir(), '.claude', 'settings.json'),
|
|
14
17
|
path.join(process.cwd(), '.claude', 'settings.local.json'),
|
|
15
18
|
];
|
|
16
19
|
|
|
17
20
|
for (const loc of locations) {
|
|
18
|
-
if (fs.existsSync(loc))
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
21
|
+
if (!fs.existsSync(loc)) continue;
|
|
22
|
+
try {
|
|
23
|
+
const content = JSON.parse(fs.readFileSync(loc, 'utf8'));
|
|
24
|
+
const servers = content.mcpServers || {};
|
|
25
|
+
for (const [name, config] of Object.entries(servers)) {
|
|
26
|
+
const args = (config.args || []).join(' ');
|
|
27
|
+
const url = config.url || '';
|
|
28
|
+
|
|
29
|
+
// figma-console-mcp detection
|
|
30
|
+
if (name.includes('figma') && config.command && args.includes('figma-console-mcp')) {
|
|
31
|
+
result.console = true;
|
|
32
|
+
continue;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// Official Figma MCP detection (by URL or server name)
|
|
36
|
+
if (url.includes('mcp.figma.com')) {
|
|
37
|
+
result.official = true;
|
|
38
|
+
continue;
|
|
39
|
+
}
|
|
40
|
+
if ((name === 'figma' || name === 'claude.ai Figma') && !args.includes('figma-console-mcp')) {
|
|
41
|
+
result.official = true;
|
|
42
|
+
continue;
|
|
30
43
|
}
|
|
31
|
-
} catch (_) {
|
|
32
|
-
// Ignore parse errors
|
|
33
44
|
}
|
|
34
|
-
}
|
|
45
|
+
} catch (_) {}
|
|
35
46
|
}
|
|
36
47
|
|
|
37
|
-
return
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
/**
|
|
41
|
-
* Return the MCP add command for the user to run.
|
|
42
|
-
*/
|
|
43
|
-
function getMcpAddCommand() {
|
|
44
|
-
return 'claude mcp add figma-console -s user -e FIGMA_ACCESS_TOKEN=figd_YOUR_TOKEN -- npx -y figma-console-mcp@latest';
|
|
48
|
+
return result;
|
|
45
49
|
}
|
|
46
50
|
|
|
47
|
-
module.exports = { checkMcp
|
|
51
|
+
module.exports = { checkMcp };
|
package/lib/scaffold.js
CHANGED
|
@@ -5,7 +5,7 @@ const path = require('path');
|
|
|
5
5
|
* Recursively copy a directory, preserving structure.
|
|
6
6
|
* @param {string[]} skipDirs - directory names to skip (e.g., ['registries', 'guides', 'ui-references'])
|
|
7
7
|
*/
|
|
8
|
-
function copyDir(src, dest, skipDirs = []) {
|
|
8
|
+
function copyDir(src, dest, skipDirs = [], skipFiles = []) {
|
|
9
9
|
const created = [];
|
|
10
10
|
if (!fs.existsSync(dest)) {
|
|
11
11
|
fs.mkdirSync(dest, { recursive: true });
|
|
@@ -15,8 +15,9 @@ function copyDir(src, dest, skipDirs = []) {
|
|
|
15
15
|
const destPath = path.join(dest, entry.name);
|
|
16
16
|
if (entry.isDirectory()) {
|
|
17
17
|
if (skipDirs.includes(entry.name)) continue;
|
|
18
|
-
created.push(...copyDir(srcPath, destPath, skipDirs));
|
|
18
|
+
created.push(...copyDir(srcPath, destPath, skipDirs, skipFiles));
|
|
19
19
|
} else {
|
|
20
|
+
if (skipFiles.includes(entry.name)) continue;
|
|
20
21
|
fs.copyFileSync(srcPath, destPath);
|
|
21
22
|
created.push(destPath);
|
|
22
23
|
}
|
|
@@ -102,6 +103,7 @@ function scaffold(projectDir) {
|
|
|
102
103
|
'.claude/skills/design-workflow/references/knowledge-base/registries/*.json',
|
|
103
104
|
'.claude/skills/design-workflow/references/knowledge-base/ui-references/screenshots/*.png',
|
|
104
105
|
'.claude/skills/design-workflow/references/knowledge-base/ui-references/screenshots/*.jpg',
|
|
106
|
+
'.claude/skills/design-workflow/references/knowledge-base/learnings.json',
|
|
105
107
|
];
|
|
106
108
|
const gitignoreBlock = gitignoreEntries.join('\n') + '\n';
|
|
107
109
|
|
|
@@ -137,7 +139,8 @@ function update(projectDir) {
|
|
|
137
139
|
|
|
138
140
|
// Copy skill files, skipping user-generated KB data
|
|
139
141
|
const userDataDirs = ['registries', 'guides', 'ui-references'];
|
|
140
|
-
const
|
|
142
|
+
const userDataFiles = ['learnings.json'];
|
|
143
|
+
const files = copyDir(skillsSrc, skillsDest, userDataDirs, userDataFiles);
|
|
141
144
|
updated.push(...files.map(f => path.relative(projectDir, f)));
|
|
142
145
|
|
|
143
146
|
// Update command file
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@noemuch/bridge-ds",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.5.1",
|
|
4
4
|
"description": "AI-powered design generation in Figma — 100% design system compliant. Connects Claude Code to Figma via MCP for spec-first, token-bound, component-native design.",
|
|
5
5
|
"main": "lib/cli.js",
|
|
6
6
|
"bin": {
|
|
@@ -12,7 +12,12 @@
|
|
|
12
12
|
"skills/",
|
|
13
13
|
"commands/",
|
|
14
14
|
"README.md",
|
|
15
|
-
"
|
|
15
|
+
"CHANGELOG.md",
|
|
16
|
+
"LICENSE",
|
|
17
|
+
".claude-plugin/",
|
|
18
|
+
".cursor-plugin/",
|
|
19
|
+
".mcp.json",
|
|
20
|
+
"CLAUDE.md"
|
|
16
21
|
],
|
|
17
22
|
"engines": {
|
|
18
23
|
"node": ">=18"
|
|
@@ -27,7 +32,9 @@
|
|
|
27
32
|
"mcp",
|
|
28
33
|
"design-tokens",
|
|
29
34
|
"ai-design",
|
|
30
|
-
"figma-plugin-api"
|
|
35
|
+
"figma-plugin-api",
|
|
36
|
+
"claude-code-plugin",
|
|
37
|
+
"cursor-plugin"
|
|
31
38
|
],
|
|
32
39
|
"author": "noemuch",
|
|
33
40
|
"license": "MIT",
|
|
@@ -5,14 +5,14 @@ description: >
|
|
|
5
5
|
Covers components and full interfaces/screens. Use when a designer wants to:
|
|
6
6
|
(1) write or review a component or screen spec, (2) generate a Figma design via MCP,
|
|
7
7
|
(3) review and iterate on a design, (4) close or abandon work.
|
|
8
|
-
Triggers: "spec", "design", "screen", "review", "done", "drop", "
|
|
9
|
-
"setup", "workflow", "what's next", "new component", "new screen", or any design request.
|
|
8
|
+
Triggers: "spec", "design", "screen", "review", "done", "drop", "learn", "sync",
|
|
9
|
+
"status", "setup", "quick", "express", "fast", "workflow", "what's next", "new component", "new screen", or any design request.
|
|
10
10
|
---
|
|
11
11
|
|
|
12
12
|
# Design Workflow
|
|
13
13
|
|
|
14
14
|
> Spec-first workflow for designers using Claude Code to design in Figma.
|
|
15
|
-
> Powered by
|
|
15
|
+
> Powered by Figma MCP transport (console or official). See `references/transport-adapter.md`.
|
|
16
16
|
> **All output in the user's language.**
|
|
17
17
|
|
|
18
18
|
---
|
|
@@ -28,6 +28,18 @@ description: >
|
|
|
28
28
|
|
|
29
29
|
---
|
|
30
30
|
|
|
31
|
+
## Knowledge Base Location
|
|
32
|
+
|
|
33
|
+
The knowledge base is project-specific. Resolve its path in this order:
|
|
34
|
+
1. If `./bridge-ds/knowledge-base/registries/` exists and contains JSON files → use `./bridge-ds/knowledge-base/`
|
|
35
|
+
2. Else if `./.claude/skills/design-workflow/references/knowledge-base/registries/` exists and contains JSON files → use that path
|
|
36
|
+
3. Else → knowledge base not found. Suggest running `/design-workflow setup` to extract the DS.
|
|
37
|
+
|
|
38
|
+
The `specs/` directory is always at `./specs/` (project root), regardless of KB location.
|
|
39
|
+
The `learnings.json` is always inside the knowledge base directory.
|
|
40
|
+
|
|
41
|
+
---
|
|
42
|
+
|
|
31
43
|
## Commands
|
|
32
44
|
|
|
33
45
|
| Command | Purpose | Action file |
|
|
@@ -38,7 +50,19 @@ description: >
|
|
|
38
50
|
| `review` | Validate design against spec, tokens, and visual fidelity | `references/actions/review.md` |
|
|
39
51
|
| `done` | Archive spec and close | `references/actions/done.md` |
|
|
40
52
|
| `drop` | Abandon with preserved learnings | `references/actions/drop.md` |
|
|
53
|
+
| `learn` | Diff design vs corrections, extract learnings | `references/actions/learn.md` |
|
|
54
|
+
| `sync` | Incremental DS sync (no full re-setup) | `references/actions/sync.md` |
|
|
41
55
|
| `status` | Show current state and suggest next action | *(inline below)* |
|
|
56
|
+
| `quick {description}` | Express generation — skip spec, generate directly | `references/actions/quick.md` |
|
|
57
|
+
| `express {description}` | Alias for quick | `references/actions/quick.md` |
|
|
58
|
+
| `fast {description}` | Alias for quick | `references/actions/quick.md` |
|
|
59
|
+
|
|
60
|
+
---
|
|
61
|
+
|
|
62
|
+
### Express Mode
|
|
63
|
+
For rapid generation without formal specs, use `quick`. Requires an existing knowledge base.
|
|
64
|
+
Full quality gates still apply for DS compliance and token binding.
|
|
65
|
+
See `references/actions/quick.md`.
|
|
42
66
|
|
|
43
67
|
---
|
|
44
68
|
|
|
@@ -70,7 +94,7 @@ The `spec` action auto-detects the mode from context, or asks the user.
|
|
|
70
94
|
|
|
71
95
|
```
|
|
72
96
|
setup (first time only)
|
|
73
|
-
→ Extract DS via
|
|
97
|
+
→ Extract DS via Figma MCP transport
|
|
74
98
|
→ Build knowledge base (registries + guides)
|
|
75
99
|
↓
|
|
76
100
|
spec {name}
|
|
@@ -105,7 +129,32 @@ review
|
|
|
105
129
|
│ 3. Verdict: PASS / FAIL with identified gaps
|
|
106
130
|
│
|
|
107
131
|
▼
|
|
132
|
+
(optional) user corrects in Figma
|
|
133
|
+
│
|
|
134
|
+
▼
|
|
135
|
+
learn (optional, repeatable)
|
|
136
|
+
│
|
|
137
|
+
├─ Diff snapshot vs current Figma state
|
|
138
|
+
├─ Classify: DS-compliant → learning | hardcoded → flag
|
|
139
|
+
├─ Persist to learnings.json
|
|
140
|
+
└─ Update spec with corrections
|
|
141
|
+
│
|
|
142
|
+
▼
|
|
108
143
|
done
|
|
144
|
+
│
|
|
145
|
+
├─ Persist learnings
|
|
146
|
+
├─ Archive spec
|
|
147
|
+
└─ Cleanup snapshot
|
|
148
|
+
|
|
149
|
+
───────────────────────────────
|
|
150
|
+
|
|
151
|
+
sync (independent, anytime)
|
|
152
|
+
│
|
|
153
|
+
├─ Re-extract DS via MCP
|
|
154
|
+
├─ Diff vs current registries
|
|
155
|
+
├─ Report: +added, ~modified, -removed
|
|
156
|
+
├─ Breaking change analysis
|
|
157
|
+
└─ Update registries + patch guides
|
|
109
158
|
```
|
|
110
159
|
|
|
111
160
|
---
|
|
@@ -122,7 +171,10 @@ Detect intent from user input and **read the action file BEFORE executing**:
|
|
|
122
171
|
| "review", "check", "validate", "audit" | `references/actions/review.md` |
|
|
123
172
|
| "done", "finish", "complete", "close", "ship" | `references/actions/done.md` |
|
|
124
173
|
| "drop", "abandon", "cancel" | `references/actions/drop.md` |
|
|
174
|
+
| "learn", "diff", "corrections", "what changed" | `references/actions/learn.md` |
|
|
175
|
+
| "sync", "update DS", "refresh DS", "sync DS" | `references/actions/sync.md` |
|
|
125
176
|
| "status", "workflow", "what's next", "what now" | *(status logic below)* |
|
|
177
|
+
| "quick", "express", "fast", "quick design", "just design" | `references/actions/quick.md` |
|
|
126
178
|
|
|
127
179
|
---
|
|
128
180
|
|
|
@@ -152,7 +204,8 @@ Detect state by checking:
|
|
|
152
204
|
| No spec | "Ready. Run: `spec {name}`" |
|
|
153
205
|
| Active spec, no Figma design | "Spec ready. Run: `design`" |
|
|
154
206
|
| Active spec + Figma done | "Design ready. Run: `review`" |
|
|
155
|
-
| Review passed | "Run: `done`" |
|
|
207
|
+
| Review passed | "Run: `done` (or `learn` if you made manual corrections)" |
|
|
208
|
+
| DS may be outdated | "Run: `sync` to update registries from Figma" |
|
|
156
209
|
|
|
157
210
|
---
|
|
158
211
|
|
|
@@ -179,6 +232,7 @@ Full definitions: `references/quality-gates.md` (read before any phase transitio
|
|
|
179
232
|
|
|
180
233
|
| Reference | Path |
|
|
181
234
|
|-----------|------|
|
|
235
|
+
| Transport adapter | `references/transport-adapter.md` |
|
|
182
236
|
| Quality gates | `references/quality-gates.md` |
|
|
183
237
|
| Figma API rules | `references/figma-api-rules.md` |
|
|
184
238
|
| Onboarding flow | `references/onboarding.md` |
|
|
@@ -191,15 +245,14 @@ Full definitions: `references/quality-gates.md` (read before any phase transitio
|
|
|
191
245
|
|
|
192
246
|
## MCP Tools Used
|
|
193
247
|
|
|
194
|
-
Bridge
|
|
195
|
-
|
|
196
|
-
|
|
|
197
|
-
|
|
198
|
-
|
|
|
199
|
-
| `figma_take_screenshot` |
|
|
200
|
-
|
|
|
201
|
-
| `figma_get_variables` |
|
|
202
|
-
| `
|
|
203
|
-
| `
|
|
204
|
-
| `
|
|
205
|
-
| `figma_get_status` | Check Figma connection |
|
|
248
|
+
Bridge supports two Figma MCP transports. Tool names vary by transport — see `references/transport-adapter.md` for the full mapping table and adaptation rules.
|
|
249
|
+
|
|
250
|
+
| Operation | Console transport | Official transport |
|
|
251
|
+
|-----------|------------------|--------------------|
|
|
252
|
+
| Execute Plugin API code | `figma_execute` | `use_figma` |
|
|
253
|
+
| Take screenshot | `figma_take_screenshot` | `get_screenshot` |
|
|
254
|
+
| Full DS extraction | `figma_get_design_system_kit` | Composite strategy |
|
|
255
|
+
| Get variables | `figma_get_variables` | `get_variable_defs` |
|
|
256
|
+
| Get styles | `figma_get_styles` | `search_design_system` |
|
|
257
|
+
| Search components | `figma_search_components` | `search_design_system` |
|
|
258
|
+
| Connection check | `figma_get_status` | `whoami` |
|
|
@@ -1,13 +1,15 @@
|
|
|
1
1
|
# Action: design
|
|
2
2
|
|
|
3
|
-
> Generate a Figma design from the active spec via
|
|
3
|
+
> Generate a Figma design from the active spec via Figma MCP transport.
|
|
4
|
+
>
|
|
5
|
+
> **Before generating, check `references/transport-adapter.md` to determine the active transport.** Tool names and script format vary by transport.
|
|
4
6
|
|
|
5
7
|
---
|
|
6
8
|
|
|
7
9
|
## Prerequisites
|
|
8
10
|
|
|
9
11
|
- Active spec in `specs/active/` (abort if missing: "No active spec. Run: `spec {name}`")
|
|
10
|
-
-
|
|
12
|
+
- Figma MCP transport available (console: `figma_get_status`, official: `whoami` — see transport-adapter.md Section F)
|
|
11
13
|
- **If screen spec lists "New DS Components Required"**: all listed components MUST be spec'd and designed first. Abort and prompt: "New component `{name}` needs to be created first. Run: `spec {name}`"
|
|
12
14
|
|
|
13
15
|
---
|
|
@@ -44,7 +46,25 @@ Parse from spec:
|
|
|
44
46
|
**Load Figma API rules (CRITICAL — read before writing any script):**
|
|
45
47
|
- `references/figma-api-rules.md` → all API patterns, variable binding, boilerplate
|
|
46
48
|
|
|
47
|
-
All paths relative to
|
|
49
|
+
All paths relative to `references/knowledge-base/`.
|
|
50
|
+
|
|
51
|
+
### 1e. Load Learnings
|
|
52
|
+
|
|
53
|
+
Load `references/knowledge-base/learnings.json` (skip if file doesn't exist — no learnings yet).
|
|
54
|
+
|
|
55
|
+
Filter applicable learnings:
|
|
56
|
+
- **Global learnings** (`scope: "global"`): always apply
|
|
57
|
+
- **Contextual learnings** (`scope: "contextual"`): match by `screenType` (from spec's description), `component`, or `section`
|
|
58
|
+
|
|
59
|
+
Display matched learnings before generation:
|
|
60
|
+
```
|
|
61
|
+
KNOWN PREFERENCES ({n} learnings):
|
|
62
|
+
─────────────────────────────────
|
|
63
|
+
• {rule} (signals: {n}, scope: {scope})
|
|
64
|
+
• {rule} (signals: {n}, scope: {scope})
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
Integrate these into pre-script audits: when a script creates an element matching a learning's context, use the learning's `to` token instead of the default.
|
|
48
68
|
|
|
49
69
|
**Registry key validation (BLOCKING):**
|
|
50
70
|
Before using any registry, verify that entries contain `key` fields (not just `id` or `name`):
|
|
@@ -73,8 +93,8 @@ Key rules applied: {bullet list}
|
|
|
73
93
|
|
|
74
94
|
**If the spec has a "Reference Screen" section with a Figma URL/node ID, this step is MANDATORY.**
|
|
75
95
|
|
|
76
|
-
1. **Screenshot the reference**
|
|
77
|
-
2. **Inspect the reference structure** via `figma_execute` — extract the node tree:
|
|
96
|
+
1. **Screenshot the reference** (console: `figma_take_screenshot({ node_id, file_key })`, official: `get_screenshot({ nodeId, fileKey })`)
|
|
97
|
+
2. **Inspect the reference structure** via Plugin API (console: `figma_execute`, official: `use_figma` with fileKey+description) — extract the node tree:
|
|
78
98
|
```js
|
|
79
99
|
return (async function() {
|
|
80
100
|
var ref = await figma.getNodeByIdAsync("REFERENCE_NODE_ID");
|
|
@@ -127,30 +147,40 @@ Ask the user:
|
|
|
127
147
|
- **Which Figma file?** (URL or fileKey)
|
|
128
148
|
- **Which page?** (or create a new page)
|
|
129
149
|
|
|
130
|
-
Verify connection:
|
|
150
|
+
Verify connection (transport-neutral — see transport-adapter.md Section F):
|
|
131
151
|
```
|
|
132
|
-
figma_get_status()
|
|
152
|
+
Console: figma_get_status()
|
|
153
|
+
Official: whoami() + test use_figma call
|
|
133
154
|
```
|
|
134
155
|
|
|
135
156
|
**Library activation check:** Verify DS libraries are **enabled** in the target file. `importComponentByKeyAsync` only works with published AND enabled libraries.
|
|
136
157
|
|
|
137
158
|
### 3. Generate the design — Atomic Steps
|
|
138
159
|
|
|
139
|
-
Write and execute Figma Plugin API scripts
|
|
160
|
+
Write and execute Figma Plugin API scripts (console: `figma_execute`, official: `use_figma` — see `references/transport-adapter.md` Section C for script format).
|
|
140
161
|
|
|
141
162
|
**Before writing any script, read `references/figma-api-rules.md`.** It contains:
|
|
142
163
|
- Mandatory patterns (FILL after appendChild, variable binding, font loading)
|
|
143
164
|
- DS component reuse rules (Rule 18) and canvas positioning (Rule 19)
|
|
144
165
|
- Standard script boilerplate with helpers
|
|
145
166
|
|
|
146
|
-
**Script execution via MCP:**
|
|
167
|
+
**Script execution via MCP (format depends on transport — see transport-adapter.md Section C):**
|
|
168
|
+
|
|
169
|
+
Console:
|
|
147
170
|
```
|
|
148
171
|
figma_execute({
|
|
149
172
|
code: "return (async function() { ... your Plugin API code ... return { success: true }; })();"
|
|
150
173
|
})
|
|
151
174
|
```
|
|
152
175
|
|
|
153
|
-
|
|
176
|
+
Official:
|
|
177
|
+
```
|
|
178
|
+
use_figma({
|
|
179
|
+
fileKey: "...",
|
|
180
|
+
description: "Step N: ...",
|
|
181
|
+
code: "await figma.loadFontAsync(...); ... return { success: true };"
|
|
182
|
+
})
|
|
183
|
+
```
|
|
154
184
|
|
|
155
185
|
**Atomic generation (MANDATORY approach):**
|
|
156
186
|
|
|
@@ -202,9 +232,10 @@ NEVER recreate as raw frame/text/shape. NEVER hardcode hex colors — always bin
|
|
|
202
232
|
| 3. Bind props | `componentPropertyReferences` on all nodes | ~30-40 | — |
|
|
203
233
|
| 4. Refinements | Adjust spacing, sizing, visual polish | ~20-30 | — |
|
|
204
234
|
|
|
205
|
-
**After each step:** verify visually with `figma_take_screenshot`
|
|
235
|
+
**After each step:** verify visually with a screenshot before proceeding (console: `figma_take_screenshot({ node_id, file_key })`, official: `get_screenshot({ nodeId, fileKey })` — both require nodeId and fileKey):
|
|
206
236
|
```
|
|
207
|
-
figma_take_screenshot({ node_id: "{rootOrSectionId}", file_key: "{fileKey}" })
|
|
237
|
+
Console: figma_take_screenshot({ node_id: "{rootOrSectionId}", file_key: "{fileKey}" })
|
|
238
|
+
Official: get_screenshot({ nodeId: "{rootOrSectionId}", fileKey: "{fileKey}" })
|
|
208
239
|
```
|
|
209
240
|
Compare the screenshot against the spec and reference patterns. If something is wrong, fix it before moving to the next step.
|
|
210
241
|
|
|
@@ -244,6 +275,26 @@ Only create raw elements for pure layout frames or when no DS component exists (
|
|
|
244
275
|
|
|
245
276
|
Verify all layers have semantic names (no "Frame", "Rectangle", "Group").
|
|
246
277
|
|
|
278
|
+
### 6. Save Snapshot
|
|
279
|
+
|
|
280
|
+
After successful generation, save a snapshot of the design's node tree for future `learn` diffing.
|
|
281
|
+
|
|
282
|
+
1. Run the node tree extraction script from `schemas/learnings.md` via `figma_execute`, using the root node ID from step 3
|
|
283
|
+
2. Save to `specs/active/{name}-snapshot.json` with structure:
|
|
284
|
+
```json
|
|
285
|
+
{
|
|
286
|
+
"meta": {
|
|
287
|
+
"spec": "{name}",
|
|
288
|
+
"generatedAt": "{ISO timestamp}",
|
|
289
|
+
"rootNodeId": "{rootId}",
|
|
290
|
+
"fileKey": "{fileKey}"
|
|
291
|
+
},
|
|
292
|
+
"tree": { ... extracted node tree ... }
|
|
293
|
+
}
|
|
294
|
+
```
|
|
295
|
+
|
|
296
|
+
This snapshot enables the `learn` action to detect user corrections later.
|
|
297
|
+
|
|
247
298
|
---
|
|
248
299
|
|
|
249
300
|
## Output
|
|
@@ -26,15 +26,32 @@ Append to `specs/history.log`:
|
|
|
26
26
|
{date} | {name} | {component|screen} | {figma_url} | {author}
|
|
27
27
|
```
|
|
28
28
|
|
|
29
|
-
### 4.
|
|
29
|
+
### 4. Persist learnings
|
|
30
|
+
|
|
31
|
+
Check if `learn` was run during this cycle (i.e., `references/knowledge-base/learnings.json` was updated with entries referencing this spec):
|
|
32
|
+
|
|
33
|
+
- If yes: learnings are already persisted — confirm count:
|
|
34
|
+
```
|
|
35
|
+
Learnings persisted: {n} learnings, {n} flags from this spec.
|
|
36
|
+
```
|
|
37
|
+
- If no learnings exist yet but a snapshot exists (`specs/active/{name}-snapshot.json`):
|
|
38
|
+
```
|
|
39
|
+
💡 A snapshot exists but `learn` was never run.
|
|
40
|
+
If you made manual corrections in Figma, run `learn` before `done` to capture them.
|
|
41
|
+
Skip? (learnings will be lost)
|
|
42
|
+
```
|
|
43
|
+
If user skips, proceed. If not, abort and let them run `learn` first.
|
|
44
|
+
|
|
45
|
+
### 5. Brief retro
|
|
30
46
|
|
|
31
47
|
- **What went well?** (patterns to repeat)
|
|
32
48
|
- **What was friction?** (improvements for the workflow)
|
|
33
49
|
- **What was learned?** (reusable knowledge)
|
|
34
50
|
|
|
35
|
-
###
|
|
51
|
+
### 6. Cleanup
|
|
36
52
|
|
|
37
|
-
Delete
|
|
53
|
+
- Delete snapshot file: `specs/active/{name}-snapshot.json` (if exists)
|
|
54
|
+
- Delete any remaining temp files
|
|
38
55
|
|
|
39
56
|
---
|
|
40
57
|
|
|
@@ -45,4 +62,5 @@ Delete any remaining temp files if not already done.
|
|
|
45
62
|
|
|
46
63
|
Figma: {url}
|
|
47
64
|
Spec archived: specs/shipped/{name}-spec.md
|
|
65
|
+
Learnings: {n} persisted
|
|
48
66
|
```
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
# Action: learn
|
|
2
|
+
|
|
3
|
+
> Diff the generated design against the current Figma state, extract user corrections, and persist learnings.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Prerequisites
|
|
8
|
+
|
|
9
|
+
- Active spec in `specs/active/` (abort if missing: "No active spec. Run: `spec {name}`")
|
|
10
|
+
- Snapshot file exists at `specs/active/{name}-snapshot.json` (abort if missing: "No snapshot found. The design must have been generated with the latest workflow. Re-run: `design`")
|
|
11
|
+
- Figma MCP transport available (console: `figma_get_status`, official: `whoami` — see `references/transport-adapter.md` Section F)
|
|
12
|
+
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
## Procedure
|
|
16
|
+
|
|
17
|
+
### 1. Load artifacts
|
|
18
|
+
|
|
19
|
+
- Read the active spec from `specs/active/{name}-spec.md`
|
|
20
|
+
- Read the snapshot from `specs/active/{name}-snapshot.json`
|
|
21
|
+
- Read existing learnings from `references/knowledge-base/learnings.json` (create empty structure if file doesn't exist)
|
|
22
|
+
- Load `references/knowledge-base/registries/variables.json` → for token resolution
|
|
23
|
+
|
|
24
|
+
### 2. Re-extract current state
|
|
25
|
+
|
|
26
|
+
Run the same node tree extraction script used for snapshots (see `schemas/learnings.md`) via Plugin API execution, using the `rootNodeId` and `fileKey` from the snapshot's `meta`.
|
|
27
|
+
|
|
28
|
+
```
|
|
29
|
+
Console: figma_execute({ code: "...extraction script with ROOT_NODE_ID from snapshot meta..." })
|
|
30
|
+
Official: use_figma({ fileKey: "...", description: "Re-extract node tree for learn diff", code: "...same script without IIFE wrapper..." })
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
See `references/transport-adapter.md` Section C for script format differences.
|
|
34
|
+
|
|
35
|
+
### 3. Diff snapshot vs current state
|
|
36
|
+
|
|
37
|
+
Compare the two JSON trees in context. Claude performs this comparison directly — no custom diff code needed.
|
|
38
|
+
|
|
39
|
+
**Match strategy:**
|
|
40
|
+
- Match nodes by `id` (stable across edits)
|
|
41
|
+
- For each matched node, compare: `layoutMode`, `itemSpacing`, `paddingTop/Bottom/Left/Right`, `cornerRadius`, `fills`, `boundVariables`, `width`, `height`, `componentKey`
|
|
42
|
+
- Detect **added nodes** (present in current, absent in snapshot)
|
|
43
|
+
- Detect **removed nodes** (present in snapshot, absent in current)
|
|
44
|
+
- Detect **property changes** (same node, different values)
|
|
45
|
+
|
|
46
|
+
**Ignore:**
|
|
47
|
+
- Pure name changes (layer renaming)
|
|
48
|
+
- Position changes (x, y) unless they indicate a structural move
|
|
49
|
+
|
|
50
|
+
### 4. Classify changes
|
|
51
|
+
|
|
52
|
+
For each detected change:
|
|
53
|
+
|
|
54
|
+
```
|
|
55
|
+
Does the new value use a DS token (bound variable)?
|
|
56
|
+
→ YES: Classify as LEARNING
|
|
57
|
+
→ NO (hardcoded hex, raw px value, unbound): Classify as FLAG
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
**Token resolution:** Check `boundVariables` in the current tree. If the property has a bound variable ID, resolve it against `registries/variables.json` to get the token name.
|
|
61
|
+
|
|
62
|
+
### 5. Extract learnings
|
|
63
|
+
|
|
64
|
+
For each LEARNING-classified change:
|
|
65
|
+
|
|
66
|
+
1. **Determine context:**
|
|
67
|
+
- `screenType`: from the spec's description or visual reference section
|
|
68
|
+
- `component`: nearest component ancestor name, or the node's own name if it's a component instance
|
|
69
|
+
- `section`: parent frame name (e.g., "header", "content", "sidebar")
|
|
70
|
+
|
|
71
|
+
2. **Check for existing learning:** Search `learnings.json` for a learning with matching `context` + `change.property` + `change.to.token`
|
|
72
|
+
- If found: increment `signals`, append to `history`
|
|
73
|
+
- If not found: create new learning entry
|
|
74
|
+
|
|
75
|
+
3. **Generate rule:** Write a human-readable rule describing the preference (e.g., "For settings screens, cards use spacing/medium (not large)")
|
|
76
|
+
|
|
77
|
+
4. **Check promotion:** After updating signals, check if any contextual learning qualifies for global promotion:
|
|
78
|
+
- `signals >= 3`
|
|
79
|
+
- Observations from ≥ 2 different `screenType` values
|
|
80
|
+
- No contradiction (same property pointing to different tokens in different learnings)
|
|
81
|
+
|
|
82
|
+
### 6. Extract flags
|
|
83
|
+
|
|
84
|
+
For each FLAG-classified change:
|
|
85
|
+
|
|
86
|
+
1. Create a flag entry with the spec name, node description, and what was hardcoded
|
|
87
|
+
2. Add to `flags` array in `learnings.json`
|
|
88
|
+
|
|
89
|
+
### 7. Update spec
|
|
90
|
+
|
|
91
|
+
If learnings were extracted (DS-compliant changes):
|
|
92
|
+
- Update the active spec's token references to match the corrected values
|
|
93
|
+
- This ensures the spec in `specs/shipped/` (after `done`) reflects the final design
|
|
94
|
+
|
|
95
|
+
### 8. Save learnings
|
|
96
|
+
|
|
97
|
+
Write updated `learnings.json` to `references/knowledge-base/learnings.json`.
|
|
98
|
+
|
|
99
|
+
Update `meta.lastUpdated` to today's date.
|
|
100
|
+
|
|
101
|
+
### 9. Report
|
|
102
|
+
|
|
103
|
+
```markdown
|
|
104
|
+
## Learn: {name}
|
|
105
|
+
|
|
106
|
+
### Changes detected: {total count}
|
|
107
|
+
|
|
108
|
+
### Learnings extracted: {count}
|
|
109
|
+
| # | Context | Property | From | To | Rule |
|
|
110
|
+
|---|---------|----------|------|----|------|
|
|
111
|
+
| 1 | settings / card | itemSpacing | spacing/large (24) | spacing/medium (16) | Cards in settings use medium spacing |
|
|
112
|
+
|
|
113
|
+
### Flags: {count}
|
|
114
|
+
| # | Node | Issue |
|
|
115
|
+
|---|------|-------|
|
|
116
|
+
| 1 | StatusBadge | Hardcoded hex #FF5722 — no DS token bound |
|
|
117
|
+
|
|
118
|
+
### Promotions: {count}
|
|
119
|
+
- "{rule}" promoted to global (signals: {n}, screenTypes: {list})
|
|
120
|
+
|
|
121
|
+
### Spec updated: {yes/no}
|
|
122
|
+
{list of spec changes if any}
|
|
123
|
+
|
|
124
|
+
Next: Continue editing in Figma and run `learn` again, or run: `done`
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
---
|
|
128
|
+
|
|
129
|
+
## Output
|
|
130
|
+
|
|
131
|
+
```
|
|
132
|
+
Learn complete for {name}.
|
|
133
|
+
|
|
134
|
+
Learnings: {n} extracted ({n} new, {n} reinforced, {n} promoted)
|
|
135
|
+
Flags: {n} hardcoded values flagged
|
|
136
|
+
Spec: {updated/unchanged}
|
|
137
|
+
|
|
138
|
+
Learnings saved to knowledge-base/learnings.json
|
|
139
|
+
Next: `done` to archive, or continue editing and `learn` again.
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
---
|
|
143
|
+
|
|
144
|
+
## Transition
|
|
145
|
+
|
|
146
|
+
- If user wants to continue editing → they can run `learn` again after more changes
|
|
147
|
+
- When satisfied → suggest: "Run: `done`"
|