penpot-migrate
Migrate a Figma design into Penpot with high fidelity: Figma Auto Layout → Penpot flex/grid, Figma Variables → Penpot tokens, Figma component sets → Penpot variants, preserving hierarchy. Reads via the Figma MCP, writes via the Penpot MCP, through an intermediate representation (IR). Degrades to manually-pasted Figma data if the Figma MCP is absent. Triggers: 'migrate from Figma', 'import this Figma file into Penpot', 'move our Figma library to Penpot', 'recreate this Figma design in Penpot', 'Figma to Penpot'.
How do I install this agent skill?
npx skills add https://github.com/penpot/penpot-ai-kit --skill penpot-migrateIs this agent skill safe to install?
- Gen Agent Trust Hubpass
The skill is a legitimate utility designed to migrate design files from Figma to Penpot. It utilizes a structured, multi-phase workflow involving an intermediate representation (IR) to ensure layout fidelity. The code follows standard integration patterns for the Penpot environment, and no malicious behaviors such as data exfiltration, obfuscation, or unauthorized remote code execution were found.
- Socketpass
No alerts
- Snykwarn
Risk: MEDIUM · 1 issue
What does this agent skill do?
penpot-migrate — Figma → Penpot, fidelity-first
1. Title + How it works
penpot-migrate bridges two MCP servers: it reads a Figma design via the Figma MCP and writes it
into Penpot via the Penpot MCP — every mutation goes through execute_code; validate visually with
export_shape; read structure with penpotUtils.shapeStructure (full tool surface:
shared/penpot-mcp-tool-reference.md). It never writes Penpot directly from Figma data — it first builds a normalized
intermediate representation (IR), then translates the IR into Penpot constructs (boards, flex,
tokens, components). If the Figma MCP isn't available, it accepts manually-pasted Figma export/JSON and
works from that.
2. The One Rule That Matters Most
IR before any Penpot write, and migrate in layers. Tokens first, then components, then screens — each validated. Never one-shot a whole file. The IR is the contract that decouples Figma's model from Penpot's API.
3. Penpot MCP Tool Reference
Full surface: shared/penpot-mcp-tool-reference.md. Penpot-write side: createBoard/addFlexLayout/
addGridLayout, penpot.library.local.tokens.addToken, createComponent/createVariantFromComponents,
export_shape for fidelity checks. Figma-read side: the Figma MCP's design-context tools (names vary;
treat them as producing raw data the IR normalizes).
4. Plugin API Essentials
Gotcha numbers refer to shared/plugin-api-gotchas.md.
- Penpot uses Boards (not Frames); Auto Layout maps to Board flex (
dir, gaps, padding, sizing fill/auto/fix) or grid. - Figma Variables → Penpot tokens via
addToken({type,name,value})with the real type strings (shared/tokens-schema.json). Map Figma modes → Penpot themes. - #9 Figma component sets/variants → Penpot variant containers: prefer
penpotUtils.createVariantContainer([{ shape: mainInstance, properties }])(≥ 2.17);penpot.createVariantFromComponents(mainInstances)is the low-level fallback;Board.combineAsVariants(ids)is listed on 2.17 but unverified — do not use. Beware #12 — variant mutation corrupts the file; prefer create-then-group, never edit a variant container in place. - #2 token application is async — apply in one call, verify
resolvedValue/shape.tokensin a LATER call; #4 flex overrides child x/y; #6 detach before mutating instance internals. - Verify unfamiliar signatures with
penpot_api_infofirst.
5. Token-Aware Brief Contract
- Context — source Figma file/scope, target Penpot file, fidelity expectations.
- Objective — single: "migrate <scope> from Figma to Penpot at <fidelity>".
- Inputs — Figma access (MCP or pasted export), naming/token mapping rules.
- Constraints — preserve hierarchy/layout/variants; map Variables to tokens; on-grid spacing.
- Acceptance Criteria — IR built; tokens migrated & resolving; components/variants reconstructed; screens visually match (export compare); fidelity report.
Act as a migration engineer who prizes structural fidelity.
6. Mandatory Workflow
Visual self-review (mandatory): before every ✋ checkpoint that shows visual work, run the export → look → fix loop from
shared/visual-self-review.md— export the unit you just built, inspect the image yourself against the checklist, fix visible defects (max 2 iterations), and present that same export with any remaining defects named.
Phase 0 — Figma analysis. Read the source (Figma MCP or pasted data); inventory tokens/components/screens (scripts/analyzeFigmaStructure.js, references/01-figma-analysis.md). ✋ Checkpoint: scope & mapping rules.
Phase 1 — Build IR. Normalize into the IR (scripts/buildIR.js, references/02-ir-building.md). The IR is plain data; no Penpot writes yet. ✋ Checkpoint: review IR coverage.
Phase 2 — Tokens. Translate Variables → tokens (scripts/migrateTokens.js, references/03-token-migration.md); reconcile with penpot-foundations. ✋ Checkpoint.
Phase 3 — Components. Reconstruct components & variants (scripts/migrateComponent.js, references/04-component-migration.md). ✋ Checkpoint.
Phase 4 — Layout & screens. Auto Layout → flex/grid (references/05-layout-translation.md); build screens (scripts/migrateScreen.js, references/06-screen-migration.md). ✋ Checkpoint per screen (export_shape).
Phase 5 — Validate fidelity. scripts/validateFidelity.js (references/07-validation.md) — structure, tokens, visual compare. Report. (references/08-error-recovery.md for issues.)
7. Critical Rules
- Build the IR before any Penpot write.
- Migrate tokens → components → screens, in that order, validating each.
- Auto Layout → flex/grid; never absolute-position what was auto-laid-out.
- Variables → tokens with real type strings; modes → themes.
- Degrade gracefully if the Figma MCP is absent (accept pasted data).
- Report fidelity gaps honestly; don't claim 1:1 when it isn't.
8. Domain Architecture
IR (plain JSON) decouples the two tools:
{ tokens:[{type,name,value,mode?}],
components:[{name, variantProps?, layout, children:[...]}],
screens:[{name, size, layout, children:[...]}] }
Each IR node carries enough to build the Penpot equivalent (layout = flex/grid spec; children reference components or primitives). Translation reads IR, writes Penpot.
9. Modes & Policies
Default review. Component/variant restructuring and detach never auto (shared/modes-and-policies.md).
10. State Management
Ledger under RUN_ID: phase, ir (or a pointer), migrated:{tokens,components,screens}, gaps:[...]. The IR is the resumable artifact — re-read it after truncation.
11. User Checkpoints
| After phase | Artifacts | Ask |
|---|---|---|
| 0 | inventory + mapping rules | Approve scope/mapping? |
| 1 | IR coverage | Approve IR? |
| 2 | migrated tokens (tokenOverview) | Approve tokens? |
| 3 | components/variants | Approve components? |
| 4 | screen export_shape | Approve screen? |
12. Naming Conventions
shared/naming-conventions.md: map Figma names to Penpot conventions (PascalCase components, Property=Value variants, semantic layers, dot-notation tokens).
13. Anti-Rationalization Table
| Excuse | Why it's wrong | Countermeasure (halt) |
|---|---|---|
| "Skip the IR, write Penpot straight from Figma." | Couples the two models; brittle, lossy. | Build the IR first; translate from it. |
| "Absolute-position everything to match pixels." | Loses Auto Layout responsiveness. | Map Auto Layout → flex/grid; absolute only where Figma used absolute. |
| "Recreate Variables as hardcoded values." | Drops the token system. | Migrate Variables → tokens; modes → themes. |
| "Migrate the whole file in one pass." | One-shot loses fidelity and is unauditable. | Layered: tokens → components → screens, validate each. |
| "Figma MCP isn't connected, so I'll guess the design." | Guessing fabricates the design. | Ask for a pasted export/JSON; work from real data. |
| "Claim it's a perfect 1:1." | Some Figma features don't map cleanly. | Report fidelity gaps honestly. |
14. Helper Code Snippets
// Translate an IR layout node to a Penpot flex Board
function buildFromIR(node, parent){
const b = penpot.createBoard(); b.name = node.name;
if (node.layout && node.layout.type === "flex"){
const f = b.addFlexLayout();
f.dir = node.layout.dir || "column";
f.rowGap = node.layout.rowGap || 0; f.columnGap = node.layout.columnGap || 0;
}
(parent || penpot.currentPage.root).appendChild(b);
return b;
}
return { ok: true };
15. Reference Resources
penpot_api_info('Board'),penpot_api_info('VariantContainer'),penpot_api_info('TokenSet').- Figma MCP design-context tools (names vary by version) — discover via the Figma MCP's own overview.
16. Supporting Files
references/: 01-figma-analysis.md, 02-ir-building.md, 03-token-migration.md, 04-component-migration.md, 05-layout-translation.md, 06-screen-migration.md, 07-validation.md, 08-error-recovery.md.
scripts/: analyzeFigmaStructure.js, buildIR.js, migrateTokens.js, migrateComponent.js, migrateScreen.js, validateFidelity.js.
Doctrine paths. shared/… and policies/… resolve inside this bundle in native installs (vendored by the installer); in a Claude Code plugin install they live at the plugin root — ${CLAUDE_PLUGIN_ROOT}/shared/…, two directories up from this file.
How can the creator link this skill?
Add the canonical catalog link to the repository README so users can inspect current installs and available audits. The publishing guide covers the complete discovery path.
<a href="https://skillzs.dev/skills/penpot/penpot-ai-kit/penpot-migrate">View penpot-migrate on skillZs</a>