# Sb Ship

> Graduate 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'.

- Skill: `strongeron/sb-ship` (Agent Skill, multi-file: 7 files)
- Install (CLI): `npx skillmds@latest add strongeron/sb-ship`
- Raw SKILL.md: https://api.skillmd.com/api/skills/strongeron/sb-ship/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Web & Frontend
- License: MIT
- Author: strongeron (https://skillmd.com/u/strongeron)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/strongeron/sb-ship

---


# sb-ship — graduate, preserving history

Event-triggered when an Explore iteration meets the graduation gate. **The one rule that matters:
preserve the experiment — `cp`, never `git mv`.** The Explore story stays as design history;
`git mv` here is the destructive bug `propagate-workflow.md` exists to prevent. **Load
`references/propagate-workflow.md` before any Ship action** — it's the *only* reference
this skill needs; **Do NOT load** the sb-wrappers/sb-audit refs (lifecycle, galleries, composition) for
a Ship.

## Decide the path (ask yourself)

- **Did the Explore define its own component file, or iterate on an existing one?** → Path A vs Path B.
- **Path B: evolve in place (B1) or keep V1 in `_legacy/` (B2)?** B2 only when V1 still has live
  callsites needing a migration window.
- **Did the import path change?** If yes → `ast-grep` callsites. If not → skip it.
- **Other tagged stories that should flip?** (a Compare `decision:pending` → `decision:chosen` + winner.)

## Execute

- **Path A — NEW component.** `cp` the component explore→components, write a *fresh* production
  stories file **to the recorded `storiesLocation`** (`.storybook/audit/status.md`; the rule lives in
  `CONTEXT.md` §STORIES LOCATION — never scatter) — don't `cp` the Explore stories (production has
  different concerns: autodocs, no decision metadata), validate, then `ast-grep` callsites only if a path changed.
- **Path B — UPDATE existing.** Apply the Explore's diffs into the production component + stories
  in place; `ast-grep` only if the import path changed.
- **Both — close the loop IN PLACE** (no `git mv`):
  `tags: ['explore','decision:chosen','archived','!autodocs','!test']` +
  `parameters.decision = { status, winner, date, shippedTo }`. Confirm with
  `find-stories-by-tag.sh decision:chosen`.

## Gate + next

Run the bundled `scripts/validate-stories.sh` on the new production story (in the bundle:
`${CLAUDE_PLUGIN_ROOT}/scripts/validate-stories.sh`, or
`${CLAUDE_PLUGIN_ROOT}/scripts/`). Confirm the flip with `scripts/find-stories-by-tag.sh
decision:chosen`. Append the decision to the ledger (`templates/design-decisions.md`); the graduated experiment stays put.

**Re-enter the usage flow.** A graduated component is new to `src/` — it isn't in the rendered JSONs
yet, so its Docs "Real usage" band and `storyCoverage` are blank. Trigger the one-command usage refresh
(`refresh-usage.sh`, owned by `sb-audit`/`sb-inventory`) so the new component enters `component-usage.json`
/ `project-inventory.json`; a Storybook rebuild then shows its real usage. Then `/sb-hub`.

