Design with Pen
/pen-design turns a Pen canvas into code using project tokens and components. The .pen file is the design source; shipped frames record their file and commit.
What you need
penCLI andpencilMCP:devkit syncinstalls both; then runpen login.- Pen.app with the project's
.penopen. Download it from pen.dev. - Node 22.19+ and Playwright for browser verification.
.agents/context/DESIGN.mdwith a completed## Adapterblock./indexcreates it.
The first files
For frontend stacks, /index creates .agents/context/DESIGN.md and fills detected tokens, components, and adapter keys. It also initializes .agents/design-inventory.json from the stack starter and writes the gitignored .agents/context/component-inventory.json. Edit the recipe when the project structure differs.
/pen-design phases 0–2 run design-seed.mjs against the single .pen under design/. Before writing, the seed checks the file format and confirms that Pen.app has that same canvas in front. Another front document or --dry-run writes nothing; existing companion files are kept.
| Created | Purpose |
|---|---|
design/AGENTS.md | Drawing rules plus project rules supplied with --preamble |
01 · Tokens | Canvas variables shown as colour, type, and spacing samples |
02 · Icons | Project icons; set by --icons |
design/CLAUDE.md | Relative symlink to design/AGENTS.md; Pen's agent reads the drawing rules and generated component inventory there |
design/README.md | Canvas zones, cells, and sorting convention |
design/PROMPT.md | Component, implementation, and page briefs |
devkit design-inventory refreshes components, ownership and the table Pen's agent reads; --check reports stale input; --pairs lists components drawn but not built, or built but not drawn.
devkit design-tidy --write sorts design/ and rewrites the .pen image paths; --check exits 1 while a file is out of place.
How a design moves
- Set up. Seed a new canvas with
design-seed.mjs --from-template <name>or use the existing one; complete the adapter. - Draw. Variables, navigation, components, sections, then pages. Import a page before redesigning it.
- Approve mobile. Approve
Mobile 390before derivingDesktop 1280. - Name the frames. Approval, even after a Pen edit, names numbers; “continue” or “okay” authorizes nothing.
- Hand over. Build inventory components; the stack skill owns values and data. Run
devkit design-inventory --check. - Verify. Compare both frame widths and a width above the layout max-width. Page values, sizes and colours must match canvas variables.
- Stamp. Fold approved drafts into their masters and delete them; mark both frames
· shippedwith file and commit. Git keeps the archive.
Every canvas value comes from a project token; a draft reuses a component or standard View first.
Working in one file with others
Use one .pen per project. While Pen.app is open, write through the app or pen interactive; a direct file edit can be overwritten by the next save. Each session owns only the frames it created. The seed reports foreign frames and never moves them.
Frames declare their row and granularity in context, for example Spur: product | Ebene: View. design-sort.mjs places them: sheets and components on top, views grouped by Spur and numbered by group. Without an adapter groups key it keeps the board's own shape.
The adapter
The adapter tells the shared method how this project works. Run the keys check before the first draft:
node "$(devkit path skill pen-design)/scripts/design-adapter-check.mjs"| Key | Value |
|---|---|
tokens | File and block consumed by the build |
naming | Canvas variable to code identifier mapping |
inventory | .agents/context/component-inventory.json |
gate | Project command that proves the implementation |
rows | Routes or zone names, in journey order |
owners | Dependency source that owns each component |
decisions | Usually .agents/context/DESIGN-DECISIONS.md |
concepts | Usually design/konzepte/*.md |
scrollword, figures, bleed | Optional project vocabulary, key figures, full-bleed exceptions |
Commands
Run commands from the project root. For .mjs scripts use node "$(devkit path skill pen-design)/scripts/<name>". Exit codes: 0 pass, 1 findings (new only with a baseline), 2 invalid input or unavailable check.
| Command | Purpose |
|---|---|
design-seed.mjs [--icons <source>] [--preamble <file>] [--dry-run] | Seed rules, sheets, and companion files |
devkit design-check [--baseline <file>] | Check canvas rules |
design-status.mjs [--open] | List pending, stale, and unsaved frames |
design-read.mjs <mobile> <desktop> [--diff] | Read a frame pair's values, or only changes |
design-verify.mjs <nr> --url <path> [--base <url>] [--strict] | Compare canvas and rendered page |
design-marker-check.mjs | Validate shipped stamps; flag stale drafts |
design-sort.mjs [--apply] | Compute or apply frame positions |
design-tokens.mjs [--json] | Read project tokens as canvas variables |
design-fonts.mjs, design-tidy --images | Unused fonts; shrink images to WebP |
Shopify projects also have a generated skill reference.
Acceptance criteria
devkit design-check checks classification, tokens, clipping, icons, typography, reuse, numbering and sliders. Project rules live in .agents/design-check.project.js; --no-project runs core rules only. Reports separate run time from ruleset date.
--write-baseline <file> records existing findings for this checkout; --baseline <file> separates new, known and resolved findings and fails on new ones. Baselines bind the absolute canvas path. Full acceptance runs without a baseline.