$npx -y skills add strongeron/storybook-workbench --skill sb-shipGraduate ONE Explore experiment to a production component — preserve the experiment (cp, never git mv), pick new-vs-update, close the decision loop. Use for 'ship this', 'promote this experiment', 'graduate to production'.
| 1 | # sb-ship — graduate, preserving history |
| 2 | |
| 3 | Event-triggered when an Explore iteration meets the graduation gate. **The one rule that matters: |
| 4 | preserve the experiment — `cp`, never `git mv`.** The Explore story stays as design history; |
| 5 | `git mv` here is the destructive bug `propagate-workflow.md` exists to prevent. **Load |
| 6 | `references/propagate-workflow.md` before any Ship action** — it's the *only* reference |
| 7 | this skill needs; **Do NOT load** the sb-wrappers/sb-audit refs (lifecycle, galleries, composition) for |
| 8 | a Ship. |
| 9 | |
| 10 | ## Decide the path (ask yourself) |
| 11 | |
| 12 | - **Did the Explore define its own component file, or iterate on an existing one?** → Path A vs Path B. |
| 13 | - **Path B: evolve in place (B1) or keep V1 in `_legacy/` (B2)?** B2 only when V1 still has live |
| 14 | callsites needing a migration window. |
| 15 | - **Did the import path change?** If yes → `ast-grep` callsites. If not → skip it. |
| 16 | - **Other tagged stories that should flip?** (a Compare `decision:pending` → `decision:chosen` + winner.) |
| 17 | |
| 18 | ## Execute |
| 19 | |
| 20 | - **Path A — NEW component.** `cp` the component explore→components, write a *fresh* production |
| 21 | stories file **to the recorded `storiesLocation`** (`.storybook/audit/status.md`; the rule lives in |
| 22 | `CONTEXT.md` §STORIES LOCATION — never scatter) — don't `cp` the Explore stories (production has |
| 23 | different concerns: autodocs, no decision metadata), validate, then `ast-grep` callsites only if a path changed. |
| 24 | - **Path B — UPDATE existing.** Apply the Explore's diffs into the production component + stories |
| 25 | in place; `ast-grep` only if the import path changed. |
| 26 | - **Both — close the loop IN PLACE** (no `git mv`): |
| 27 | `tags: ['explore','decision:chosen','archived','!autodocs','!test']` + |
| 28 | `parameters.decision = { status, winner, date, shippedTo }`. Confirm with |
| 29 | `find-stories-by-tag.sh decision:chosen`. |
| 30 | |
| 31 | ## Gate + next |
| 32 | |
| 33 | Run the bundled `scripts/validate-stories.sh` on the new production story (in the bundle: |
| 34 | `${CLAUDE_PLUGIN_ROOT}/scripts/validate-stories.sh`, or |
| 35 | `${CLAUDE_PLUGIN_ROOT}/scripts/`). Confirm the flip with `scripts/find-stories-by-tag.sh |
| 36 | decision:chosen`. Append the decision to the ledger (`templates/design-decisions.md`); the graduated experiment stays put. |
| 37 | |
| 38 | **Re-enter the usage flow.** A graduated component is new to `src/` — it isn't in the rendered JSONs |
| 39 | yet, so its Docs "Real usage" band and `storyCoverage` are blank. Trigger the one-command usage refresh |
| 40 | (`refresh-usage.sh`, owned by `sb-audit`/`sb-inventory`) so the new component enters `component-usage.json` |
| 41 | / `project-inventory.json`; a Storybook rebuild then shows its real usage. Then `/sb-hub`. |