agentsclimarketplace

Sb hub

Skill strongeron/storybook-workbench/skills/sb-hub

AI agent skill bundle for Storybook on React + Vite — audit real-vs-slop components, capture flows, write CSF3 stories, ship. Claude Code / Codex / Cursor.

Install
npx -y skills add strongeron/storybook-workbench --skill sb-hub

Assembled from the repository path, not quoted from the project. Check it against their README if it does not work.

One thing to look at

  • 18 stars18 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.

What its author says it does

Copied from the file, not written here

Hub for the Storybook CSF3 bundle — diagnose a repo, orchestrate the audit→stories pipeline, or name the next sb-* step. Use for 'set up Storybook', 'audit my app', 'where do I start', 'what's next'.

The file declares its own license as MIT. That is the author’s claim about this one file, and it is not the same thing as the license GitHub reports for the repository, which is listed with the other numbers below.

SKILL.md

16.5 KB, as published. Nobody here has run it

sb-hub — onboarding check · orchestrator · navigator

The hub. You don't author here — you inspect state and route. Three read-only modes; pick by intent. Read CONTEXT.md once for shared vocabulary, the storage map, and the resume protocol.

Load by mode (don't pull both refs up front):

  • references/runbook.md — the navigator engine (state detection → one next step). Load it for Mode 0 / Mode 2 (diagnose / "what's next").
  • references/end-to-end-flow.md (~220 lines) — the full pipeline worked example for "messy app → design system". Load it only for Mode 1 (orchestrate a full audit). Do NOT load it for a Mode-0 onboarding check or a Mode-2 next-step lookup — runbook.md is all those need.

Canonical context (one source). The bundle has exactly one CONTEXT.md (shared vocab · STORAGE MAP · resume). It's never hand-duplicated: in the bundle/plugin install every skill reads this one file (CONTEXT.md / ${CLAUDE_PLUGIN_ROOT}/CONTEXT.md); a standalone npx skills add <skill> ships a byte-identical copy the build vendors, refreshed on update. sb-hub is the orchestrator — if skills are installed separately, route through sb-hub so the pipeline + shared vocabulary stay authoritative.

Resolve the bundle

Scripts live in scripts/. In this repo: ${CLAUDE_PLUGIN_ROOT}/scripts/. When installed as a plugin, use ${CLAUDE_PLUGIN_ROOT}/scripts/.

CORE=${CLAUDE_PLUGIN_ROOT:-${CLAUDE_PLUGIN_ROOT}}   # shared scripts: "$CORE/scripts/<name>"

Pick the mode

User intentMode
"is this ready", "where do I start", fresh/unknown repo0 · Onboarding check
"audit this app", "do the whole thing", "build Storybook for this app"1 · Orchestrate
"what's next", or after any verb appends to the ledger2 · Navigate (default)
"this is wrong", "strange behavior", "report a bug", a skill misfired3 · Report

Mode 0 — Onboarding check (phase-0 diagnose, read-only)

A fresh messy app: probe the stack + readiness before any verb, print a report, recommend the first step. No prompts, no writes — re-runnable.

echo "━━ Phase 0 — readiness ━━"
grep -q '"react"' package.json 2>/dev/null && echo "  [ok]   React" || echo "  [warn] no React in package.json"
grep -qE '"vite"|"@vitejs' package.json 2>/dev/null && echo "  [ok]   Vite" || echo "  [info] not Vite (skill targets React+Vite)"
test -d .storybook && grep -q '"storybook"' package.json 2>/dev/null && echo "  [ok]   Storybook present" || echo "  [warn] NO_STORYBOOK → start with sb-setup"
test -d node_modules && echo "  [ok]   node_modules present" || echo "  [warn] deps not installed — run your package-manager install"
lock=$(ls package-lock.json pnpm-lock.yaml yarn.lock 2>/dev/null | head -1); echo "  [info] lockfile: ${lock:-none}"
grep -q '@storybook/addon-mcp' package.json 2>/dev/null && test -f .mcp.json && echo "  [info] MCP wired → sb-stories uses with-mcp" || echo "  [info] no addon-mcp → without-mcp path"
if find .storybook -maxdepth 1 -name '*.json' 2>/dev/null | grep -q .; then
  find .storybook -maxdepth 1 -name '*.json' | sed 's/^/  [ok]   discovery: /'
else echo "  [info] no discovery JSON yet → sb-inventory not run"; fi
grep -q 'storiesLocation:' .storybook/audit/status.md 2>/dev/null && echo "  [ok]   stories location decided" || echo "  [warn] stories location undecided → sb-setup must ASK (isolated .storybook/stories/ vs co-located) before sb-stories"

Worked example — a half-migrated app (Storybook installed, nothing audited yet):

━━ Phase 0 — readiness ━━
  [ok]   React
  [ok]   Vite
  [ok]   Storybook present
  [ok]   node_modules present
  [info] lockfile: pnpm-lock.yaml
  [info] no addon-mcp → without-mcp path
  [info] no discovery JSON yet → sb-inventory not run
  [warn] stories location undecided → sb-setup must ASK …

→ Storybook exists but no discovery JSON and location undecided, so don't jump to sb-stories. Name sb-setup first (to record the stories location), then sb-inventory. That ordering — setup before inventory before stories — is the whole point of the gate: the [info]/[warn] lines are the routing signal, not noise.

Everything the bundle writes lives under .storybook/ (CONTEXT.md STORAGE MAP) — flag if you ever see outputs elsewhere. The one decision is where stories go; if undecided, name sb-setup (it asks).

Discovery is precomputed. The discovery layers are JSON under .storybook/: project-inventory (+ tokens.map, storyCoverage) · component-usage · flows · design-system-health · component-states · prop-shapes · page-patterns · runtime. The first four are rendered in Storybook (autodocs embeds + wrappers) and refreshed together by refresh-usage.sh; the rest are authoring inputs (regenerated on demand). Never re-derive by shell scan what a script already wrote to .storybook/*.json — Read the field.

Then print → Start: <first verb>sb-setup if NO_STORYBOOK, else sb-inventory. Don't run the verb; name it and stop. For the full new-project arc, hand to Mode 1.

Mode 1 — Orchestrate (run the whole audit → stories)

"Audit this app end to end." Run the pipeline in order, gating between phases — never advance until the prior artifact exists (the discovery scripts write atomically, so an existing JSON is complete). You don't run sibling scripts directly; you invoke each focused skill and verify its output.

  1. sb-setup — if Mode 0 reported NO_STORYBOOK, or stories location is undecided. GATE: .storybook/ + "storybook" in package.json, AND storiesLocation recorded in .storybook/audit/status.md (sb-setup asks the user — isolated .storybook/stories/ vs co-located), AND .storybook/runtime.json exists (discover-runtime.py — provider tree / root-CSS / portals / MSW the shared preview must supply), before step 2.
  2. sb-inventory — real-vs-slop + dominant design system. GATE: .storybook/project-inventory.json exists.
  3. sb-health — design-system health. GATE: .storybook/design-system-health.json exists; if designSystem.mixed / heavy raw-hex, surface the /ds-runbook handoff before authoring.
  4. sb-flows — route map + nav edges. GATE: .storybook/flows.json exists.
  5. sb-stories <Component> — author a story for each component that needs one: work down components.storyCoverage.needsStory[] (own components without a story, top-imported first), each self-gating with validate-stories.sh. The honest progress meter is storyCoverage.withRegisteredStory/ needsCount when storyCoverage.source == "storybook-index" (reconciled against Storybook's index.json — the stories Storybook actually registers); otherwise withColocatedStory/needsCount (heuristic; withStory is a loose upper bound — it also counts components a story merely imports to mock). Re-run sb-inventory (or sb-audit) after authoring to refresh coverage from the index and shrink needsStory[] — iterate until empty.
  6. sb-wrappers — render each step's output as a view: ProjectInventory (after step 2), DesignSystemHealth/TokenMatrix (after step 3's health), AppFlowGraph/JourneyGraph (after step 4), and StateGrid/StateMatrix while authoring stories (step 5). The data wrappers need their step's JSON first — see sb-wrappers "When in the flow".
  7. sb-audit — periodic drift survey + decision board once stories land; runs refresh-usage.sh (below).

Figma-originated design system (optional branch, after step 1). The pipeline above is code-first (audit what exists). When the source of truth is an approved Figma file, insert sb-figma to establish foundation-token parity before authoring: it captures the Figma MCP variables to .storybook/figma/, writes .storybook/figma-token-parity.json (color/spacing/type, OKLCH→hex), wires the Foundations/Colors|Tokens|Type stories' figmaVar/figmaHex, and reports drift. It feeds — doesn't replace — sb-health (step 3): health checks the code-internal token set; sb-figma adds the design↔code axis health can't see. (Delivering approved components from Figma is also sb-figma, authored via sb-stories; iterating undecided designs stays sb-explore.)

Append a one-line finding to .storybook/audit/findings.md after each phase. Stop on the first GATE that fails and tell the user which verb to fix. (Pattern: ordered pipeline with hard gates, like lfg.)

Keep rendered data fresh (the usage layer). The four rendered JSONs (inventory · component-usage · flows · design-system-health) feed the autodocs usage embedUsageSection wired once into preview.ts docs.page adds "Real usage in this app" to every component's Docs and each Foundation (Colors/Semantic/Typography/Scales = token tables, Health = audit findings). refresh-usage.sh --docs re-runs all four together so a rebuild reflects reality; sb-audit does this each pass, and it belongs in CI before storybook build. (Setup wires the docs.page composition — see sb-setup install-wizard.)

Mode 2 — Navigate (default — name the single next step)

Inspect state + ledger, recommend exactly one next surgical skill (whose prerequisites are met).

test -d .storybook && grep -q '"storybook"' package.json 2>/dev/null && echo STORYBOOK_PRESENT || echo NO_STORYBOOK
ls .storybook/*.json 2>/dev/null            # which discovery JSONs exist
cat .storybook/audit/status.md 2>/dev/null  # ledger / resume point
# DRIFT — source/story files changed since the last discovery (newer than the inventory JSON). Plain
# `find -newer` → cross-agent (no git, no Claude hook), works on uncommitted/untracked files. Lists the
# exact files that moved this session; if any, the discovery JSONs are stale → refresh before routing.
if [ -f .storybook/project-inventory.json ]; then
  find src app components .storybook/stories \( -name '*.tsx' -o -name '*.ts' \) \
    -newer .storybook/project-inventory.json 2>/dev/null | grep -v '\.storybook/.*\.json' | head -20
fi
# COVERAGE — READ the field the script already wrote (CONTEXT.md doctrine: never re-derive). Extract
# ONLY storyCoverage so the FULL object surfaces complete — never a truncated dump of the whole
# inventory. Prefer the authoritative `withRegisteredStory` (source=storybook-index, reconciled against
# index.json); fall back to the heuristic `withColocatedStory`. needsStory[] is the iterate list.
if [ -f .storybook/project-inventory.json ]; then
  python3 - <<'PY'
import json
try: c = json.load(open(".storybook/project-inventory.json"))["components"]["storyCoverage"]
except Exception: raise SystemExit
src = c.get("source", "heuristic")
done = c.get("withRegisteredStory") if src == "storybook-index" else c.get("withColocatedStory", 0)
print(f"coverage: {done}/{c.get('real',0)} components have a story [{src}] · {c.get('needsCount',0)} need one")
if c.get("needsStory"):
    extra = " …" if c.get("needsCount", 0) > 8 else ""
    print("iterate next (sb-stories): " + ", ".join(c["needsStory"][:8]) + extra)
PY
fi

If DRIFT lists files, the discovery JSONs no longer match the code — route to sb-inventory (or sb-audit for a periodic pass) to refresh before naming the next step: its refresh-usage.sh re-runs inventory/usage/flows AND reconciles story coverage against Storybook's own index.json (authoritative, not a basename guess). Then route — name exactly one:

StateNext stepSkill
NO_STORYBOOKdefer bootstrap to npx storybook ai setup, then alignsb-setup
No project-inventory.jsondiscover real-vs-slop firstsb-inventory
Inventory done, no design-system-health.jsoncheck health before authoringsb-health
Health done, no flows.jsoncapture navigation + app-mapsb-flows
Inventory clean, want storiesauthor ONE componentsb-stories <Component>
New/redesigned component, undecided — iterating optionssandboxed iteration (+ Figma node)sb-explore
Approved Figma design — map foundation tokens (color/spacing/type) or deliver an approved componentFigma → production Storybooksb-figma
Check Figma↔code token parity / "is the design system in sync with Figma"parity + drift reportsb-figma
Connect components back to Figma (Code Connect) / "show my code in Figma Dev Mode"code → design (reverse)sb-figma
Periodic checkdrift survey + decision boardsb-audit
Explore meets graduation gatepropagate to productionsb-ship

EXPLORE vs DELIVER (both are Figma-aware — route by stage, not by "uses Figma"): undecided / trying optionssb-explore (Lab) → sb-ship (graduate). Already approved in Figmasb-figma (deliver direct to prod). sb-figma writes the Foundation token stories itself; for an approved component it extracts the design then authors via sb-stories' rules. It captures every Figma MCP output to .storybook/figma/ (manifest + per-tool files) so the pipeline is reproducible/iterable, not MCP-bound.

Resume rule (CONTEXT.md): read status.md + check which JSONs exist; resume from the first incomplete step. Never treat a file half-written in a prior session as complete — re-run that step.

Mode 3 — Report (a skill misfired / strange behavior)

When the user says a skill did something wrong, surprising, or broken, help them file a useful report — don't just apologize. Draft it with the agent-native reporter, then hand them the submit command.

CORE=${CLAUDE_PLUGIN_ROOT:-${CLAUDE_PLUGIN_ROOT}}
"$CORE/scripts/report-issue.sh" --asked "<what they asked>" --observed "<what happened>" --expected "<what they wanted>"

It writes a sanitized draft (versions + .storybook/*.json shapes/counts only — never source, token values, or component names) and prints a gh issue create … command + a blank-issue URL. It makes no network call — the user submits. Fill --asked/--observed/--expected from the conversation, show them the draft path + the gh line, and (only if they ask) offer to run gh for them. To target a different repo: SB_ISSUE_REPO=owner/name. A good report becomes a reproduction → a new eval case → a fix → a field-learnings.md entry — the loop that keeps the next run from re-hitting the same bug.

Never (orchestration failure modes, and why)

  • NEVER advance past a failed/empty gate in Mode 1 — each phase's .storybook/*.json is the precondition for the next (foundation tokens before components, flows before the app map). Skip one and every later phase builds on missing ground truth and silently under-delivers.
  • NEVER re-derive CONTEXT by shell-scanning what a script already wrote — the .storybook/*.json files ARE the state. Hand-grepping drifts from what the scripts captured and what the wrappers render; cite the field, don't recompute it.
  • NEVER treat a half-written prior-session artifact as complete — writes are atomic per file, but an interrupted run may have stopped mid-pipeline. Check status.md and re-run the first incomplete step.
  • NEVER author here — the hub inspects and routes. Writing a story/wrapper from the hub bypasses the focused skill's own checks and anti-patterns; invoke the skill instead.
  • NEVER hand-duplicate CONTEXT.md — every skill reads the one canonical file (CONTEXT.md); a copy is drift waiting to happen.

Cross-agent

  • Claude: this skill is /sb-hub (Mode 2 / "what's next" is the default; /sb-hub onboard or /sb-hub audit this app selects Mode 0 / 1).
  • Codex: $sb-hub what's next · $sb-hub onboard · $sb-hub audit this app.
  • The loop: a verb runs → appends to .storybook/audit/findings.md → ask sb-hub again (Mode 2) → it names the next surgical skill → run it.

Keep looking

Skills are one crate of 328,083. Ordering is by how many stacks a row turns up in, so the top of any crate is what has actually been picked rather than what has the most stars.