skillZs
★ LIVE SKILL TAGS ★
>>> LIVE SKILLS INDEX <<<
* OPEN SOURCE *
NO LOGIN, NO TRACKING
※ REAL INSTALL DATA ※
← back to all skills
penpot/penpot-ai-kit92 installs

penpot-design-md

Extract a DESIGN.md design-documentation file from a Penpot file: a portable markdown spec (YAML frontmatter with colors/typography/rounded/spacing/components token maps + prose sections: Overview, Colors, Typography, Layout, Shapes, Components, Do's & Don'ts, Iteration Guide, Known Gaps) in the design-md format, grounded in the file's real tokens, library assets, and sampled component styles — never invented. Read-only on the canvas; writes one local markdown file. Triggers: 'generate DESIGN.md', 'create a design.md', 'document the design system as markdown', 'export design guidelines', 'extract design documentation', 'design system spec file', 'make a style guide file from this design'.

How do I install this agent skill?

npx skills add https://github.com/penpot/penpot-ai-kit --skill penpot-design-md
view source ↗

Is this agent skill safe to install?

  • Gen Agent Trust Hubpass

    The skill is designed to extract design documentation from Penpot files into a markdown format. It uses standard plugin scripts to read design data and contains no malicious code, though it processes external design content that could theoretically contain indirect instructions.

  • Socketpass

    No alerts

  • Snykpass

    Risk: LOW · No issues

What does this agent skill do?

penpot-design-md — Extract a DESIGN.md spec from a Penpot file

1. Title + How it works

This skill turns a Penpot file into a DESIGN.md: a single, portable markdown document that lets any human or LLM reproduce the design system without opening Penpot — YAML frontmatter carrying the token maps (colors, typography, rounded, spacing, components) plus prose sections that explain how the system behaves (Overview, per-domain sections, Do's & Don'ts, Iteration Guide, Known Gaps). 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) — but this skill performs no canvas mutation at all: it only reads (tokens, library assets, sampled component styles, exported images) and writes one local markdown file on the agent's filesystem. It is multimodal by design: the aesthetic prose (frontmatter description, Overview, Do's & Don'ts) must be written after looking at real exports, not from token names alone.


2. The One Rule That Matters Most

Every value in the DESIGN.md must be traceable to something you read or saw in the file — never invented, never "typical". A hex that appears in colors: was read from a token, a library color, or a sampled shape fill. A padding in components: was read from a real component's layout. A "Don't" was observed (the file never does it), not imagined. When something cannot be extracted, it goes in Known Gaps — an honest gap beats a plausible fabrication, because downstream agents will build from this file.


3. Penpot MCP Tool Reference

Full surface: shared/penpot-mcp-tool-reference.md. The calls this skill leans on (all read-only):

NeedCall (inside execute_code unless noted)
Pages inventorypenpotUtils.getPages(), penpotUtils.getPageByName(name)
Token sets, themes, tokenspenpot.library.local.tokens → sets[], themes[], set.tokens[] (name, type, value, resolvedValue)
Library assetspenpot.library.local → components[], colors[], typographies[]
Component style samplingcomponent.mainInstance() then walk children: fills, strokes, borderRadius*, flex (padding/gap), text fontFamily/fontSize/fontWeight/lineHeight/letterSpacing, shape.tokens
Structure of a page/boardpenpotUtils.shapeStructure(shape, depth)
Visual groundingexport_shape (separate MCP tool) on the cover, key component boards, and 1–2 representative screens

Verify any unfamiliar signature with penpot_api_info before relying on it.


4. Plugin API Essentials

The gotchas that bite this skill (full list: shared/plugin-api-gotchas.md):

  • #1 style arrays — read fills[0].fillColor etc.; never attempt to write (this skill doesn't mutate).
  • Variant reading is safe (#12 forbids mutation only) — read variants.properties, variantComponents()[].variantProps freely to document the variant axes.
  • Library color duplicates — library.local.colors can hold several entries with the same short name (default, hover) belonging to different groups; disambiguate by color.path/group before mapping to semantic names, or fall back to value-based grouping.
  • Text metrics live on the shape — fontSize is a string in some builds; normalize to px numbers when emitting typography:.
  • mainInstance() of a heavy component can be slow — sample components one execute_code call per batch of ~5, not all in one blast.
  • Verify unfamiliar signatures with penpot_api_info before use.

5. Token-Aware Brief Contract

Before extracting, restate the request. Act as a senior design-systems documentarian: your reader is another agent that will rebuild this system from your file alone.

  • Context — which Penpot file/pages, what the product is, who consumes the DESIGN.md (humans, coding agents, both).
  • Objective (single) — e.g. "Produce DESIGN.md for the Pencil design system covering tokens, type, shape language, and the Button/Input/Modal component families."
  • Inputs — the file's token sets + themes, library components/colors/typographies, the pages to sample, the output path for the file.
  • Constraints — scope (whole system vs. named components); which theme is canonical (light/dark) and how to document the other; format is the design-md contract (see references/02-designmd-format.md) — do not invent alternative section names.
  • Acceptance Criteria (quantitative) —
    • every colors: entry has a hex read from the file, and its source (token/library color/sampled fill) is noted in the body or Known Gaps;
    • every typography: entry carries fontFamily/fontSize/fontWeight/lineHeight/letterSpacing read from a typography asset or a sampled text shape;
    • components: covers the agreed component list, each with values interpolated from {colors.*}/{typography.*}/{rounded.*} (no raw hex where a mapped color exists);
    • Overview and Do's & Don'ts cite only observed behavior; ≥1 export was actually looked at before writing them;
    • Known Gaps lists every domain that could not be extracted (responsive behavior, motion, elevation, …).

6. Mandatory Workflow

Visual grounding (mandatory): this skill's variant of shared/visual-self-review.md — you cannot write the description, Overview, or Do's & Don'ts before exporting and looking at the cover / key screens. Aesthetic prose written from token names alone is fabrication.

Phase 0 — Discovery (read-only)

  • Goal: inventory what the file offers before deciding the extraction plan.
  • Steps:
    1. high_level_overview (once per session).
    2. execute_code: run scripts/extractDesignData.js → pages, token sets (+ themes, active state), library components/colors/typographies, counts. Cache in storage.run.inventory.
    3. Decide with the user: scope (which components to document in depth), canonical theme, output path.
  • Exit criterion: an inventory + an agreed scope and output path.
  • ✋ Checkpoint: show the inventory summary and the proposed DESIGN.md scope (which sections will be rich, which will land in Known Gaps).

Phase 1 — Token & asset extraction

  • Goal: the raw material for the frontmatter maps.
  • Steps: execute_code per group: dump color tokens (name → resolvedValue, per theme where sets differ), dimension/spacing/radius tokens, typography assets, library colors (deduped by group/path). Derive the semantic mapping (canvas, surface-*, ink-*, primary, hairline, semantic-*) from token names/tiers where they exist; from library-color groups and usage sampling where they don't (see references/03-inference.md).
  • Exit criterion: draft colors:, typography:, rounded:, spacing: maps with a source note per entry.
  • ✋ Checkpoint: show the draft maps + anything unmapped. Confirm semantic names before they ossify into the doc.

Phase 2 — Component sampling

  • Goal: the components: map + the Components body section.
  • Steps: for each in-scope component (batches of ≤5 per execute_code): resolve mainInstance(), read background/text/border/radius/padding/typography and bound tokens; capture variant axes (variants.properties, variantProps) — states become separate entries (button-primary-hover, …). Interpolate values through the Phase 1 maps.
  • Exit criterion: every in-scope component has a frontmatter entry + body bullets; unresolved values are flagged.
  • ✋ Checkpoint: show 2–3 sample component entries for tone/format approval before doing the full list.

Phase 3 — Visual character pass

  • Goal: the honest aesthetic prose.
  • Steps: export_shape the cover and 1–3 representative boards/screens. Look at them. Write: frontmatter description (one dense paragraph: dominant surfaces, accent usage, type character, shape language, rhythm), Overview (+ Key Characteristics bullets), and Do's & Don'ts (only rules the file itself demonstrates or its token structure implies).
  • Exit criterion: prose grounded in what was seen; each Don't traceable to an observation ("no pill buttons anywhere", "single accent hue").
  • ✋ Checkpoint: show the exports next to the drafted prose.

Phase 4 — Assemble, self-review, write

  • Goal: the deliverable.
  • Steps: assemble per references/02-designmd-format.md (section order fixed); run the format self-check (frontmatter parses as YAML, every {ref} resolves to a frontmatter key, no raw hex in components: where a colors: entry exists, Known Gaps non-empty unless truly complete); write the file to the agreed path.
  • Exit criterion: file written; self-check clean.
  • ✋ Checkpoint: present the file (or its outline + key excerpts) for final approval.

7. Critical Rules

  1. Read-only on the canvas. No shape, token, or library mutation — ever. The only write is the local markdown file.
  2. No invented values. Every hex/px/weight is read from the file. Unknown → Known Gaps.
  3. Interpolate, don't repeat. Body prose and components: reference {colors.x}/{typography.y}/{rounded.z}; raw values appear once, in the frontmatter maps.
  4. Look before you describe. No aesthetic prose before at least one export_shape has been viewed (Phase 3).
  5. Themes are explicit. If the file has light/dark sets, document the canonical theme in the maps and the other as a delta subsection — never silently mix values from both.
  6. Dedupe library colors by group before semantic mapping; identical short names across groups are different colors.
  7. Curate, then disclose. A 100+-token file is summarized into semantic groups — say what was collapsed ("107 Global tokens → 14 semantic colors; full set names in Known Gaps") — no silent truncation.
  8. One extraction step per execute_code call; component sampling in batches of ≤5.
  9. Variant axes are documentation gold — record Property=Value matrices for components that have them; reading them is safe.
  10. The output must lint as the format — section order and frontmatter keys exactly per references/02-designmd-format.md.

8. Domain Architecture

The DESIGN.md contract (summary — full spec in references/02-designmd-format.md):

--- (YAML frontmatter)
version, name, description        # description = one dense aesthetic paragraph
colors:      { semantic-name: "#hex", ... }          # canvas/surface-*/ink-*/primary/hairline/semantic-*
typography:  { style-name: {fontFamily,fontSize,fontWeight,lineHeight,letterSpacing}, ... }
rounded:     { xs..pill: Npx }
spacing:     { xxs..section: Npx }
components:  { component-or-state: {backgroundColor,textColor,typography,rounded,padding,...}, ... }
---
## Overview                      # prose + **Key Characteristics** bullets
## Colors                        # Brand & Accent / Surface / Text / Semantic subsections, sources cited
## Typography                    # Font Family / Hierarchy / Principles / substitutes note
## Layout                        # Spacing System / Grid & Container / Whitespace Philosophy
## Elevation & Depth             # shadows/borders ladder (or "flat by design")
## Shapes                        # Border Radius Scale + shape language
## Components                    # per component: **`name`** + purpose + property bullets with {refs}
## Do's and Don'ts               # observed rules only
## Responsive Behavior           # only if derivable from the file; else Known Gaps
## Iteration Guide               # how a future agent should edit designs with this doc
## Known Gaps                    # everything not extractable — mandatory honesty section

Run ledger keys (see §10): inventory, maps, componentEntries, exportsViewed, gaps.


9. Modes & Policies

See shared/modes-and-policies.md. This skill is suggest and stays there: it never mutates the canvas, so there is no safe-set and nothing to auto-apply. The single side effect — writing the markdown file — happens at the Phase 4 checkpoint with the path the user approved in Phase 0. Overwriting an existing DESIGN.md requires explicit confirmation (show a diff summary first).


10. State Management

See shared/state-management.md. RUN_ID slug example: designmd-2026-07-09-a. Session cache in storage.run.* (inventory, maps, componentEntries, exports viewed, gaps). This skill is read-only, so it does not write setSharedPluginData unless the user asks to persist a pointer to the generated doc (designmd.lastGenerated = path + date). Resume: re-read storage.run; if gone, re-run Phase 0 (extraction is cheap and idempotent).


11. User Checkpoints

After phaseArtifacts shownWhat we ask
0 DiscoveryInventory (pages, sets, themes, assets) + proposed scope & output path"Confirm scope, canonical theme, and where to write the file."
1 TokensDraft frontmatter maps + unmapped values"Approve the semantic names / flag mis-mappings."
2 Components2–3 sample component entries"Right tone and depth? Then I'll complete the list."
3 VisualExports + drafted description/Overview/Do's & Don'ts"Does this prose match what you see?"
4 AssembleThe written file (outline + excerpts)"Final approval — anything to add to Known Gaps?"

12. Naming Conventions

See shared/naming-conventions.md. Frontmatter keys are kebab-case semantic names in the design-md idiom (ink-muted, surface-2, display-xl, button-primary-hover) — map Penpot's dot-notation tokens onto them and record the mapping (color.text.muted → ink-muted) in the Colors section so the doc stays traceable back to the file. Component entries use the component's kebab-cased name plus -hover/-pressed/-disabled/-selected state suffixes derived from variant values.


13. Anti-Rationalization Table

Excuse the LLM makesWhy it's wrongDeterministic countermeasure
"The file has no tokens, so I'll write a typical palette."Fabricated values poison every downstream consumer of the doc.Stop. Sample real shape fills (references/03-inference.md), map what exists, put the rest in Known Gaps.
"I can describe the aesthetic from the token names."color.primary = #00d1b8 doesn't tell you whether the design is dense or airy, flat or elevated.Halt Phase 3 until ≥1 export_shape has been viewed. Prose cites what was seen.
"107 tokens is too many; I'll just list them all raw."A raw dump is not documentation — the format demands curated semantic groups.Curate into the semantic map, then disclose the collapse explicitly in Colors + Known Gaps.
"This component is obvious — a standard button, 8px radius.""Standard" is fabrication; this file's button may be 6px with a hairline border.Sample the actual mainInstance() before writing any component entry.
"Do's & Don'ts are generic best practices anyway."The section documents THIS system's rules, not design folklore.Each Do/Don't must trace to an observation (token structure, sampled styles, or a viewed export).
"Light and dark values differ; I'll average or pick per-property."Mixed-theme values describe a design that doesn't exist.Pick the canonical theme (Phase 0 decision); document the other as a delta subsection.

14. Helper Code Snippets

Inventory (Phase 0 — or use scripts/extractDesignData.js):

const lib = penpot.library.local;
return {
  pages: penpotUtils.getPages().map(p => p.name),
  sets: (lib.tokens.sets || []).map(s => ({ name: s.name, active: s.active, count: (s.tokens||[]).length })),
  themes: (lib.tokens.themes || []).map(t => ({ group: t.group, name: t.name })),
  components: (lib.components || []).length, colors: (lib.colors || []).length,
  typographies: (lib.typographies || []).map(t => t.name)
};

Dump color tokens with resolution (Phase 1):

const out = [];
for (const s of penpot.library.local.tokens.sets || []) {
  if (!s.active) continue; // canonical theme only — dump inactive sets separately as the delta
  for (const t of s.tokens || []) if (t.type === "color")
    out.push({ set: s.name, name: t.name, value: t.value, resolved: String(t.resolvedValue) });
}
return { count: out.length, tokens: out };

Sample one component's style (Phase 2):

const comp = penpot.library.local.components.find(c => c.name === "REPLACE-ME");
const root = comp.mainInstance();
const texts = penpotUtils.findShapes(s => s.type === "text", root).slice(0, 3);
return {
  name: comp.name,
  bg: root.fills && root.fills[0] ? root.fills[0].fillColor : null,
  radius: root.borderRadius ?? null,
  padding: root.flex ? [root.flex.topPadding, root.flex.rightPadding, root.flex.bottomPadding, root.flex.leftPadding] : null,
  gap: root.flex ? [root.flex.rowGap, root.flex.columnGap] : null,
  boundTokens: root.tokens || {},
  text: texts.map(t => ({ family: t.fontFamily, size: t.fontSize, weight: t.fontWeight, lh: t.lineHeight, ls: t.letterSpacing, fill: t.fills && t.fills[0] && t.fills[0].fillColor })),
  variantAxes: comp.isVariant && comp.isVariant() ? comp.variantProps : null
};

15. Reference Resources

  • penpot_api_info("TokenCatalog"), ("LibraryComponent", "mainInstance"), ("Variants"), ("LibraryTypography") — verify before Phase 1/2.
  • shared/penpot-mcp-tool-reference.md (tool surface), shared/plugin-api-gotchas.md (traps), shared/tokens-schema.json (tiers, Penpot token type strings).
  • The format's canonical skeleton: references/04-designmd-template.md (self-contained — no external corpus needed).

16. Supporting Files

References (progressive disclosure — load when that phase runs)

FileRead duringCovers
references/01-extraction.mdPhases 0–2What to read where: token sets/themes, library assets, component sampling recipes, variant axes, theme handling
references/02-designmd-format.mdPhases 3–4The full DESIGN.md contract: frontmatter schema, section order, interpolation rules, tone, the self-check list
references/03-inference.mdPhase 1 (token-poor files)Deriving semantic maps without tokens: library-color groups, fill-frequency sampling, surface-ladder detection
references/04-designmd-template.mdPhase 4The fill-in DESIGN.md skeleton (agnostic, self-contained) — copy, fill with extracted values, delete the guidance lines

Scripts (paste into an execute_code call; replace placeholders)

ScriptUse for
scripts/extractDesignData.jsPhase 0 — one-call read-only inventory: pages, sets, themes, assets, counts
scripts/sampleComponentStyles.jsPhase 2 — batch-sample ≤5 components' resolved styles + bound tokens + variant axes

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.

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-design-md">View penpot-design-md on skillZs</a>