storysync-diff

storysync-diff is a command for Claude Code from brendanciccone/storysync. It costs 12 tokens per session (2,796 once invoked), scanned A, original, MIT.

A command that compares a Figma design file with the project's design tokens and Storybook components. Figma is a design tool, while Storybook is a tool for viewing and testing interface components in code.

In plain words
What is it for?
Use it to compare colors, spacing, corner shapes, component variants, and other design details between Figma and the codebase.
Why use it?
It finds differences between what was designed and what was implemented before those differences become harder to fix.

Command for Claude Code

Written for Claude Code: argument-hint in frontmatter. Also seen: reads .claude/ paths.

Good fit Use it to compare colors, spacing, corner shapes, component variants, and other design details between Figma and the codebase.

Compare 6 commands from other repositories ↓
Install with agentmods
npx agentmods add commands/brendanciccone/storysync/storysync-diff
Install

Getting it into your agent

One page per mod, every tool's command on it. A separate URL per tool would split the same page into five that compete with each other.

Clone the repo
git clone --depth 1 https://github.com/brendanciccone/storysync

Made for: Claude Code.

Wrote this? Show the measurements

A badge with what this costs and how it scanned, read live from this page, so it follows the numbers instead of freezing them. Markdown for a README, HTML for a documentation site or a project page.

agentmods badge for storysync-diff

README.md
[![agentmods](https://agentmods.dev/badge/commands/brendanciccone/storysync/storysync-diff/github.svg)](https://agentmods.dev/commands/brendanciccone/storysync/storysync-diff)
Your own site
<a href="https://agentmods.dev/commands/brendanciccone/storysync/storysync-diff"><img src="https://agentmods.dev/badge/commands/brendanciccone/storysync/storysync-diff/github.svg" alt="Measured on agentmods" height="20"></a>

Or the 80×15 button, for a site that already has a row of RSS and ATOM ones. Only the verdict fits; the numbers stay here.

agentmods 80×15 button for storysync-diff

Your own site · 80×15
<a href="https://agentmods.dev/commands/brendanciccone/storysync/storysync-diff"><img src="https://agentmods.dev/badge/commands/brendanciccone/storysync/storysync-diff.svg" alt="Reviewed on agentmods" width="80" height="20"></a>
Per session 12 Only the description is in the session, so the agent can decide to use it. The body loads when it is invoked.
When invoked 2,796 The whole file, excluding the scripts and references it only reads on demand.
Security scan A 0 findings. A grade says what 26 rules found in the file — not that it is safe.
Origin original No closer match found in the catalogue.
Token cost

What it costs to keep this loaded

Counted locally with the o200k_base tokenizer, which is exact for GPT models; Claude uses its own tokenizer and its counts differ. Treat this as one consistent yardstick across the catalogue rather than a bill. Prices are per million input tokens.

ModelPer sessionOnce invoked
Fable 5.1 $0.00012 $0.02796
Opus 5.5 $0.00005 $0.01118
Sonnet 5.5 $0.00002 $0.00559
Haiku 4.5 $0.00001 $0.00280

Measured 23d ago against content hash 1b2039d7b978, method: parsed. Prices are Anthropic first-party input rates as of 2026-10-07, from the pricing page.

Security

Grade A, and why

storysync-diff scanned grade A with 0 findings against 26 rules in 11 categories — prompt injection, anti-refusal, data exfiltration, privilege escalation, supply chain, agent snooping, system-prompt leakage, SSRF and excessive agency — measured 23d ago.

A static scan of the body, not an audit. Every finding is printed with the line that produced it so you can judge whether it matters here. A mod is markdown that instructs an agent; that is exactly why what it instructs is worth reading.

Nothing flagged

None of the 26 patterns this scan looks for appear in this file: no shell pipes, no recursive deletes, no credential paths, no hidden text, no instruction-override or anti-refusal phrasing, no agent-config snooping. That is not a guarantee, it is the absence of the things that are checkable.

commands/storysync-diff.md · 30 lines

How it starts

The opening of the file, as written. The whole thing — 30 lines — stays where its author put it; the contents beside it link to each section on GitHub.

Compare the current Figma file against this codebase's design tokens and Storybook components, then report drift in either direction. Use the storysync skill at .claude/skills/storysync/SKILL.md (Audit section).

Figma file key: $ARGUMENTS

If the user did not provide a file key (or $ARGUMENTS is empty), ask for it. The file key is the part of a Figma URL between /design/ and the next /.

Workflow. The step numbers here are this command's own: steps 1 to 6 are the skill's Audit steps 1 to 6, steps 7 and 8 its step 7, and step 9 its step 8.

  1. Read Figma variables: call use_figma to enumerate every variable collection and its resolved values (use figma.variables.getLocalVariableCollectionsAsync() and convert COLOR values to hex, #rrggbb with the alpha as two more digits when it comes to less than ff). It reads each variable in its collection's first mode and, in a collection of several modes, in each, as modes by mode name, for step 5 to compare the Dark one with the code's dark theme. use_figma returns at most 20kb per call, which a full palette passes, so read them a slice per call with the skill's template, from the next each call returns until it is null.
  2. Read Figma components: call use_figma to enumerate every component set and its variant properties, and every component outside a set (the push makes a component with no variant properties a plain component), a page at a time: use_figma loads pages as it switches to them and does not support figma.loadAllPagesAsync(), so a search from figma.root sees only the pages already loaded and misses the sets on the rest. List the pages (figma.root.children), then make one call per page with the skill's template: it switches to the page with figma.setCurrentPageAsync, uses page.findAllWithCriteria({ types: ['COMPONENT_SET', 'COMPONENT'] }) without the sets' variants, and returns each one's nodeId, type, the storybookId the push stored on it (getSharedPluginData('storysync', 'id')) and componentPropertyDefinitions, as many per call as fit under 20kb, from the next each call returns as in step 1. Figma throws Component set has existing errors reading a set it flags as errored: the template returns that set with its error and reads on.
  3. Run npx storysync tokens --json --project . for code-side tokens. If its warnings say storysync can't read or find part of the Tailwind config, or doesn't follow it, or read no theme from it, code is missing the tokens that part declares: in step 7, report a Figma variable that code lacks as possibly coming from what the warning names, not as orphaned, and name the warning.
  4. Run npx storysync map --storybook http://localhost:6006 --json for code-side components. map leaves out what the push left out, reading each component's excludedProps from .storysync/snaps/styles.json, which keeps the record of every component a push measured, and takes the props the stories' argTypes and args add from it too; pass --snap <dir> if the push's snap is elsewhere. Without that file, pass the --exclude-props the push used, if any, from the push's summary, which names them; otherwise every prop it left out is reported missing from Figma. If neither has them, and props come back missing from Figma on components the push made (those with a storybookId), ask the user whether the push left those out before reporting them. If the user asked about some components only, first run npx storysync list --storybook http://localhost:6006 --json for every component's id, name, title and category, to pair with in step 6, then pass map with --components only the scope's names that list has (by id, title, name or the last segment of title, ignoring case) rather than map every component, which can take many minutes: map refuses a name Storybook doesn't have, and a name only Figma has is for step 6. If list has none of them, skip map.
  5. Compare tokens by name within each category. storysync's own alpha and per-mode variables (destructive 10%, destructive 10% dark 20%, background dark input 30%, input 0% dark 30%, slate-50 dark slate-900, [#3f3f3f] dark [#e8e8e8]) are not missing from code while each color in the name is a code token (the one after dark written as a class names it, muted-foreground for muted/foreground), a Tailwind palette color or an arbitrary [#rrggbb]: leave them out of the report; one whose token is gone is -. Normalize before comparing: compare a color by its token's hex and a length by its px (rem and calc() worked out) where the token has one; otherwise lowercase hex, convert rem→px, strip units. A translucent color is #rrggbbaa on both sides: compare all eight digits. Round numbers to thousandths on both sides. Match Figma collection names to code categories (Colors→colors, Border Radius→radius, etc.). Compare each collection's first mode with the token's light value and, where the tokens output's modes includes Dark, each variable's Dark mode with the token's dark hex or px, or its light ones where it has no dark; a token with a dark whose collection has no Dark mode is missing from Figma in Dark. Note what can't be compared, for step 8 to name: every mode of a Figma collection but its first and the Dark one, and the Dark one too where the tokens output's modes has no Dark; the tokens a tokens warning says it didn't read (Unresolved:, Skipped dynamic value:, Not read from @theme, Uncategorized:); and the categories tokens has no collection for in a project on Tailwind, whose components use Tailwind's default spacing, type or shadow scale, which tokens doesn't extract.
  6. Compare components by Storybook ID first: a Figma component whose storybookId is a code component's id is that component's, whatever its name or page (two with it, as a copy of a set has, are told apart by page as below), and one whose storybookId no code component has is Figma only, never paired with another component by name. Compare the code components no ID paired with the sets that have no storybookId by set name (case-insensitive): the last segment of a component's title, or its name without one, or its name where no set has that and it is no other component's set name. A name only one code component and one set have is a pair. If two code components share a name, or two Figma component sets do (on different pages: an archived copy, say, or each category's own Button), counting those an ID paired, pair a component with the set of its name on its category's page (Components without one, comparing page names ignoring case, spaces, /, - and _) where each is the only one of the name on that page on its side; of the copies left, code's alone are code only and Figma's alone Figma only. Copies left on both sides, even one of each, can't be told apart (a set on another page may be the component's, moved, or an archived copy beside a component not pushed yet): report the name as ambiguous, and only as ambiguous: compare none of the copies left, and don't also count them as matched, mismatched or missing. A component outside any set with no storybookId may be a designer's own, such as an icon: it pairs only with a code component the sets left code only, of its set name and on its category's page, each the only one there, and never makes a name ambiguous. One left unpaired is not one the push made, since the push stores a storybookId on each component it makes: don't list it as Figma only, but count it as not compared, unless the scope names it. A set with an error pairs as any set, but is reported as errored in Figma (can't read its properties), by name, page and nodeId, with nothing in it compared; don't delete it unless the user asks. When the audit is scoped, pair with every component list gave, but compare and report only those in scope, and a Figma component paired with none only if the scope names it; a name in the scope that neither list nor Figma has is a typo: say so. For each pair: missing props, extra props, missing/extra values per prop.
  7. Report drift grouped by category/component:
    • + missing from Figma (in code, not in Figma)
    • - missing from code (in Figma, not in code)
    • ~ value mismatch (both exist, values differ)
    • ? ambiguous (a name two code components or two Figma component sets share, none of its copies compared)
    • ! errored in Figma (a set whose properties Figma won't give, compared with nothing)
  8. End with a summary: N tokens matched / mismatched / missing. N components matched / mismatched / code-only / Figma-only / ambiguous / errored in Figma, and N components outside any set not from the push, not compared. Beside the token counts, say what they cover and what they don't, so 39 matched isn't read as every token in both themes: 39 matched (colors and radius, in Light and Dark; not compared: the High contrast mode of Colors, font/sans and font/mono, which tokens couldn't resolve, and Tailwind's default spacing, type and shadow scales, which have no tokens). Confirm "Figma and code are in sync." only if everything matches and no name is ambiguous or set errored; components outside any set not from the push don't count against it. An ambiguous name was compared on none of its copies, and an errored set on nothing, so either can hide drift: while any is, name them instead, and never say the two are in sync. Say with it what the audit compares: tokens, in the modes it noted, and each component's variant properties, not the styles the push's verify scores.
  9. When the user asks whether the sets look like the code, not only whether their names and values agree, score them as the push's verify does, reading Figma and changing nothing, with the skill's Audit step 8: snap the components in scope with --out .storysync/audit/snaps (in the background, with --variants all, the push's --exclude-props and --keep-props, and the push's --stories, <id>=<storyId> for each component in scope from the storyId the push's .storysync/snaps/styles.json records, ending it with ! where the component records storyOnly: true, as in npx storysync snap --storybook http://localhost:6006 --variants all --out .storysync/audit/snaps --json), run npx storysync figma code --snap .storysync/audit/snaps/styles.json --out .storysync/audit/figma, send only the plan's read calls, never its build, images or label calls, saving each response unchanged and continuing each with npx storysync figma next --plan .storysync/audit/figma/plan.json --seq <its seq>, then run npx storysync verify --plan .storysync/audit/figma/plan.json. Add to the report each component's element fidelity and differences by key and node id, elements missing or no longer measured, designer layers, pictures not filled, sets an earlier storysync pushed root-only (their variants read as not built by storysync, which a push deepens), sets no read found, and that the element-tree readback doesn't read variable bindings yet. Never fix what it finds in the audit.

Read the full file on GitHub · 30 lines

Changes

What this file has done since we first saw it

Hashed on every crawl. A supply-chain change to an agent config is a question of when, not whether, so the history is kept rather than the latest state alone.

  1. 23d ago Changed · +2 lines 1b2039d7b978
  2. 1mo ago Changed · +1 lines 3f79a830994e
  3. 2mo ago First seen · 27 lines · 12 tokens per session scan A 072cbde49679

Subscribe to this mod's changes

storysync-diff is a command published in the GitHub repository brendanciccone/storysync (75 stars, last pushed 8d ago), licensed MIT. It adds 12 tokens to every session and 2,796 once invoked, about $0.0000 per session on Opus 5.5. A static security scan graded it A with 0 findings. No closer match exists in the catalogue, so it is treated as the original; first seen 2026-08-30.

Related

storysync-diff compared with commands from other repositories

storysync-diff next to 6 commands from other repositories
ModTypeStarsLast pushLicenceScanTokensWorks with
storysync-diffbrendanciccone/storysyncCommand758d agoMITA12Claude Code
profilecathrynlavery/diagram-designCommand65k3d agoMITA16Claude Code
erne-animateJubaKitiashvili/everything-react-native-expoCommand5029d agoMITA21Claude Code
ui-flow-reviewMRCalderon3D/everything-game-dev-codeCommand10428d agoMITA15Claude Code
responsive-design-specialistimsaif/design-with-claudeCommand11yesterdayMITA36Claude Code
design-auditw2ur/claude-code-setupCommand23d agoMITA30Claude Code
ppt-image2-editable-rebuildwwe-dog/ppt-image2-editable-rebuildCommand2045mo agoUnlicenseA15Claude Code