Skip to content
Back to skills

Help

BSecurity

Orientation, connection, one-time setup and troubleshooting for Design Twin, the free-plan Figma→code workflow. Use this whenever the user asks a discovery-shaped question — "how does this work", "what can this plugin do", "how do I connect Claude to Figma", "is there a CLI", "what's the MCP server for", "how do I set this up", which export path to use — even if they don't name a command; when they are about to try a Figma task but have no connection set up yet; and whenever something is brok...

  • 2 stars
  • 0 votes
  • 0 copies
  • 0 views
  • Added October 20, 2026
designgoswiftkotlinshellnodesecurity

Works with

  • claude code
  • cli
  • mcp

Security analysis

B77/100
  • highPerforms destructive filesystem operations
  • mediumInstalls packages at runtime which could introduce malicious dependencies

Pro scans all 3 files and shows the line behind each finding

Scanned October 20, 2026

npx -y skills add its-magdy/design-twin --skill help --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Help?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Help
[![Security: B — Skills Directory](https://www.skillsdirectory.com/api/skills/its-magdy-help-design-twin/badge)](https://www.skillsdirectory.com/skills/its-magdy-help-design-twin)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: help
description: Orientation, connection, one-time setup and troubleshooting for Design Twin, the free-plan Figma→code workflow. Use this whenever the user asks a discovery-shaped question — "how does this work", "what can this plugin do", "how do I connect Claude to Figma", "is there a CLI", "what's the MCP server for", "how do I set this up", which export path to use — even if they don't name a command; when they are about to try a Figma task but have no connection set up yet; and whenever something is broken (plugin won't import, port 8787 busy / EADDRINUSE, bridge token / 401, plugin stays offline, MCP not connecting, empty library list, stale snapshot, scripts not found). It orients, routes and diagnoses; it does not export (that's extract), review a design (that's audit-design), write code (that's build-screen) or update built code after a design change (that's sync-design).
argument-hint: "[question or symptom]"
---

# Design Twin — what it is, how to connect, what to do when it breaks

Design Twin feeds a Figma design to Claude Code **on a free Figma plan, with zero network egress**.
A self-authored Figma plugin (`allowedDomains`: loopback only) extracts the design as stack-neutral
JSON + real assets into **`design/export/`**; `/designtwin:audit-design` reviews it for
implementation gaps, and `/designtwin:build-screen` turns it into code for any stack.

**`design/export/` is the only place a pull writes.** Everything beside it under `design/` —
`target.json`, `codeconnect.local.json`, `plan/`, `audit/`, `verify/` — is decisions and evidence you
own and cannot regenerate, so `rm -rf design/export && re-pull` is always safe. `dtwin init` drops a
`design/README.md` saying so. Projects created before this split keep their export directly in
`design/`; everything still finds it, and `dtwin doctor` reports which layout it found.

**Your job when this skill is invoked: figure out what the user is trying to do and give them the
exact next step.** Orientation → this file. Something broken → read
[`references/troubleshooting.md`](references/troubleshooting.md) (where it says `<plugin>` it means
`${CLAUDE_PLUGIN_ROOT}`, the installed plugin folder), match the symptom, give the fix —
don't debug a bridge error from memory.

Nothing here is headless: the target Figma file must be **open in the desktop app with the "Design
Twin" plugin running** (Figma desktop → Plugins → Development → Design Twin).

## The three ways to reach a Figma file

| | Manual export | `dtwin` CLI | `figma-mcp` server |
|---|---|---|---|
| What it is | Clicking the plugin's own export buttons, saving downloads into `design/export/` | A one-shot (or `--serve` daemon) local process that pulls data and writes it to `design/export/` on disk | A persistent MCP server, registered in the project being *built*, that Claude calls as tools mid-conversation |
| Setup | **None** — no bridge, no token | Once, from a clone: `npm install`, `npm run build --workspace bridge`, `npm link --workspace bridge`; the token generates itself on first start (paste it into the plugin once) | Same install as the CLI, plus a `.mcp.json` registration — same token, nothing extra |
| Direction | Read only | Read only | Read **and** a small set of safe writes (create a frame/text, set a fill, set text) |
| Best for | One screen, or a first try before setting anything up | Bulk/repeated pulls, CI-style extraction | Interactive back-and-forth, "check this, now pull that", code → design writes |

**Use what is already set up.** `mcp__designtwin__*` tools in this session (a `.mcp.json` registering
`designtwin`, e.g. from `dtwin init --mcp`; under another registration key the prefix differs — the same
`figma_*` tools count) → the MCP tools; else `dtwin` on PATH → the CLI; nothing
installed → the plugin's export buttons (manual export needs nothing and always works). Reach for the CLI
or MCP once someone's pulling repeatedly or wants Claude to query Figma live.

**The one thing to say up front: port 8787 (loopback) has one owner at a time, and the owner shares.**
- While the **MCP server** or a **daemon** (`dtwin serve`) holds it, ordinary `dtwin` commands and a
  second Claude Code session's MCP server work normally — they detect the owner and route through
  it. Nothing changes in how you invoke them. Inside an MCP session, `writeToDisk: true` on the
  export tools is still the simplest way to get files, and the **only** MCP way to get asset bytes.
- An MCP server that holds the bridge **exits when its client goes away**, unless another process has used
  its shared socket; then it keeps serving and idles out after `FIGMA_DAEMON_IDLE_MIN` (default 120 min,
  `0` = never). SIGINT/SIGTERM cancel in-flight reads, free the socket and exit 0.
- The exception is a plain one-shot `dtwin pull` with no daemon: it does not share, so a second pull
  started while it runs exits with `EADDRINUSE`, and an MCP tool call made meanwhile errors (the server
  stays up; retry the call). Wait for it, or use `dtwin serve`.
- To run two bridges deliberately, set `FIGMA_BRIDGE_PORT` on one (`8788` or `8789` — the only other
  ports the plugin can dial).
- **Windows: no sharing (yet).** `dtwin serve` / `dtwin stop` refuse there (Node cannot make the local
  socket private to the user), so one MCP session or `dtwin` command holds the bridge at a time; the
  others get a port-in-use error saying so. Close the other session (or wait for the command), then retry.

## What each one lets Claude actually do

**Through the CLI**, Claude runs `dtwin`. Check `which dtwin` first — it is normally already a
global binary, and only if it is missing are you inside a clone of the Design Twin repo, where every
`dtwin` is `node bridge/src/figma-pull.ts`. `dtwin help` prints a quick start, the commands and every
flag, and each command answers `--help` with its own page (`dtwin screenshot --help`,
`dtwin list --help`, `dtwin pull --help`, `dtwin whoami --help`, `dtwin mcp --help` — every verb has one)
without doing anything else while doing so. The output directory is positional and defaults to `design/export` (`dtwin pull`
writes there; give a path only for somewhere else — there is no `--out`, and never bare `design`, which
makes a parallel export tree nothing else reads) and the port comes only from `FIGMA_BRIDGE_PORT` (8787/8788/8789; no `--port`). A mistyped flag is refused, not ignored. Each command is shorthand for a flag (`dtwin list pages`
= `dtwin --list-pages`) and the flag spellings keep working — use either.
- **Anything not working → `dtwin doctor` first.** It checks the token, the port, the daemon, whether
  the plugin can connect (and whether it has the *right* token) and the project, changes nothing, and
  prints the next step for each problem.
- Discover structure cheaply before pulling anything heavy: `dtwin whoami` (which file am I on),
  `dtwin list clients`, `dtwin list pages` / `dtwin list` (pages + their top-level LAYERS with ids —
  SECTIONs and groups too, so on a sectioned file the real screens are one `list children` deeper),
  `dtwin list children <id>` (peek one frame). `dtwin list libraries` answers which library owns a
  token but is the slowest read there is — a few seconds up to ~15 s (about 2 s on a file with no
  libraries enabled): it walks every instance in the file and makes one Figma call per enabled
  library variable collection. It prints progress while it works.
- Pull a real export: `dtwin pull` (current page, into `design/export`), `--all-pages`,
  `--selection`, `--page <id>`, `--node <id|figma-url>`, `--design-system` (tokens/styles/components
  only, no page walk), `--as-library "<name>"` (a whole library file's catalog — run with the *library* open).
  On a file that CONSUMES a library, `--design-system` returns that file's OWN tokens, styles and components
  plus only the library variables something in the file references — never the library's catalog; for that,
  open the LIBRARY file and pull `--as-library` (CLI only). Add `--variant-visuals` for component variant looks.
- Visually check ONE component after generating code for it: `dtwin screenshot <id>` — an on-demand PNG,
  cheaper than re-exporting and tighter than the one whole-frame reference PNG every export carries.
- Keep the connection warm across several pulls with `dtwin serve` (`dtwin stop` / `dtwin status`)
  instead of reconnecting every time: a direct pull ends with `done in Xs — waited Ys for the plugin to
  connect · export Zs · write Ws`, and a long "waited" is the plugin re-dialling a fresh bridge, not a
  slow export — `dtwin serve` keeps the plugin connected so later commands skip it (not on Windows).

**Through the MCP server**, once registered in the target project (as `designtwin` in its `.mcp.json`, so each
tool's full name is `mcp__designtwin__<tool>`), Claude gets live tools instead of shelling out: `figma_status`, `figma_whoami`, `figma_list_clients`, `figma_get_selection`,
`figma_list_libraries`, `figma_list_pages`, `figma_list_children`, `figma_export_full` /
`figma_export_design_system` / `figma_export_selection` / `figma_export_url`, `figma_screenshot`,
`design_get_component`, `design_drift_lint`, and `figma_write` for the small set of safe writes. The
standout move is pasting a Figma link mid-conversation — `figma_export_url` reads that exact node
live, so "what spacing does this use?" gets answered from the real file, not a stale export.

MCP first calls: `figma_status` (which files; pass a row's connId as `client`) → `figma_list_pages
{depth:1}` → `figma_list_children {nodeId:<page or section id>}` → (`figma_screenshot {nodeId, scale:0.25,
writeToDisk:true}` for look-alikes) → `figma_export_url {url:"<node id>", writeToDisk:true}`.

## One-time setup (once per machine)

**Shortcut:** with the CLI installed, run **`dtwin init`** in the root of the project being built (add
`--mcp` to also register the MCP server; `--dry-run` to preview). It creates `design/` and
`design/export/`, writes `design/README.md` and `design/target.json` (the detected stack, or
`profile: null` for build-screen to fill in on its first run), makes sure a bridge token exists,
merges `.mcp.json` without overwriting anything, and prints the steps that are clicks in Figma. The
manual version:

1. **Import the Figma plugin.** Figma desktop → **Plugins → Development → Import plugin from
   manifest…** → pick `figma-plugin/manifest.json` from a clone of the Design Twin repo.
2. **Pick a lane:**
   - **Just one screen, nothing installed** → click the plugin's export buttons and save the downloads
     into `design/export/`. Done.
   - **The CLI** → `which dtwin`; if it isn't there, in a clone of this repo run `npm install`,
     `npm run build --workspace bridge` and `npm link --workspace bridge` (it is not on npm), or use
     `node bridge/src/figma-pull.ts` in place of `dtwin`. There is no token to make by hand: the first bridge start generates one, saves it per-user
     (`~/.config/design-twin/bridge-token`, `0600`; `%APPDATA%` on Windows) and prints it once — paste
     it into the plugin's **Bridge token** field (Save) and neither side asks again.
     `dtwin token show` reprints it, `dtwin token rotate` replaces it, `dtwin token` says which token
     is in play without disclosing it (flag forms: `--show-token` / `--rotate-token` /
     `--token-status`). Then `dtwin doctor` to confirm the plugin connects, and `dtwin list` to see
     what's there.
     One bridge serves **several Figma files at once** — each open plugin window is one client. With
     more than one connected, every command that reaches the plugin needs `--client <connId|part of
     the file name>`, or it refuses rather than guessing; `dtwin list clients` is the address book and
     `dtwin doctor` says when you will need it. (MCP: a `client` argument on each tool.) A partial
     file name is the form to reach for: `figma.fileKey` is gated to private plugins, so on a
     self-imported plugin it is `null` and cannot address anything.
   - **Live MCP tools in the project being built** → same install as the CLI, plus a `.mcp.json` *in
     that project* pointing at the absolute path of `bridge/dist/figma-mcp.js` (built and linked) or
     `bridge/src/figma-mcp.ts` (repo checkout) (`dtwin init --mcp` writes it); enable it via `/mcp` and
     restart. No token goes in that file — the MCP server reads the same per-user stored token.
3. **(Optional) config maps** so the agent reuses your components/tokens instead of regenerating —
   `design/target.json` (stack, auto-detected if absent), `design/tokens.json` (Figma variable → your
   code token — hand-authored; do NOT confuse with the generated `design/export/design-system/tokens.json`,
   which is Figma's own raw values), and the component map `design/codeconnect.local.json` (scaffold it with
   `node "${CLAUDE_PLUGIN_ROOT}/scripts/map-bootstrap.js" design/export/design-system/components.local.json --out design/codeconnect.local.json`).
   `build-screen` documents all three. Both `design/export/design-system/` paths above exist only after a
   `dtwin pull --design-system` (or a full pull) — see the table below.

## What a pull actually writes

Which files land depends on which pull ran, and expecting the full set after a single-screen pull is
the most common way to conclude an export "failed" when it did exactly what was asked:

| Pull | Writes (all under `design/export/`) |
|---|---|
| `dtwin pull --node <id>` (or a selection) | `pages/<Page>/<Screen>__<node-id>.json` (`exportedAt`, `screen`, `page`, `nodeId`, `nodes[]`, `manifest`, `sourceFile` — the connected Figma file this pull actually talked to, absent on a screen pulled by an older dtwin — the reference PNG path is `nodes[0].reference`), plus `…__<id>.vars.json` (that screen's tokens) and `…__<id>.assets.json` (its assets, with content hashes) beside it, a row in `pages/index.json` (also carrying `sourceFile`), the merged `variables.json`, and `assets/` |
| `dtwin pull --page <id>` / `--all-pages` | the same `pages/` tree, one file per top-level layer (each with a ROOT `reference`), and `assets/` |
| `dtwin pull --design-system` | `design-system.json` (slim pointer manifest) + `design-system/` (`tokens.json`, `components.local.json`, `components.library.json`, `styles.*.json`, `hygiene.json`). No page walk, no assets |
| every pull that writes to disk | `SCHEMA.md` — the scripting quick keys (the same text as the top of the build-screen skill's `ir-fields.md`); read it before scripting against the JSON. Rewritten only when its text changes; a `SCHEMA.md` you wrote yourself is left alone |
| `dtwin screenshot <id>` | `assets/<id>_ref.png` — the same place a later `--node` pull of that frame writes its own reference, so there is never a second copy. With `--scale N`: `assets/<id>_shot@<N>x.png`, which never takes the reference's name |

Single screens and whole pages land in **one** tree, so nothing downstream has to know which pull
produced a file. The node id is in the filename because a frame NAME does not identify a frame: two
`Popup`s on one page are two screens. Read `pages/index.json`; don't reconstruct filenames.

A single-screen pull writes **no `design-system/`**, and that is normal. `variables.json`
**accumulates** — a second screen's tokens merge in rather than replacing the first's. `dtwin doctor`
counts any of these as an export, and reports when one export mixes more than one Figma file.

## Then run it

Running an export is the **extract** skill's job — it owns path selection, the discover-then-scope
order, and the manifest check afterwards. Hand off to **`/designtwin:extract`** rather than reciting
commands here. Then: **`/designtwin:audit-design <screen>`** (is it buildable?) →
**`/designtwin:build-screen <screen>`**.

## Where the long-form docs live

**Without a clone of the Design Twin repo, the reference is `dtwin --help` (plus each command's own
`--help`) and the skills in this plugin** — including
[`references/troubleshooting.md`](references/troubleshooting.md), which lives inside this installed
plugin and is always readable. The repository docs are a different thing: `README.md` (workflow,
config-map shapes), `bridge/README.md` (full CLI + MCP surface, token, daemon, limits),
`figma-plugin/README.md` (the plugin's UI and outputs), `ARCHITECTURE.md` (CLI vs MCP front-ends,
security). Point a user at those only if they actually have a clone — the one-time setup step that
imports the Figma plugin does need one, since `figma-plugin/manifest.json` exists only there.

## Subagents this plugin ships

- **`designtwin:screen-builder`** — builds one screen with `build-screen` preloaded, in its own
  context. Used for multi-screen fan-out.
- **`designtwin:visual-verifier`** — renders a built screen, measures every node against the design's
  own numbers, checks that every component on the frame was actually built and that every designed
  interaction works, and writes the measurements to `design/verify/`. It returns measurements rather
  than a verdict: `node "${CLAUDE_PLUGIN_ROOT}/scripts/verify-screen.js" --compare` computes that, so "pass" is never something anyone
  asserts. Never edits app code. If the probe exits 3 (no usable browser), the install line it prints is the
  user's call; a Chromium they already have cached works too — `verify-probe.js --browser-path <executable>` (on macOS
  the binary inside the `.app`, `…/Contents/MacOS/…`; only guaranteed with the bundled Chromium).

## Related

- **Something broken:** [`references/troubleshooting.md`](references/troubleshooting.md).
- **Get the design out of Figma:** `/designtwin:extract`.
- **Check the design is buildable first (states, tokens, a11y, designer questions):** `/designtwin:audit-design <screen>`.
- **Build a screen from it:** `/designtwin:build-screen <screen>` — it handles multi-screen fan-out
  itself (one layer per subagent, so each screen's large JSON stays out of the main context).
- **Only check a built screen against its design (no code changes):** `/designtwin:verify <screen>` —
  renders it, compares it with the export and lists the differences with evidence. (It runs the
  `designtwin:visual-verifier` agent; `@agent-designtwin:visual-verifier` reaches the agent directly.)
- **A theme file from the Figma tokens** (CSS variables, or Swift / Kotlin / Dart / TS): part of
  `/designtwin:extract` — "set up my theme from Figma".
- **The design changed after you built it:** `/designtwin:sync-design <screen>` — diffs the old and
  new export and patches only what moved, keeping your hand edits. Commit `design/` so there is
  always a previous export to diff against.

Files in this skill

  • SKILL.md18.4 KB
  • evals/evals.json4.9 KB
  • references/troubleshooting.md16.1 KB

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.