MCP SDK Audit
awdr74100/figwright
Upgrade @modelcontextprotocol/server (the MCP TypeScript SDK v2) and prove the wire contract survived.
Standalone validator for a completed figma-from-code rebuild.
$ npx skills add bitovi/ai-enablement-prompts --skill figma-from-code-validator -a claude-codeProject install by default; add -g for ~/.claude/skills/.
$ gh skill install bitovi/ai-enablement-prompts figma-from-code-validator --agent claude-codeProject scope by default; add --scope user for a personal install. Needs GitHub CLI 2.90.0 or later (public preview).
$ git clone --depth 1 https://github.com/bitovi/ai-enablement-prompts.git skills-src && mkdir -p .claude/skills && cp -r skills-src/plugins/figma-from-code/skills/figma-from-code/10-validator .claude/skills/figma-from-code-validator && rm -rf skills-srcUse ~/.claude/skills/ instead of .claude/skills for a personal install. The folder must contain SKILL.md.
Claude Code skills documentation · loads skills from .claude/skills/
Install the "figma-from-code-validator" agent skill from https://github.com/bitovi/ai-enablement-prompts/tree/main/plugins/figma-from-code/skills/figma-from-code/10-validator into .claude/skills/figma-from-code-validator/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "figma-from-code-validator", then confirm the skill loads.Claude Code copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$skill-installer install https://github.com/bitovi/ai-enablement-prompts/tree/main/plugins/figma-from-code/skills/figma-from-code/10-validatorType this inside Codex. $skill-installer <name> installs a curated skill from openai/skills. The installer writes to $CODEX_HOME/skills (default ~/.codex/skills). Restart Codex if the skill does not show up.
$ npx skills add bitovi/ai-enablement-prompts --skill figma-from-code-validator -a codexProject install goes to .agents/skills/; add -g for ~/.codex/skills/.
$ gh skill install bitovi/ai-enablement-prompts figma-from-code-validator --agent codexProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/bitovi/ai-enablement-prompts.git skills-src && mkdir -p .agents/skills && cp -r skills-src/plugins/figma-from-code/skills/figma-from-code/10-validator .agents/skills/figma-from-code-validator && rm -rf skills-srcUse ~/.agents/skills/ instead of .agents/skills for a personal install.
Codex skills documentation · loads skills from .agents/skills/
Install the "figma-from-code-validator" agent skill from https://github.com/bitovi/ai-enablement-prompts/tree/main/plugins/figma-from-code/skills/figma-from-code/10-validator into .agents/skills/figma-from-code-validator/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "figma-from-code-validator", then confirm the skill loads.Codex copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ npx skills add bitovi/ai-enablement-prompts --skill figma-from-code-validator -a cursorProject install goes to .agents/skills/; add -g for ~/.cursor/skills/.
$ gh skill install bitovi/ai-enablement-prompts figma-from-code-validator --agent cursorProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/bitovi/ai-enablement-prompts.git skills-src && mkdir -p .cursor/skills && cp -r skills-src/plugins/figma-from-code/skills/figma-from-code/10-validator .cursor/skills/figma-from-code-validator && rm -rf skills-srcUse ~/.cursor/skills/ instead of .cursor/skills for a personal install.
Cursor skills documentation · loads skills from .cursor/skills/, .agents/skills/, .claude/skills/, .codex/skills/
Install the "figma-from-code-validator" agent skill from https://github.com/bitovi/ai-enablement-prompts/tree/main/plugins/figma-from-code/skills/figma-from-code/10-validator into .cursor/skills/figma-from-code-validator/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "figma-from-code-validator", then confirm the skill loads.Cursor copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ gemini skills install https://github.com/bitovi/ai-enablement-prompts.git --path plugins/figma-from-code/skills/figma-from-code/10-validator--scope user (default) or --scope workspace; --path is the subfolder of the repo that holds the skill; --consent skips the security confirmation prompt.
$ npx skills add bitovi/ai-enablement-prompts --skill figma-from-code-validator -a gemini-cliProject install goes to .agents/skills/; add -g for ~/.gemini/skills/.
$ gh skill install bitovi/ai-enablement-prompts figma-from-code-validator --agent gemini-cliProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/bitovi/ai-enablement-prompts.git skills-src && mkdir -p .gemini/skills && cp -r skills-src/plugins/figma-from-code/skills/figma-from-code/10-validator .gemini/skills/figma-from-code-validator && rm -rf skills-srcUse ~/.gemini/skills/ instead of .gemini/skills for a personal install, then run /skills reload.
Gemini CLI skills documentation · loads skills from .gemini/skills/, .agents/skills/
Install the "figma-from-code-validator" agent skill from https://github.com/bitovi/ai-enablement-prompts/tree/main/plugins/figma-from-code/skills/figma-from-code/10-validator into .gemini/skills/figma-from-code-validator/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "figma-from-code-validator", then confirm the skill loads.Gemini CLI copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ gh skill install bitovi/ai-enablement-prompts figma-from-code-validatorInstalls for Copilot at project scope by default; add --scope user for a personal install. Preview a skill first with gh skill preview. Needs GitHub CLI 2.90.0 or later (public preview).
$ npx skills add bitovi/ai-enablement-prompts --skill figma-from-code-validator -a github-copilotProject install goes to .agents/skills/; add -g for ~/.copilot/skills/.
$ git clone --depth 1 https://github.com/bitovi/ai-enablement-prompts.git skills-src && mkdir -p .github/skills && cp -r skills-src/plugins/figma-from-code/skills/figma-from-code/10-validator .github/skills/figma-from-code-validator && rm -rf skills-srcUse ~/.copilot/skills/ instead of .github/skills for a personal install. Commit .github/skills so cloud agent and code review can use it.
GitHub Copilot skills documentation · loads skills from .github/skills/, .claude/skills/, .agents/skills/
Install the "figma-from-code-validator" agent skill from https://github.com/bitovi/ai-enablement-prompts/tree/main/plugins/figma-from-code/skills/figma-from-code/10-validator into .github/skills/figma-from-code-validator/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "figma-from-code-validator", then confirm the skill loads.GitHub Copilot copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ npx skills add bitovi/ai-enablement-prompts --skill figma-from-code-validator -a opencodeOpenCode documents no install command of its own. Project install goes to .agents/skills/; add -g for ~/.config/opencode/skills/.
$ gh skill install bitovi/ai-enablement-prompts figma-from-code-validator --agent opencodeProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/bitovi/ai-enablement-prompts.git skills-src && mkdir -p .opencode/skills && cp -r skills-src/plugins/figma-from-code/skills/figma-from-code/10-validator .opencode/skills/figma-from-code-validator && rm -rf skills-srcUse ~/.config/opencode/skills/ instead of .opencode/skills for a personal install.
OpenCode skills documentation · loads skills from .opencode/skills/, .claude/skills/, .agents/skills/
Install the "figma-from-code-validator" agent skill from https://github.com/bitovi/ai-enablement-prompts/tree/main/plugins/figma-from-code/skills/figma-from-code/10-validator into .opencode/skills/figma-from-code-validator/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "figma-from-code-validator", then confirm the skill loads.OpenCode copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
figma-from-code-validatorStandalone validator for a completed figma-from-code rebuild.
Figma From Code Validator is an agent skill from bitovi/ai-enablement-prompts. Standalone validator for a completed figma-from-code rebuild. Navigates the live app, screenshots each component in its natural context, and compares against the matching Figma variant. Also used by the Phase 5 orchestrator agent as a reference for the Component App Map and comparison scripts.
Its SKILL.md is about 6.4k tokens, which your agent loads only when the skill is triggered. The skill folder holds 1 other file (for example `README.md`).
It sits in Agent Workflows. It works with Figma. The repository describes itself as: Prompts Bitovi uses for software development. The licence is MIT.
5 steps, taken from the step headings in SKILL.md.
Read from SKILL.md and the folder at commit df229b1. It shows what the files ask for, not the result of running them.
Pre-approves nothing: there is no allowed-tools line, so your agent's usual permission prompts apply.
From allowed-tools in the SKILL.md frontmatter.
Shell commands in SKILL.md call:
nodecurlFrom the folder's file list and the shell code blocks in SKILL.md.
No URLs in SKILL.md. Its commands use curl, which can reach the network depending on how they are called.
From URLs in SKILL.md, links to its own repository left out.
Names no API keys, tokens, secrets or passwords.
From names ending in _API_KEY, _TOKEN, _SECRET, _KEY or _PASSWORD in SKILL.md.
Figma From Code Validator loads about 6.4k tokens when it runs. Until then it costs about 80 tokens; SKILL.md has 1,903 words of instructions outside code blocks.
Estimates: characters ÷ 4, the usual rule of thumb; real counts depend on the model's tokenizer. Scripts and assets cost tokens only if the agent reads them.
The automated check found no risky patterns in SKILL.md.
Automated static check — not a guarantee. Review scripts before installing. It scans the text of SKILL.md for risky patterns (piping downloads into a shell, reading credential files, hidden Unicode, destructive commands); files beside SKILL.md are not scanned.
The full file from bitovi/ai-enablement-prompts at commit df229b1, republished under its MIT licence (© bitovi). 1,903 words, ~6,364 tokens.
.claude/skills/figma-from-code-validator/SKILL.md (or your agent's skills folder). This skill also uses 1 other file; get the full folder from GitHub.Validates the output of figma-from-code by navigating the live app, screenshotting each component in its natural context, and comparing against the matching Figma variant — not the entire component set. Produces a structured report with side-by-side screenshots.
This skill can be used two ways:
figma-from-code to verify the output (standalone)Placeholders like
{devServerUrl}and{skillRoot}resolve fromstate.json → config.
{devServerUrl} — use the URL from state.json → config.devServerUrl (default http://localhost:5173).temp/figma-from-code/state.json must exist (produced by figma-from-code)compare.js for pixel diff is vendored at {skillRoot}/scripts/compare.jsPhase 1: Inventory → list all Figma components + classify app visibility
Phase 1e: Variant Resolve → for each component set, find the specific variant used in the app
Phase 2: Screenshots → process each tier sequentially to capture app + Figma screenshots and run pixel diffs
Phase 3: Structural → check variables, pages, screen sizes
Phase 4: Report → merge tier results, write .temp/figma-validation/report.mdcat .temp/figma-from-code/state.jsonExtract fileKey.
// use_figma
await figma.setCurrentPageAsync(figma.root.children.find((p) => p.name === '📦 Components'));
const sets = figma.currentPage.findAll((n) => n.type === 'COMPONENT_SET');
const singles = figma.currentPage.children.filter((n) => n.type === 'COMPONENT');
const all = [
...sets.map((s) => ({ name: s.name, id: s.id, type: 'set' })),
...singles.map((s) => ({ name: s.name, id: s.id, type: 'single' })),
];
return JSON.stringify(all);Use the Component App Map below to assign each component a url, selector, optional click action, and figmaVariant (the variant properties that match what's rendered in the app).
curl -s --max-time 3 {devServerUrl} > /dev/null && echo "running" || echo "not_running"If not_running: halt and tell the user to run the dev server.
Print the classification to the conversation:
📱 App visible (44): Button, Input, ...
⚠️ Requires interaction (4): Dialog, Sheet, ...
🚫 Not visible in app (1): Skeleton (loading state only)This is the key step that ensures Figma screenshots match the app variant.
For every component whose type === 'set' and that has a figmaVariant specified in the Component App Map, resolve the specific child variant node ID before taking screenshots.
Without this step, get_screenshot(fileKey, setNodeId) returns an image of all variants tiled in the component set — not the single variant that the app is rendering. Resolving to the child node gives an apples-to-apples comparison.
// use_figma
const setNodeId = '{nodeId from Phase 1b}';
const targetProps = { Variant: 'primary', State: 'Default' }; // from Component App Map figmaVariant column
const componentSet = figma.getNodeById(setNodeId);
if (!componentSet || componentSet.type !== 'COMPONENT_SET') {
return JSON.stringify({
resolvedId: setNodeId,
resolvedName: componentSet?.name ?? 'unknown',
fallback: true,
});
}
// Log available variant property names and their values to aid debugging
const available = componentSet.children.map((c) => ({
id: c.id,
name: c.name,
props: c.variantProperties,
}));
// Try exact match first (case-insensitive values)
let match = componentSet.children.find((child) =>
Object.entries(targetProps).every(
([k, v]) => child.variantProperties?.[k]?.toLowerCase() === v.toLowerCase()
)
);
// Partial match fallback: match only props that exist on the set's property keys
if (!match) {
const availableKeys = Object.keys(componentSet.children[0]?.variantProperties ?? {});
const filteredTarget = Object.fromEntries(
Object.entries(targetProps).filter(([k]) => availableKeys.includes(k))
);
match = componentSet.children.find((child) =>
Object.entries(filteredTarget).every(
([k, v]) => child.variantProperties?.[k]?.toLowerCase() === v.toLowerCase()
)
);
}
// Last resort: first child
match = match ?? componentSet.children[0];
return JSON.stringify({
resolvedId: match.id,
resolvedName: match.name,
props: match.variantProperties,
available,
});Store the resolved variantNodeId for each component. Use this in Phase 2 when calling get_screenshot.
Some components appear in multiple variants in the app (e.g., Button appears as primary on form submit and ghost in menus). For these, create two entries in the comparison table:
| Entry | App Variant | Figma Variant Props |
|---|---|---|
| Button (submit) | button[type="submit"] on the create form page | {Variant: "primary", Size: "regular"} |
| Button (menu action) | [data-radix-dropdown-menu-content] button on list page | {Variant: "ghost", Size: "small"} |
The Component App Map assigns each Figma component a URL, Playwright CSS selector, optional click/hover action, and Figma variant properties for comparison targeting.
This map is built dynamically during Phase 1c from the component-map.json output (Phase 0a). It is NOT hardcoded.
The screenshot script is: {skillRoot}/scripts/screenshot.js
Usage:
# Element screenshot (preferred)
node screenshot.js <url> <output> --selector "css" [--click "click-css"] [--hover "hover-css"] [--variant "label"] [width] [height]
# Full-page fallback
node screenshot.js <url> <output> [width] [height]Flags:
--selector — CSS selector for the element to screenshot--click — click this element before screenshotting (opens overlays, enters edit mode)--hover — hover over this element before screenshotting (reveals tooltips, hover cards)--variant — label printed in output for logging (no effect on screenshot)--nth N — use the Nth matching element (0-indexed)Batch manifest entries additionally support fallbackSelectors (ordered alternates tried when the primary selector times out — the output line notes which one was used) and click as an ordered array for multi-step interactions.
For each component discovered in component-map.json, prefer its capture object — it records the exact URL, validated selector, ordered fallbackSelectors, and the interaction replay recipe (clicks array + hover) from discovery time. Use capture.url verbatim; never pair a selector with a different route than the one it was derived on.
For legacy maps without capture:
component-map.json -> routes)component-map.json -> selector). Prefer [data-component="Name"], [aria-label="..."], or class-based selectors{Variant: "primary", State: "Default"})| Component Type | Selector Strategy | Example |
|---|---|---|
| Always visible (nav, header, sidebar) | aria-label or semantic HTML | header[aria-label="Main navigation"] |
| List panels | Class-based width selectors | [class*="w-[200px]"] |
| Detail panels | Flex layout selectors | [class*="flex-1"][class*="flex-col"] |
| Form inputs | Input type + placeholder | input[placeholder="..."], textarea |
| Buttons | Type or role selectors | button[type="submit"], a[href="..."] |
| Inline editing | Click to enter edit mode | --click "h1" then screenshot the input |
| Overlays/dialogs | Click trigger, screenshot overlay | --click "button[aria-label='...']" then [role="dialog"] |
| Embedded components | Parent context selectors | [class*="ComponentName"] |
Some components are not rendered by default and require special handling:
| Type | Reason | Capture Strategy |
|---|---|---|
| Loading states (e.g., Skeleton) | Only visible during data fetch | Capture during initial page load before data arrives |
| Error states (e.g., Alert) | Only visible on errors | Simulate a network error |
| Hover components (Tooltip, HoverCard) | Requires hover | Use --hover "trigger-selector" |
| Click-to-reveal (Calendar, Popover) | Requires interaction | Use --click "trigger-selector" |
| Embedded primitives (Badge, Checkbox) | Only inside parent components | Screenshot parent, or open container first |
| Not used in UI | Component exists but not rendered | Skip — note as not_visible in report |
For hover-only components, use Playwright's .hover() API in a custom script rather than the --click flag.
Process all tiers sequentially inline. For each tier, handle every component: check for pre-built screenshots, capture app + Figma screenshots, run the pixel diff. Components within a tier share URLs, so reuse a single Playwright page load per URL where possible.
For each tier in state.json -> buildOrder.tiers, process all components using Steps 2a–2e below. After completing a tier, write results to .temp/figma-validation/tier-{N}-results.json:
[{ "name": "...", "matchPct": 94.2, "borderMatchPct": 91.0, "verdict": "match", "issues": [] }, ...]After all tiers are processed, read each tier-{N}-results.json and merge into a single component list for Phase 3/4. Components with verdict: "mismatch" or verdict: "minor_diff" are candidates for Phase 5 fixes.
Run these steps for every component in each tier.
Before capturing a new screenshot, check if the orchestrator already captured one:
ls .temp/figma-from-code/screenshots/{ComponentName}/app.png 2>/dev/null && echo "exists" || echo "missing".temp/figma-validation/screenshots/{ComponentName}/app.png — skip the Playwright capture for this component.Also check for pre-extracted text:
ls .temp/figma-from-code/screenshots/{ComponentName}/text.json 2>/dev/null && echo "exists" || echo "missing"extract-text.js (Step 2b-text) and use it to update the Figma component's text nodes before screenshotting (Step 2c-text).Run the screenshot script with --selector:
node {skillRoot}/scripts/screenshot.js \
"{devServerUrl}{url}" \
".temp/figma-validation/screenshots/{ComponentName}/app.png" \
--selector "{selector}" \
1440 900If the component requires a click first, use --click:
node {skillRoot}/scripts/screenshot.js \
"{devServerUrl}{url}" \
".temp/figma-validation/screenshots/{ComponentName}/app.png" \
--selector "{screenshot-selector}" \
--click "{click-selector}" \
1440 900If text.json was not produced during the rebuild, run the extractor now and update the Figma component's text nodes to match the app before screenshotting:
Extract:
node {skillRoot}/scripts/extract-text.js \
"{devServerUrl}{url}" \
--selector "{selector}" \
[--click "{click-selector}"] \
[--nth N] \
> ".temp/figma-validation/screenshots/{ComponentName}/text.json"Inject into Figma (run once per component, before step 2d):
// use_figma — update Figma text nodes to match app text
async function injectText(nodeId, textJson) {
const node = figma.getNodeById(nodeId);
const { lines, headings, inputs, buttons, labels } = textJson;
// Collect all visible text strings in app order
const appStrings = [...headings, ...labels, ...inputs, ...buttons, ...lines]
.filter((s, i, arr) => s && arr.indexOf(s) === i) // dedupe, preserve order
.slice(0, 20);
let strIdx = 0;
async function updateTextNodes(n) {
if (n.type === 'TEXT' && strIdx < appStrings.length) {
const s = appStrings[strIdx++];
if (s) {
const fn = n.fontName === figma.mixed ? { family: 'Inter', style: 'Regular' } : n.fontName;
await figma.loadFontAsync(fn);
n.characters = s;
}
}
if ('children' in n) {
for (const c of n.children) await updateTextNodes(c);
}
}
await updateTextNodes(node);
}
const textJson = JSON.parse('{contents of text.json}');
await injectText('{variantNodeId}', textJson);
return 'done';Skip this step for components that have no app selector (not visible in app).
Before taking the Figma screenshot, run a structural check on the resolved variant node. This catches defects that are invisible in a screenshot but cause visual discrepancies in the app.
// use_figma
function auditNode(node) {
const issues = [];
// INSIDE stroke alignment creates a double-border visual that doesn't match CSS
if ('strokeAlign' in node && node.strokeAlign === 'INSIDE' && node.strokes?.length > 0) {
issues.push({ type: 'inside_stroke', node: node.id, name: node.name });
}
// Multiple overlapping fills can cause unexpected color blending
if ('fills' in node && node.fills.filter((f) => f.visible !== false).length > 1) {
issues.push({ type: 'multiple_fills', node: node.id, count: node.fills.length });
}
if ('children' in node) node.children.forEach((c) => issues.push(...auditNode(c)));
return issues;
}
const node = figma.getNodeById('{variantNodeId}');
const issues = auditNode(node);
return JSON.stringify(issues);If any issues are returned, fix them before screenshotting (e.g., change strokeAlign from INSIDE to OUTSIDE). Note the fix in the report.
Always use the variantNodeId resolved in Phase 1e, NOT the component set node ID.
Always request scale: 1 to produce a 1x export that matches the app screenshots (captured at deviceScaleFactor: 1 by screenshot.js). Without explicit scale, Figma may return higher-resolution images that cause dimension mismatches during comparison.
get_screenshot(fileKey, variantNodeId, { scale: 1 })
curl -sL "{image_url}" -o ".temp/figma-validation/screenshots/{ComponentName}/figma.png"{} (single) or type === 'single', use the node ID as-is.Button-primary/ and Button-ghost/.Why this matters: Screenshotting the component set shows all variants stacked side-by-side in Figma. Screenshotting the resolved variant node shows only the single variant that matches what the app renders — making the visual comparison meaningful.
After both screenshots are saved, run the comparison script:
node {skillRoot}/scripts/compare.js \
".temp/figma-validation/screenshots/{ComponentName}/app.png" \
".temp/figma-validation/screenshots/{ComponentName}/figma.png" \
".temp/figma-validation/screenshots/{ComponentName}/"The script outputs:
diff.png — red pixels mark differences, dimmed original provides contextcomparison.json — { matchPct, borderMatchPct, verdict, borderVerdict }0 = match, 1 = minor_diff (⚠️ flag for review), 2 = mismatch (❌ auto-defect)Thresholds:
The border-region check catches subtle styling defects (extra strokes, wrong border color, box-shadow presence/absence) that are masked by text-content differences in the overall score. Always include the diff.png in the report table regardless of verdict — it lets you visually verify what the score detected.
Note on text-content diffs: When Figma components were built with real app text (via extract-text.js in Phase 3), scores should be high (> 90%) for matching components. A score of 75–90% on a text-seeded component is meaningful — inspect the diff image for structural differences (layout, spacing, color). If components were built with placeholder text (older rebuild), scores of 60–85% are expected for text-heavy components and are not defects; in that case rely on the border score and diff image to find real issues.
// use_figma
const results = {};
const colls = figma.variables.getLocalVariableCollections();
results.collections = colls.map((c) => ({
name: c.name,
mode: c.modes[0].name,
count: c.variableIds.length,
}));
results.pages = figma.root.children.map((p) => p.name);
await figma.setCurrentPageAsync(figma.root.children.find((p) => p.name === '📄 Screens'));
results.screens = figma.currentPage.children.map((f) => ({
name: f.name,
w: Math.round(f.width),
h: Math.round(f.height),
}));
await figma.setCurrentPageAsync(figma.root.children.find((p) => p.name === '🎨 Foundations'));
results.foundationFrames = figma.currentPage.children.map((f) => f.name);
return JSON.stringify(results);Validate variable counts against the actual counts from Phase 1 (stored in state.json). Verify the expected number of pages, foundation frames, and screens match the project's configuration.
Output: .temp/figma-validation/report.md
# Figma Rebuild Validation Report
File: {fileKey} | Generated: {timestamp}
## Summary
| | Count |
| ---------------------- | ------------- |
| Components in Figma | {total} |
| Screenshotted from app | {captured} |
| Not visible in app | {skipped} |
| Screenshot failures | {failed} |
| Structural QA fixes | {structFixes} |
| Fixed after validation | {fixed} |
## Structural Checks
...
## Components Not Visible in App
| Component | Reason |
| --------- | ------ |
...
## Screenshot Comparisons
### {ComponentName}
Figma variant: `{variantProperties}` (node: `{variantNodeId}`)
Pixel score: **{matchPct}%** overall | **{borderMatchPct}%** border — verdict: `{verdict}`
| App (`{url}`) | Figma (`{variantNodeId}`) | Diff |
| ------------------------------------------- | ----------------------------------------------- | --------------------------------------------- |
|  |  |  |After writing the report, assess whether any components have visual defects or mismatches:
Runs up to 3 iterations. Each iteration attempts to fix all remaining defects, re-screenshots, and re-evaluates.
Step 5a — Identify defects
Review the report for all components marked as mismatched or defective. On iteration 1 this is the initial report; on subsequent iterations, only components still marked ⚠️ Still Defective.
Step 5b — Fix each defective component in Figma
For each defective component:
use_figmaget_screenshot(fileKey, variantNodeId, { scale: 1 }) — use the same resolved variant node ID, not the set.temp/figma-validation/screenshots/{ComponentName}/figma.pngfigma.png against the existing app.pngNever re-attempt a component already marked ✅ Fixed in a prior iteration.
Step 5c — Update the report
Append an iteration section to report.md:
## Fix Loop — Iteration {N}
| Component | Status | Notes |
| --------- | ------------------ | --------------------------------------- |
| Button | ✅ Fixed | Corrected border-radius from 4px to 6px |
| Input | ⚠️ Still Defective | Focus ring color still wrong |Update the summary counter: Fixed after validation: {total fixed so far}.
Step 5d — Exit conditions
## Unresolved After 3 Fix Iterations
| Component | Remaining Issue |
| --------- | ----------------------------------- |
| Input | Focus ring color does not match app |.temp/figma-validation/
├── report.md
└── screenshots/
├── Button-primary/
│ ├── app.png ← Playwright element screenshot from live app
│ └── figma.png ← Figma MCP get_screenshot of resolved variant node
├── Button-ghost/
│ ├── app.png
│ └── figma.png
└── Input/
├── app.png
└── figma.png| Error | Action |
|---|---|
| Dev server not running | Halt, tell user to run the dev server |
| Component set has no matching variant | Log resolved variant + all available props; use first child; note in report |
| Selector not found on page | Log as selector_not_found, skip; note in report |
| Element exists but empty/zero-size | Log as element_empty, try broader selector |
| Requires interaction not yet supported | Note as requires_interaction, include fallback full-page screenshot |
| Component not visible in app | Note as not_visible, include Figma variant screenshot only |
Never stop the full run for a single component failure.
© bitovi, MIT. Rendered from Markdown: HTML in the file is shown as text, images as links, and headings moved down two levels. Raw file
SKILL.md and 1 other file in plugins/figma-from-code/skills/figma-from-code/10-validator of bitovi/ai-enablement-prompts.
Open the folder on GitHubat commit df229b1
Figma From Code Validator next to the 5 skills that share the most tags, products or categories with it. Stars are the repository's; “used in” counts other GitHub owners with a copy.
| Skill | Stars | Used in | Tokens | Auto-check | Licence | Repo updated |
|---|---|---|---|---|---|---|
| Figma From Code Validator this skillbitovi/ai-enablement-prompts | 121 | — | ~6.4k | Automated safety check: Pass | MIT | |
| MCP SDK Auditawdr74100/figwright | 977 | — | ~4.1k | Automated safety check: Pass | MIT | |
| Integration Orchestratorrampstackco/claude-skills | 935 | — | ~5.3k | Automated safety check: Pass | MIT | |
| Product Designqf-studio/navigator | 354 | — | ~5.1k | Automated safety check: Notes | MIT | |
| MCP ServerWellApp-ai/Well | 345 | — | ~679 | Automated safety check: Pass | MIT | |
| Figma Handoff Gatehashgraph-online/awesome-codex-plugins | 1.2k | — | ~5k | Automated safety check: Pass | MIT |
awdr74100/figwright
Upgrade @modelcontextprotocol/server (the MCP TypeScript SDK v2) and prove the wire contract survived.
rampstackco/claude-skills
Generate a phased delivery orchestration plan for creative-direction-driven work: which skills run when, what locks at which gate, how handoffs occur, and how the cadence implements in the team's…
qf-studio/navigator
Automates design review, token extraction, component mapping, and implementation planning.
WellApp-ai/Well
Guide for creating new MCP server integrations. An agent skill from WellApp-ai/Well.
hashgraph-online/awesome-codex-plugins
Pre-ship gate for a Figma handoff. An agent skill from hashgraph-online/awesome-codex-plugins.
lassejlv/loora
Build, edit, refine, troubleshoot, and review polished responsive product interfaces through the Loora MCP server and its structured Canvas schemas.
bitovi/ai-enablement-prompts
Track reusable UI components and unextracted patterns. An agent skill from bitovi/ai-enablement-prompts.
bitovi/ai-enablement-prompts
Extract and compare computed CSS styles between a baseline URL and a dev/Storybook URL using Playwright MCP evaluate calls.
bitovi/ai-enablement-prompts
A skill your agent uses when the user asks to "create a plugin", "add a plugin", "make a new plugin", "build a plugin", or wants to package skills into an installable plugin for this marketplace.
bitovi/ai-enablement-prompts
Create React components, hooks, or utilities following the modlet pattern.
bitovi/ai-enablement-prompts
A skill your agent uses when the user asks to "create a skill", "add a skill", "make a new skill", "build a skill", or wants to automate a repeated workflow into a reusable prompt.
bitovi/ai-enablement-prompts
Create new Agent Skills for this project. An agent skill from bitovi/ai-enablement-prompts.
Works with
Categories
Standalone validator for a completed figma-from-code rebuild. Figma From Code Validator is an agent skill from bitovi/ai-enablement-prompts. Standalone validator for a completed figma-from-code rebuild.
Figma From Code Validator fits situations like: agent Workflows work in your project.
Run `npx skills add bitovi/ai-enablement-prompts --skill figma-from-code-validator -a claude-code`. Or copy the skill folder (plugins/figma-from-code/skills/figma-from-code/10-validator in bitovi/ai-enablement-prompts) into .claude/skills/figma-from-code-validator in your project. Claude Code loads it when a task matches its description.
Run `npx skills add bitovi/ai-enablement-prompts --skill figma-from-code-validator -a codex`. Or copy the skill folder (plugins/figma-from-code/skills/figma-from-code/10-validator in bitovi/ai-enablement-prompts) into .agents/skills/figma-from-code-validator in your project. Codex loads it when a task matches its description.
Cursor, Gemini CLI, GitHub Copilot and OpenCode also load SKILL.md folders. With the skills CLI, run `npx skills add bitovi/ai-enablement-prompts --skill figma-from-code-validator -a cursor` (or -a gemini-cli, github-copilot or opencode for the others). To copy it by hand, put the folder in .cursor/skills/figma-from-code-validator, .gemini/skills/figma-from-code-validator, .github/skills/figma-from-code-validator and .opencode/skills/figma-from-code-validator in your project.
Going by SKILL.md and its folder, Figma From Code Validator needs the command-line tools its instructions call (node and curl).
SKILL.md contains no URLs. Its commands use curl, which can reach the network depending on how they are called. This is read from the text; nothing was executed.
Our automated static check of SKILL.md found no risky patterns, such as piping downloads into a shell, reading credential files or hidden Unicode. It is not a guarantee. Review the folder before installing.
Figma From Code Validator is published under the MIT licence (the repository's licence). It allows redistribution, so the full SKILL.md is shown on this page.
About 6.4k tokens (SKILL.md is roughly 25k characters). Agents keep only the skill's name and description in context until a task matches; then they load SKILL.md in full.
Skills that share tags, products or a category with Figma From Code Validator: MCP SDK Audit (awdr74100/figwright, 977 stars), Integration Orchestrator (rampstackco/claude-skills, 935 stars), Product Design (qf-studio/navigator, 354 stars) and MCP Server (WellApp-ai/Well, 345 stars). The comparison table on this page puts their stars, adoption, token cost, safety result and licence side by side.
bitovi (a GitHub organization) maintains it in bitovi/ai-enablement-prompts, which has 121 GitHub stars. The repository holds 40 skills in this directory. The repository was last updated on September 11, 2026.
Source: bitovi/ai-enablement-prompts on GitHub. Facts on this page come from the repository at the commit we read; the author's words are quoted as theirs.