Delivery Factory · Part 3 · Figma Extract

The Figma plugin, from design link to files

The design stage needs the values, the images and a screenshot of one Figma node. The plugin that provides them is a separate pack with one operation. This page follows it from the link to the files: which tools it calls, which scripts decide, and when it passes, asks a human or stops. Repo: agentic-figma

Checked in Code

Everything on this page was read in the plugin's skill, scripts, manifest and README, not only in the README. Paths are relative to plugins/figma/ unless said otherwise.

From link to files1200 × 627
DELIVERY FACTORY · PART 3 The Figma plugin, from design link to files. INPUT MCP TOOL SCRIPT · SORTS OUTCOME reference figma.com/design/… ?node-id=… get_metadata the node, its size, its children classify-node.py single · variants page · multi-frame PASS one frame, or its viewport versions each fetched, widest first QUESTION a page, or several frames every candidate listed, none picked FAIL bad link · no node · no access or the plugin is missing · error class set PER TARGET, ONE AT A TIME get_design_context values + images and icons get_variable_defs design tokens, once get_screenshot reference image .ai/figma/<file>-<node>.json · .png · .context.txt · assets/ what the next stage reads, in a fixed shape A link with no node id is a question before any tool is loaded. A link that is not a /design/ URL is a fail.
One input line in, one verdict and a folder of files out. The model calls the tools. Which frames to fetch comes from scripts reading the metadata on disk.

The parts

A plugin of its own

The Figma pack plays one role in the pipeline: design. It has its own manifest, skill, scripts and tests, and it runs no server.

Four tools from the Figma plugin

Each with one job

  • get_metadata: confirms the node exists; its name, size and children.
  • get_design_context: reference code whose classes carry layout, colour and type, and the download links for images and icons.
  • get_variable_defs: a map of token name to value. An empty map is a normal result.
  • get_screenshot: a short-lived image link with rendered and original size.
Before any call

Load, then use

  • The skill loads the four tools through ToolSearch, then loads figma:figma-design-to-code, which get_design_context asks for.
  • That skill is loaded for its prerequisite only. The operation writes no application code.
  • It never calls authenticate. An unattended run has nobody to open the sign-in link.

The classifier

Four classes, decided by a script

classify-node.py reads the metadata file from disk. The model reads its first line and never re-decides the class from names, sizes or the ticket.

A child is a viewport version when its own name matches a rule, checked in this order (pattern, keyword, width), or when size alone separates same-named frames:

Pattern: Hero / Desktop, Hero - Mobile, Desktop View, @mobile.

Keyword: a name token is desktop, mobile, tablet, responsive, phone or web.

Width: a name token is 1440, 1280, 1024, 768, 375, 390 or 414, with or without px.

Size: frames with the same base name where one is wider than 900 and one is narrower than 500.

# classification.tsv, one line per frame-like child (example names)
class	variants
node	frame	1:100	Logo Row
child	1:118	1200	variant	name:pattern=desktop	Logo Row / Desktop
child	1:131	720	variant	name:pattern=tablet	Logo Row / Tablet
child	1:144	375	variant	name:pattern=mobile	Logo Row / Mobile

A page or several frames: the question lists every candidate, none dropped, reordered or marked as preferred. Not even one whose name matches the work item.

The fetch

What it writes, and what it keeps out of files

Design values and images land in .ai/figma/ in a fixed shape. Download links are short-lived and never written down.

  1. Check the link: a figma.com/design/ URL with a node-id. For a branch URL the branch key is used as the file key.
  2. Load the four tools. get_metadata, then write its response whole to <file>-<node>.metadata.xml.
  3. classify-node.py writes .classification.tsv. For variants, viewports.py plan prints one target per version, widest first, and only those are fetched.
  4. Per target: get_design_context, with the screenshot left out of it. Keep the code block and the styles line verbatim.
  5. The code block goes to fetch-assets.py on stdin. It downloads every image and icon, names each format from its bytes, and rewrites the code to point at local files.
  6. get_variable_defs once, for the referenced node.
  7. screenshot-size.py max sizes the request to the node's longer edge. get_screenshot per target, downloaded before the link expires.
  8. Write <file>-<node>.json and report pass with the list of files written.

Formats from bytes. sniff-asset.py recognises png, jpg, gif, webp and svg from the first bytes of the file. The name or the URL is never trusted. Bytes of no known format stop the operation.

Files named by content. Each asset is written as the first 16 hex digits of its SHA-256 plus the extension. Identical bytes are one file. A name already holding different bytes is refused, so no earlier file is replaced.

No URL on disk. The asset links and the screenshot link exist only in the tool response and in the command that uses them. The script refuses a result that still contains one.

## Result
verdict: pass
summary: <node name> from <Figma file>
artifacts:
  - .ai/figma/<file>-<node>.json
  - .ai/figma/<file>-<node>.png
  - .ai/figma/<file>-<node>.metadata.xml
  - .ai/figma/<file>-<node>.classification.tsv
  - .ai/figma/<file>-<node>.context.txt
next_action: none
metrics: variables=<n> design_context=code
  node_class=single downscaled=0 assets=<n>

A design context returned as structure only, or cut short by the tool's size cap, is recorded as structure_only. It is a pass, not an error: metadata, tokens and the screenshot still cover the node.

Pass, ask, stop

Three verdicts, and the class behind a fail

The operation ends in exactly one of three verdicts. A fail always carries an error class, read off what the tool actually returned.

## Result
verdict: fail
summary: Figma is not authenticated: run /plugin,
  select figma, choose Authenticate, finish
  sign-in in the browser, then re-run.
artifacts: []
next_action: none
error_class: PERMANENT

The shape of a fail, with the exact summary the plugin uses when authentication is what is missing. The text tells the person what to do, not only that it failed.

The authentication remedy is also declared in pack.yaml for each of the four session tools, so the run can name it before any work starts.

What it doesn't cover

It reads the design as drawn

The plugin gets the values and the picture. It does not judge them.