What you’ll learn
When a design hands off to engineering, the question isn’t “does it look right?”
— it’s “can a machine read it cleanly?” A frame built with bound variables, auto
layout, real component instances, and meaningful names turns into tidy,
token-referencing code; one full of hardcoded colors and “Frame 27” layers turns
into a mess. handoff-qa measures exactly that and scores it out of 100.
Designers and managers, this one is for you. The score is a gauge — a needle from 0 (not machine-readable at all) to 100 (a clean design-to-code handoff) — and every point lost names the layer and the fix. No code reading required.
- The four scoring rules, what each weighs, and why
- How to create the read-only Figma token the command needs
- How to gate a build on the score and post findings back to Figma — safely
Setup
You’ll need the ds-bridge plugin and a Figma personal access token (PAT) from a Dev or Full seat. New here? Getting started covers install and setup; the drift tutorial covers the code side of the same handoff.
The command’s own help lists every option:
Usage: ds-bridge handoff [options] <url>
Score a Figma frame's pre-handoff machine-readability
Arguments:
url Figma frame URL (file/design/proto, optional node-id)
Options:
--threshold <n> readiness gate (0-100); exit 1 below it (default from
config, 80)
--format <format> output format: term | json (default: "term")
--comment post the score + top deductions as ONE Figma comment
(requires --yes) (default: false)
--yes confirm writing the --comment to Figma without an
interactive prompt (default: false)
-h, --help display help for command
Creating the Figma token
The command reads your frame over Figma’s API, so it needs a token. This is a five-minute, one-time setup:
-
In Figma, open Settings → Security → Personal access tokens and create a new token.
-
Give it exactly these read scopes (plus comment-write, if you want to post findings later):
file_content:read,library_content:read,file_versions:read,file_comments:read, andfile_comments:write. -
Make sure the token comes from a Dev or Full seat. A View seat is rate-limited to roughly a handful of requests per month and can’t be used here — this trips up a lot of teams, so it’s worth checking your seat first.
-
Paste it into the ds-bridge preferences dialog (it’s stored in your system keychain, never in a file), or for standalone CLI use export it:
export FIGMA_TOKEN=figd_your_token_here
Steps
-
Run the score. Point the command at a frame URL. Here’s a real run against an “almost ready” checkout frame:
Readiness 90/100 (threshold 80) — PASS ┌──────────────────────┬───────┐ │ stat │ value │ ├──────────────────────┼───────┤ │ nodes │ 13 │ │ bound coverage │ 86% │ │ auto-layout coverage │ 86% │ │ instances │ 2 │ │ detached suspects │ 0 │ │ default names │ 1 │ └──────────────────────┴───────┘ 3 deduction(s): ┌──────────────────┬─────────────────┬────────┬──────────────────────────────────┐ │ rule │ node │ points │ fix │ ├──────────────────┼─────────────────┼────────┼──────────────────────────────────┤ │ Variable binding │ Divider (12:5) │ -5.7 │ Bind fills/strokes to a variable │ │ Auto layout │ Frame 27 (12:6) │ -3.6 │ Add auto layout │ │ Naming │ Frame 27 (12:6) │ -1.2 │ Rename meaningfully │ └──────────────────┴─────────────────┴────────┴──────────────────────────────────┘(Example output rendered from a sample frame — live Figma scores will name your own layers.) Read it as a gauge: the needle sits at 90, the redline is 80, so this frame passes. The deductions are the three small things that cost the other ten points.
-
Understand the four rules and their weights. The score is 100 points split across four weighted rules:
- Variable binding — 40 points. The biggest lever. Fills and strokes
should be bound to variables, not hardcoded, so generated code gets token
references instead of raw hex. Here
Dividerhas an unbound fill — the largest deduction. - Auto layout — 25 points. Frames should use auto layout so the code
becomes flex/stack, not brittle absolute positioning.
Frame 27has none. - Component usage — 20 points. A layer named like a component should be a live instance of the published component, not a detached copy that won’t map to your coded component. This frame has none detached — a clean 20.
- Naming — 15 points. Default names like “Frame 27” produce meaningless code identifiers. Rename them to something a developer can read.
Each rule spreads its lost points evenly across the layers that failed it, so the list is naturally worst-first.
- Variable binding — 40 points. The biggest lever. Fills and strokes
should be bound to variables, not hardcoded, so generated code gets token
references instead of raw hex. Here
-
Gate on the score in CI. The exit code follows the threshold: 0 at or above it (gate passes), 1 below it. That makes it a one-line CI check:
ds-bridge handoff "$FRAME_URL" --threshold 80If a frame scores 72 against a threshold of 80, the command exits 1 and your pipeline can block the handoff until the designer tidies it up. Set the redline wherever your team wants it — strict teams use 90, gentler ones 70.
Result
You can now turn any frame into an objective, layer-by-layer readiness report and gate the handoff on it before a single line of code is generated. The score is a shared language: designers see which layer and what fix, managers see a number, and engineering gets frames that translate cleanly.
When a frame falls short, you can send the findings back to the designer as a
single Figma comment — but ds-bridge guards that write carefully. Posting needs
both --comment and --yes. Ask without confirming, and it refuses while
still showing the report:
refusing to comment without --yes (pass --comment --yes to write the summary to Figma)
Only when you add --yes does it post one comment with the score and the top
deductions:
ds-bridge handoff "$FRAME_URL" --comment --yes
The slash command /ds-bridge:handoff-qa makes this a choice, not a flag: when a
frame is below threshold it asks whether you’d like to post the summary, walk the
deductions node by node, or just stop — and it says plainly that posting writes
a comment to the Figma file. Writing to someone else’s design is never silent
and never a guess.
That completes the round trip: tokens stay in sync, code stays on system, and designs are ready before handoff. Next, zoom out from values to whole components with Build your component registry and parity matrix, or browse the full set on the tutorials index.
Troubleshooting
- “No Figma personal access token configured”? You haven’t set the PAT yet.
Add it in the preferences dialog or export
FIGMA_TOKEN, with the scopes listed in Setup. - “Figma rate-limited the request”? Almost always a View-seat token — those get only a few API calls a month. Switch to a Dev or Full-seat token.
- The score seems harsh on a finished design? Check bound coverage first. Unbound fills and strokes are 40 of the 100 points, so a beautiful frame with hardcoded colors still scores low — bind them to variables and watch the needle jump.