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.
git clone --depth 1 https://github.com/brendanciccone/storysyncWrote 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.
[](https://agentmods.dev/commands/brendanciccone/storysync/storysync-push)<a href="https://agentmods.dev/commands/brendanciccone/storysync/storysync-push"><img src="https://agentmods.dev/badge/commands/brendanciccone/storysync/storysync-push/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.
<a href="https://agentmods.dev/commands/brendanciccone/storysync/storysync-push"><img src="https://agentmods.dev/badge/commands/brendanciccone/storysync/storysync-push.svg" alt="Reviewed on agentmods" width="80" height="20"></a>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.
| Model | Per session | Once invoked |
|---|---|---|
| Fable 5.1 | $0.00012 | $0.05900 |
| Opus 5.5 | $0.00005 | $0.02360 |
| Sonnet 5.5 | $0.00002 | $0.01180 |
| Haiku 4.5 | $0.00001 | $0.00590 |
Grade A, and why
storysync-push 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.
How it starts
The opening of the file, as written. The whole thing — 28 lines — stays where its author put it; the contents beside it link to each section on GitHub.
Push design tokens and Storybook components from this codebase into Figma using the storysync skill at .claude/skills/storysync/SKILL.md.
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. The skill numbers its Components steps one lower from measuring on, so this command's steps 4 to 8 are the skill's Components steps 3 to 7: verify runs in step 7 here and in the skill's Components step 6. A reference to one of the skill's steps names its section, such as the skill's Components step 5.
- Run
mkdir -p .storysync && npx storysync tokens --json --project . > .storysync/tokens.jsonto extract design tokens from the project, and read them there. If a warning says storysync can't read or find part of the Tailwind config, or doesn't follow it, such as a preset from a package, a config built by a function, or a file it names, or that it read no theme from the config, tell the user what it names, since those tokens won't reach Figma. If one says it read another source rather than atailwind.config.mtsor.cts, tell the user, who can pass--source tailwindto read the config. If no tokens are found, skip token sync and continue with components. - Run
npx storysync figma tokens, which writes ause_figmacall per token collection (Colors,Spacing,Radius,Typography) under.storysync/figma/tokens/calls/, listed in.storysync/figma/tokens/plan.json, and send them inseqorder as step 6 sends a plan's:codethe file unchanged,descriptionitsdescription, the file key andskillNames: "figma-use", saving each response unchanged to itsresult. Write no variable code yourself. Each call creates or updates its collection and each variable by name, adds aDarkmode where the tokens have a dark theme, renames a lone modeLightorDefault, and sets each variable's scopes, writing only what differs, so a push sent again changes nothing. Note for the summary each token it prints as one it has to leave out, any token atokenswarning startingUnresolved:names among them, and the tokens a warning says were not read from@theme, which are out of the output already, as are those a warning startingSkipped dynamic value:names: name them too. Note each response'screated,updated,unchanged,modesanddarkErroras well. Never remove a variable on your own: each collection's first response lists instalethe variables no token has, asCollection/name(an earlier push'sRadius/DEFAULT, say), and inconflictsthose of a token's name that can't be its variable, all left as they are. Ask the user once which to remove, saying a layer bound to one keeps its value, detached; for those confirmed, runnpx storysync figma tokens --remove <Collection/name>, a--removefor each, and send the new calls from the first. If a call says two collections have its name, ask the user which to keep and to delete the other in Figma, then send it again; forScript exceeded time limit, runfigma tokensagain with--max-variables 20and send the new calls from the first; forThis call differs from the file storysync figma tokens wrote, send the file again exactly as it is. It keeps the alpha variables an earlier push made up to date with their tokens; the plan step 5'sfigma codewrites makes its own in its first call. - Run
npx storysync list --storybook http://localhost:6006 --jsonto count the components, with each one'sid,titleandcategory. If Storybook isn't running on port 6006, ask the user for the correct URL; if Storybook has no MCP endpoint, ask them to runnpx storysync init, then restart Storybook, and if its install fails, pass on the command it prints afterRun manually:rather than retrying. Step 4 takes several seconds a component, more on a busy Storybook (134 components took about 17 minutes), so with more than about 20 components, stop and ask the user what to push before measuring anything: all of them, some categories (name each with how many components it has), or some components, passed to snap as--componentsby ID. When you ask, say that a push isn't lightweight: plan on roughly 100k agent tokens a component, plus about 100k a push for setup and verification, so about 1.1M for 10 components and 3.1M for 30. Don't runmapas well: snap's output carries the same variant properties, and map would read every component's docs twice. If a command fails because Storybook didn't answer in time, run it again with the flag its error names raised:--request-timeout 900000for a request, which has five minutes by default, or--connect-timeout 180000for connecting. - REQUIRED: Measure the styling, don't infer it. Run
mkdir -p .storysync && STORYSYNC_PROGRESS=1 npx storysync snap --storybook http://localhost:6006 --variants all --json > .storysync/snap-out.json 2> .storysync/snap-progress.log; echo "exit $?" >> .storysync/snap-progress.lognow, in this session, adding--componentswith the IDs step 3 agreed on unless the user chose every component (it replaces those in.storysync/snaps/styles.jsonand keeps every other component an earlier push measured; where that snap was measured with other flags or another Storysync it refuses and says how, so run it with the same flags, or ask the user whether to drop the others' record with--no-merge), and--stories <ID>=<story ID>for a component the user wants measured from another of its stories (itsstoryIdsin step 3's list). Run it in the background (run_in_background), since your shell stops a foreground command after 2 to 10 minutes and a snap stopped part-way writes nothing. You're told when it ends; its progress shows withtail -n 1 .storysync/snap-progress.log(lines likesnap 12/134 UI Base/Command, variant 3/32), and its last line is itsexitcode.exit 0means it finished;exit 1that it failed, with the reason as{"error": ...}in.storysync/snap-out.json(or, for an option it can't take, in the progress log);exit 130,143or129that it was stopped. After any exit but 0,.storysync/snaps/styles.jsonandmeta.jsonare an earlier run's: never build from them, and run it again. Afterexit 0, check too thatmeta.jsonis this run's: itsmeasuredAtis after you started it, or, after a--mergeor a--componentsrun that merged, which keepmeasuredAtat the oldest component's time on purpose, itscomponentsMeasuredAttime for each component you named is. It renders every combination in a real browser and records each variant's outer element and every element inside it that draws, with its styles, text, icons and pictures (thumbnails under.storysync/snaps/assets/). You don't translate any of it into Figma: step 5'sfigma codedoes. Tell the user what snap'smessagessay, itsi,!and✗lines, which--jsonputs first insnap-out.json(jq -r '.messages[] | "\(.level) \(.component // ""): \(.text)"' .storysync/snap-out.json), this run's alone, since a run that merged says nothing of the components it kept (keptComponents): among them, a warning that it measured a component in its dark color scheme (scheme: "dark"), where Storybook would render only dark, and one that a story fails with Storybook's own error, with the story's fix. Read what it recorded from.storysync/snaps/styles.jsonon disk, a component at a time, not fromsnap-out.json, the same JSON on one line that tools cut short: each component'swarnings,capandargsNotInDocsandexcludedProps, and each variant'sstatus,appliedViaandargsChecked. Do not reuse an earlierstyles.json: it may describe code that has since changed. Every snap variant becomes a Figma variant, whatever its status: a component set needs every combination. If a component has acapfield (more combinations than the limit, 256 by default), stop and ask the user before building it: build the measured subset (itsuncoveredlist names any values it leaves out), measure it again with--components <its ID> --merge --max-combinations <total>, or narrow which props are variants: re-run snap with--exclude-propsnaming the props that don't change how it looks, such asmodalorloop, which leaves them out of every component. Do not offer to infer the rest from source: they can be measured. For atimeout, which snap already tried twice if the story was loading, the second time with three times as long (or as long, once such a try in the component timed out too), first measure those components again, in the background, adding--components <their IDs> --mergeand a longer--timeout, such as 30000, to the same command:--mergemeasures only those and merges them intostyles.json, keeping the rest, and records each component's time inmeta.json'scomponentsMeasuredAt.--componentsalone merges the same way where there is a snap to add to; never pass--no-mergeto measure some again, which drops every other component's record. A variant whosestatusis still not"ok"is built as a placeholder labeledNot measured: <status>, whichverifylists and never scores: never style one from source, and name each in the summary with the story change it needs. Anarg_rejectedvariant is a value the story's argTypes don't allow that snap couldn't set through Storybook's preview either: name it in the summary with the story change snap's warning gives. Values snap did set through the preview (appliedVia: "preview") were measured, unless the variant'sstatussays it failed after that: build them as measured, and name that story change in the summary too. A variant markedargsChecked: falsewas measured, but snap couldn't check that the story was given its values, so it may be the default under its name: measure those components again with--components <their IDs> --merge, and if they stay marked, build what was measured and name them in the summary. A component'sargsNotInDocslists choices its story's argTypes declare that Storybook's docs don't, such as a Sheet'ssideor a Button'sdisabled: snap makes them variant properties, their default the story's own arg. A prop neither the docs nor the argTypes list that the stories' own args set, as coder's Button's cvavariantandsize, becomes one too, of the values those stories give, its default the component's story's value; where no story names the component's default,defaultstands for the prop left unset (markedunset), measured with no value given. ItsexcludedPropslists the props snap left out, each with itsreason(no-op: every value measured the same, inside the outer element too, even where a story's own args set one;no-control,hiddenorevent: marked in the argTypes;opens: itsvalueopens what a closed trigger hides, or renders the component where the defaults rendered nothing, as a ConfirmDialog story'sopen: true, so every variant is measured with it), which it says once per component: name them in the summary, and if the user wants one as a variant property anyway, re-run snap with--keep-props <name>. Where snap warns that a prop's values all measured the same, build what was measured rather than styling it from source. Where it warns that every variant measured identically, it says whether their markup changed too: if theyrendered the same markup, the story may not pass its args through; iftheir markup changed with the args, the story passes them, and the props it names change nothing snap measures, likely only behavior (input-otp'stextAlign), so never blame the story: ask the user, with any cap or trigger question, whether to leave them out with the--exclude-propsthe warning gives, added to any this push passes, or to build the identical variants as measured. Where it warns that it measured a closed trigger (a dialog, popover, sheet, menu or tooltip that renders its content only while open) or a layout wrapper rather than the component, stop before building any of them and ask the user once, listing each such component with the element measured, in the same message as any cap question: build what was measured, and say so in the summary and in Figma, on a line of each such set's description that startsstorysync:, which the plan's label call writes in step 6 on every push, keeping every other line, a designer's own included, and removing the line an earlier push left once a set is no longer measured that way; skip them, naming them in the summary, and pass their IDs to step 5'sfigma codeand step 7'sverifyas--skip, which leaves them out of the push and out of the score, since they stay instyles.json; or stop, so they can give each a story that renders it open or on its own, then measure those again with--components <their IDs> --merge. Don't choose for them, and never style such a component from source. - Save the tokens, now that their variables exist, with
npx storysync tokens --json --project . > .storysync/tokens.json, then write the push's calls withnpx storysync figma code --components <the agreed IDs>(and--skipfor any the user chose not to push). It writes.storysync/figma/plan.jsonand everyuse_figmacall under.storysync/figma/calls/: the builds, animagescall per page that shows a picture, thelabelcalls and the reads; the first build and the first read carry their template and store it in the Figma file for the calls after them, so send them first. It makes a page percategory, the whole of it (Componentsfor a component without one), found ignoring case, spaces,/,-and_, and puts each set on its category's page, named by the last segment of itstitle(Buttonforui/base/Button), or by itsnamewhen it has no title, soui/base/Buttonandui/radix/Buttonstay two sets; an existing set is found by name, or by the Storybook id an earlier push stored on it, and restyled in place. Note each warning it prints for the summary: variants built as aNot measuredplaceholder, valuesleft unboundbecause several variables share them and no class names one, or a radiusleft unboundbecause its frame is drawn at an inner radius no token holds, thingsnot builtthat Figma can't draw, orbuilt assomething it draws another way, framesbuilt without auto layout, a variant sent in parts or one with a layer too big for any call, andno tokens at …, which means save the tokens and run it again. Where it warns that an earlier push built a component as one plain component and it now has variant properties, ask the user once, before sending anything, whether to make that component the first variant of its set in place, which keeps its instances; on yes, runfigma codeagain with--convert <it>. Write no styling code yourself: every call is generated from the snap. Where it printsTranslucent paints bind to N alpha variables, the plan's first call, avariablescall, makes them: each a token's color at an alpha in Light and Dark, such asdestructive 10%, or at each theme's own where adark:class paints it at another,destructive 10% dark 20%, which keeps a translucent paint's alpha when a designer switches a frame's mode: Figma then gives each bound paint its variable's color and alpha in that mode, so a token bound at an opacity turns opaque. It finds and leaves unchanged those step 2 made, and lists nothing stale. It ends with anEstimate:line: the calls, the characters you'll send and read back, and the agent tokens to plan on for this push. Before sending the first call, show the user that line and ask whether to go ahead, and send nothing until they say yes; if they'd rather spend less, runfigma codeagain with fewer--componentsand push the rest in another session. - Send the calls in plan.json in
seqorder: for each, calluse_figmawithcodethe contents of itsfile(under.storysync/figma/), unchanged,descriptionitsdescription, the file key andskillNames: "figma-use", and save the response unchanged to itsresultpath before the next call. Never edit a call or a saved response. After a build call whose response listsuploads, callupload_assetswith the file key,countthe number of uploads,nodeIdstheir node ids in order andscaleMode: "FILL", save its response unchanged with.upload.jsonfor the result's.json, and runnpx storysync figma upload --plan .storysync/figma/plan.json --seq <the call's seq>, which posts the thumbnails. After each read call, sent for the first time or again, runnpx storysync figma next --plan .storysync/figma/plan.json --seq <its seq>, and while it prints a file, send that file the same way, save its response where it says, over any there, and run it again. If a call throws, deal with what the error says, as the skill's Components step 5 lists, and send the same call again, since every call can be sent again; forScript exceeded time limit, runfigma codeagain with--max-nodes 200and send the new plan from its first call; forThis call differs from the file storysync figma code wrote, orfigma next wrote, a character changed on the way and nothing was changed, so send the file again exactly as it is. A set a build refuses is left as it was, the rest of its call built, and itssetsentry isrefusedwith the question to ask. Never act on your own on the refusals and errors that say to ask the user: two sets of a name, another component's id, a set with auto layout, a set where a plain component goes or the reverse, a variant twice. ForThis call runs the … template that call NN stores in the Figma file, send call NN again, then this one; forVariant … is sent in N calls, send the calls it names first. Keep thevariablescall'salpha,created,updatedandunchanged, each build response'sfonts,unbound,fallbacks(no alpha variable …being a build sent before thevariablescall: send that call, then the build call again), and per setmigrated,renamed,converted,removed,notRemoved,designerLayers,extra,overlaps,movedandabsoluteContainers, and the last label response'spageOne, for the summary; whereoverlapsisn't 0, ask the user whether to move the set below the rest of its page. Whereextracounts variants an earlier push built that no property names now, as after a property was added or dropped, ask the user whether to remove them; for those they say yes to, runfigma codeagain with--remove-extra <names>, the components named comma-separated, never one they said to keep, and send the new plan; where a set's response hasnotRemoved, the plan went to another file than the one that counted its extras, which it names, and nothing was removed: tell the user. - Run
npx storysync verify --plan .storysync/figma/plan.json --strict-age, adding--skipwith the IDs of any component not pushed, which leaves them out of the score and names them under it, where otherwise each of their variants is missing from Figma. It assembles.storysync/figma-readback.jsonfrom the saved responses and scores Figma element by element: the headline is element fidelity, with the share of properties beside it, then each difference by component, variant, key and Figma node id. Don't fix drift by hand, and don't send a build again for drift it made itself, which a resend makes again: a font stand-in and the widths and positions it moves, a text a pixel or so wider, an icon's shapes, a truncation or a text the build'sfallbacksname, a border style Figma lacks. Report those as a font stand-in or a limit of the mapping. Only where something besides the build made Figma differ, a build response that failed or came back cut short, a layer edited in Figma since, or a build sent from an earlier plan, send that component's build calls once more, then its read calls, and run verify again, at most twice. A planned read call not read whole: send it, and whatfigma nextasks for after it, as its lines say. Translucent paintsBound without their alpha variable, which the score can't show: send the plan's first call, then those build calls and their read calls again. An entry whose checksum doesn't match, or that is incomplete or stale: send its read call again and save the response unchanged, never editing a result. A layer a designer added inside a variant fails--strict: ask the user whether it belongs there, and if it does, run verify again with--allow-designer-layers. A recorded snap failure that names a component's error means measure that component again (step 4, with--merge), and one that says components share a key, or that the snap recorded no components, means do what snap warned and run the whole snap again. - Summarize what was synced: token collections (count per category), with their modes and what step 2's calls created, updated and left unchanged, the alpha variables the plan's
variablescall made or found (alpha), and, where a collection holds the light theme alone though its tokens havedarkvalues, why, the tokens left out, the stale and conflicting variables with what the user chose for each, components grouped by page, whether the last label call removed Figma's default pagePage 1or why it kept it (itspageOne), variant counts, the components built as one plain component for having no variant properties, the fidelity score, worded asverifywords it: element fidelity, with the share of properties beside it, and where its line says entries wereunverified, not scored, how many entries it left unverified, which the score doesn't cover, the coverage it gives and what it couldn't score, the variants built as a placeholder with the story change each needs, any story that didn't pass its args through, any props snap found reach a component but change nothing it measures, and what the user chose for them, any variant snap markedargsChecked: false, each component'sargsNotInDocsandexcludedProps, each component measured from the story--storiesnamed, with the story, for an audit to measure from it too, each component snap measured as a closed trigger or a layout wrapper (with the fix the warning gives) and what the user chose for it, whatverifyprinted under the score about what snap measured, the frames built without auto layout, the layers of an earlier root-only push the build replaced (migrated), the designer layers and what the user chose for them, the values left unbound because several variables share them, every font stand-in the build responses returned infonts(a CSS keyword such assystem-uiset in Inter, a platform face such as Menlo in Roboto Mono), any component wherefontAvailablewasfalse(the measurement describes a substituted typeface, and Figma will need that font installed, which storysync cannot do), any buildfallbacks, which variant Figma will treat as a set's default where that is not the component's default, any set skipped for its auto layout, any component skipped for a set or plain component of its name an earlier push left, any set or component a build returnedoverlapsfor, and whether the user had it moved, any picture that couldn't be uploaded, thatverifycan't yet see variable bindings in an element-tree readback, and any failures or caps.
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.
- 23d ago Changed · +4 lines 38d72d464a0a
- 1mo ago Changed c0d78f2d4864
- 2mo ago First seen · 24 lines · 12 tokens per session scan A d8baab36f83c
storysync-push 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 5,900 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.
storysync-push compared with commands from other repositories
| Mod | Type | Stars | Last push | Licence | Scan | Tokens | Works with |
|---|---|---|---|---|---|---|---|
| storysync-pushbrendanciccone/storysync | Command | 75 | 8d ago | MIT | A | 12 | Claude Code |
| profilecathrynlavery/diagram-design | Command | 65k | 3d ago | MIT | A | 16 | Claude Code |
| erne-animateJubaKitiashvili/everything-react-native-expo | Command | 50 | 29d ago | MIT | A | 21 | Claude Code |
| ui-flow-reviewMRCalderon3D/everything-game-dev-code | Command | 104 | 28d ago | MIT | A | 15 | Claude Code |
| responsive-design-specialistimsaif/design-with-claude | Command | 11 | yesterday | MIT | A | 36 | Claude Code |
| design-auditw2ur/claude-code-setup | Command | 2 | 3d ago | MIT | A | 30 | Claude Code |
| ppt-image2-editable-rebuildwwe-dog/ppt-image2-editable-rebuild | Command | 204 | 5mo ago | Unlicense | A | 15 | Claude Code |