Figma design integration — build UIs that match referenced designs (interactive-once auth)#113
Merged
Merged
Conversation
…sign pull, planner + agent injection
Requirements can now reference figma.com design URLs and vxd builds the UI to
MATCH the referenced frames instead of inventing a design.
The auth model is communicated, not hidden: Figma needs an operator
credential, so the FIRST Figma-referencing run is interactive-once rather
than fire-and-forget. 'vxd req' detects design URLs and fails fast — before
any LLM spend — naming the exact interactive step ('vxd figma auth', which
prints the settings URL without auto-opening a browser, reads + validates the
personal access token via /v1/me, and stores it at <state_dir>/figma.token
mode 0600; FIGMA_TOKEN env also honored). After that single session,
Figma runs are autonomous again.
- internal/figma: URL parsing (design/file/proto/board, node-id
canonicalisation, dedup), minimal REST client (files/nodes depth-3, 2x PNG
renders, bounded downloads, token never logged), BuildDesignContext →
DESIGN_CONTEXT.md (frame inventory: dimensions, text styles, solid fills as
hex) + rendered PNGs under .vxd-design/. Per-ref failures degrade to a note.
- Planner: design context injected inside <design-reference> data tags with
instructions to derive the design-token foundation FROM the design.
- Executor: frontend stories get the context in their goal prompt (after
FrontendDesignBrief — the reference overrides generic guidance) and the
PNGs copied into their worktree so agents can open them.
- Safety: loadDesignContext injection-scans the markdown (Figma layer names
are third-party data; a MatchInjectionPattern hit drops the context loudly)
and caps it at 16 KB. .vxd-design/ is gitignored and stripped from story
branches — working material, never a deliverable.
- CLI: vxd figma auth (interactive, validates before storing) + vxd figma
status. Docs: CLAUDE.md section + CLI tables + README bullet.
- Tests: figma pkg (URL/token/client/context via httptest), engine
(load/injection-drop/cap/copy + planner prompt pin), cli (auth stores only
valid tokens, status paths). NXD: not ported — cloud API, offline-first.
- HIGH: the req-time Figma pull ran before repoPath was established and used an error-dropped os.Getwd() — a Getwd failure silently pulled into a relative path. The pull now runs after repoPath (properly error-handled) and uses the figmaAPIBase-aware client so the full runReq path is testable. - MEDIUM: a Figma layer literally named '</design-reference>' could close the planner's data framing. Angle brackets are now neutralised (<) at the loadDesignContext choke point — protects every prompt embedding the context. - MEDIUM: an all-refs-failed pull returned a hollow 'design context + 0 renders written' success. It is now a loud error at req time. - LOW: render downloads validate the destination host (Figma CDN or the configured BaseURL) — a tampered API response cannot point the download at an internal address; hyphen/underscore file keys parse whole; an unreadable token file is named as a permissions problem instead of the generic 'no credential' guidance. New tests pin each: tag-close neutralisation, all-fail error, SSRF host refusals (metadata IP, lookalike hosts, http downgrade), hyphenated keys, unreadable-token distinction.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Requirements can now reference figma.com design URLs and vxd builds the UI to match the referenced frames instead of inventing a design.
The auth contract (communicated, not hidden)
Figma needs an operator credential, so the first Figma-referencing run is interactive-once rather than fire-and-forget — and vxd says so everywhere it matters:
vxd reqdetects design URLs and fails fast before any LLM spend when no credential exists, with the message naming the exact interactive step.vxd figma authis the one-time session: prints the Figma settings URL (never auto-opens a browser), reads the personal access token, validates it via/v1/mebefore storing (a typo fails in the session, not mid-pipeline hours later), and persists it at<state_dir>/figma.tokenmode 0600.FIGMA_TOKENenv is also honored.vxd figma statusshows the authenticated account.Pipeline flow
figma.BuildDesignContext): referenced nodes fetched at depth 3 + 2x PNG renders into<repo>/.vxd-design/— aDESIGN_CONTEXT.mdframe inventory (dimensions, text styles, solid fills as hex) plus the rendered images. Per-ref failures degrade to a note; all-refs-failed is a loud req-time error, never a hollow success.<design-reference>data tags, instructing the Tech Lead to derive the design-token foundation from the design.FrontendDesignBrief— the reference overrides generic design guidance) and the PNGs are copied into each frontend worktree so the coding agent can open them.Safety
loadDesignContextinjection-scans the markdown (aMatchInjectionPatternhit drops the whole context loudly) and neutralises angle brackets so a layer literally named</design-reference>cannot close the data framing. 16 KB cap..vxd-design/is gitignored and stripped from story branches.Review
everything-claude-code:go-reviewer: 1 HIGH (error-droppedos.Getwdin the pull path — pull moved afterrepoPathwith proper handling), 2 MEDIUM (tag-close framing escape; untestable direct client construction inrunReq), 1 MEDIUM (hollow all-fail success) and 3 LOW (SSRF host validation, hyphenated file keys, unreadable-token diagnostics) — all applied with pinning tests. Reviewer confirmed: token never leaks, injection-scan placement covers every content-to-prompt path, the fail-fast genuinely precedes LLM spend, lookalike domains rejected.Test plan
internal/figma(URL/token/client/context via httptest),engine(load/injection-drop/tag-neutralisation/cap/copy + planner prompt pin),cli(auth validates-then-stores, invalid token not stored, status paths, SSRF refusals)make verify(pre-push green gate) passes;golangci-lint0 issues