Scaffolds, audits, and tests Storybook stories for React (web) and React Native / Expo (native) component libraries. Generates three artefacts in two files per invocation: a visual regression `*.stories.tsx` file holding a `Default` story (variants grouped into one snapshot) and a `Playground` story (interactive `args` / `argTypes`), plus a sibling `*.test.stories.tsx` interaction test under a `/Tests` namespace. Supports an opt-in, per-pathname auth flow whose credentials live in the OS keychain, never in the repo. The iteration loop drives the Playwright CLI against the running Storybook URL; visual evidence delegates to the `pr-reviewer` agent and the `screen-recorder` skill. An opt-in `--validate` phase drives Playwright adversarially against the rendered story, then fixes what it breaks behind a confidence gate. Triggers on "scaffold stories", "add storybook", "story for this component", "interaction test for this story", "validate this story", "/storybook".
72
90%
Does it follow best practices?
Run evals on this skill
Adds up to 20 points to the overall score
Passed
No findings from the security scan
Scaffold and test Storybook stories — three artefacts in two files
per component: a Default story and a Playground story (both in the
visual regression file) plus an interaction test file under a
/Tests namespace.
Works on React (web) and React Native / Expo (native).
Auth — when the running Storybook is gated — is opt-in and per-pathname,
with secrets stored in the OS keychain instead of the repo.
This
SKILL.mdis a thin index. Concern-specific rules live inrules/*.mdand load on demand. Reference material lives inreferences/*.md. Literal scaffolding lives intemplates/*.md. Do not preload every file — load only what the current phase asks for.
Reach for this skill when any of the following is true:
*.stories.tsx lacks an interaction test counterpart.Playground story is missing or out of sync with current props.Do not reach for this skill when:
tdd.Parse $ARGUMENTS in this order:
| Argument | Default | Effect |
|---|---|---|
<component-path> | Prompt the user | Source file of the component to scaffold stories for. |
--platform web|native | Auto-detect (see rules/react-native.md) | Web emits .stories.tsx; native emits the Expo / RN variant. |
--no-interactions | Generate <name>.test.stories.tsx | Skip the interaction test file. |
--no-playground | Include a Playground story | Skip the Playground story. |
--no-default | Include a Default story with grouped variants | Skip the visual regression Default story (rare — only for test-only). |
--validate | Off | Run the opt-in adversarial validate-and-fix phase (Phase 6) after the scaffold. Local only. |
--auth <profile> | None | Use the named auth profile when running Playwright against the URL. |
--title <storybook-title> | Inferred from the component path | Override the Storybook title for the generated meta. |
Sub-commands:
/storybook validate <component> # Run only the adversarial validate-and-fix phase against an existing story.
/storybook auth list # List configured auth profiles in this repo.
/storybook auth add <profile> # Register a new profile (writes config + stores secret in OS keychain).
/storybook auth remove <profile> # Remove a profile (deletes config entry + keychain item).
/storybook auth test <profile> # Dry-run the login flow against the configured URL./storybook validate <component> skips scaffolding: it reads the
existing .stories.tsx / .test.stories.tsx and runs Phase 6 directly.
The full loop — probe catalog, triage, confidence-gated fixes — lives in
rules/adversarial-validation.md.
The full auth contract — config schema, keychain commands per OS, and
the storageState reuse loop — lives in rules/auth.md.
Each phase has a single gate. Do not proceed until it passes. Phase 6
runs only when --validate is passed or the skill is invoked as
/storybook validate <component>.
| Phase | Name | Gate |
|---|---|---|
| 0 | Preflight | Storybook installed; platform detected; auth profile loaded if asked |
| 1 | Component inspection | Component file read; props and variants enumerated |
| 2 | Visual regression scaffold | <name>.stories.tsx written; variants grouped |
| 3 | Playground scaffold | Playground story written with args + argTypes |
| 4 | Interaction test scaffold | <name>.test.stories.tsx written under /Tests namespace |
| 5 | Verification | Storybook running; Playwright CLI iteration confirms rendering |
| 6 | Adversarial validation | (opt-in) Probes pass or defects fixed and pinned by a regression test |
Run these read-only checks before writing anything:
# 1. Storybook installed?
jq '.devDependencies | keys[]' package.json | grep -E '@storybook/'
# 2. Storybook config dir present?
ls .storybook/ 2>/dev/null
# 3. Platform — web (Vite / Next) or native (Expo / RN)? Check
# dependencies, devDependencies, AND peerDependencies — shared
# component libraries (`packages/ui`) consumed by an Expo app
# declare `react-native` as a peer.
jq '(.dependencies // {}) + (.devDependencies // {}) + (.peerDependencies // {}) | keys[]' package.json | grep -E '^(react-native|expo|@storybook/react-native)'Decision table:
| State | Action |
|---|---|
Storybook installed + .storybook/ present | Proceed to Phase 1. |
| Storybook missing | Halt. Ask user to install Storybook before invoking this skill again. |
react-native or expo in dependencies | Set --platform native. Load rules/react-native.md. |
| Neither present | Set --platform web. |
--auth <profile> passed | Load rules/auth.md. Resolve secret before Phase 5. |
Read the component file. Enumerate, in this order:
isLoading, error,
disabled, variant, size).onClick, onChange, onSubmit, …).decorators.Output the inventory inline before scaffolding. The user reads it and corrects misinterpretations before any file is written.
Write <kebab-case-name>.stories.tsx next to the component file.
Full rules and the variant-grouping pattern live in
rules/create-stories.md.
The shape, in one diagram:
default export (Meta)
└── title: "<Inferred>/<ComponentName>"
└── component: <Component>
└── parameters: { layout: "padded" | "centered" | "fullscreen" }
export const Default: Story = {
render: () => (
<variants grouped — one Chromatic snapshot per file>
),
};Use the literal scaffolding in:
templates/component.stories.tsx
(web)templates/component.native.stories.tsx
(React Native / Expo)If the repo already exports a Stories / Stories.Entry helper
(checked by Grep "Stories\\.Entry" against the repo), use it to group
variants into a single snapshot.
Otherwise emit a plain flex/stack wrapper.
The decision tree is in
rules/create-stories.md.
Append a Playground story to the same file.
Every prop becomes an argTypes control.
Mapping:
| TypeScript prop | argTypes control |
|---|---|
boolean | { control: "boolean" } |
string | { control: "text" } |
number with inferable min/max | { control: { type: "range", min: <n>, max: <n>, step: <n> } } |
number without explicit clamps | { control: "number" } |
| Union of string literals | { control: "select", options: [...] } |
Callback (onClick, onChange) | args: { onClick: fn() } — imported from storybook/test |
ReactNode / children | { control: "text" } with a default string |
Full example: see "Playground story" in
rules/create-stories.md.
Write <kebab-case-name>.test.stories.tsx next to the component file.
Hard rules (full reasoning in
rules/interaction-tests.md):
.test.stories.tsx.
Do not use .interactions.stories.tsx, .spec.stories.tsx, or
anything else.<same-prefix>/Tests.
One Storybook namespace per file — CSF3 allows exactly one default
export.tags: ["test"] is set on the meta so the test runner picks it up.parameters.chromatic = { disableSnapshot: true } keeps these stories
out of visual regression.userEvent calls are awaited; all expect calls are awaited.getByRole → getByLabelText →
getByPlaceholderText → getByText → getByTestId.
Never start with getByTestId.Use the literal scaffolding in:
templates/component.test.stories.tsx
(web)templates/component.native.test.stories.tsx
(React Native / Expo — uses @storybook/react-native test helpers)Start Storybook in the background and iterate against the live URL.
Full Playwright CLI loop in
rules/playwright-cli.md.
Minimum verification, in this order:
npm run test-storybook) — if the runner is wired up.For visual evidence (a screenshot or short clip of the rendered story),
delegate to the pr-reviewer agent or the
screen-recorder skill.
Full handoff rules in
rules/visual-verification.md.
If the Storybook URL is gated and --auth <profile> was passed, the
Playwright CLI invocation reuses the storageState.json produced by
the auth profile's login flow.
The skill never types credentials into the Playwright CLI directly.
--validate)Runs only when --validate is passed, or standalone via
/storybook validate <component>. It is local and interactive — it
drives Playwright against the running Storybook, so it never runs in CI.
Phase 5 proves the story renders. Phase 6 proves the component works, then tries to break it: hostile inputs, rapid and duplicate events, keyboard-only navigation, viewport extremes, and error states. Each defect is triaged as a story bug or a component bug, fixed behind a confidence gate, and pinned with a regression test.
The loop, in one line: probe → triage → fix (gated) → pin with a regression test → re-validate.
.agent/storybook/.probe/ (gitignored)
so they can capture console errors, page errors, and failed requests —
the signals a bare screenshot misses.confidence, apply only at
≥ 90, and report sub-90 findings for the user to decide. Every
applied fix is pinned by a regression case in .test.stories.tsx..skip a test to force
a green run.Full probe catalog, the harness pattern, triage rules, and the loop cap
live in
rules/adversarial-validation.md.
| Signal | Do |
|---|---|
Component has no .stories.tsx | Run the full workflow (Phases 0–5). |
Component has .stories.tsx but no .test.stories.tsx | Skip to Phase 4. Reuse the existing meta title for the /Tests peer. |
--validate passed, or /storybook validate <component> | Run Phase 6. Load rules/adversarial-validation.md. Local only. |
| Running in CI | Skip Phase 6 — it drives a live browser and is not reproducible. |
Repo has react-native or expo | Set --platform native. Load rules/react-native.md. |
Storybook URL is http://localhost:6006/... (or similar) | Iterate via Playwright CLI. No auth needed. |
| Storybook URL is gated (login form, SSO, basic auth) | Resolve --auth <profile> first. Load rules/auth.md. |
| Visual evidence requested in the PR | Delegate to pr-reviewer or screen-recorder. |
| Component is a hook or non-visual | Stop. Defer to tdd. |
| Storybook isn't installed | Halt. Ask the user to install Storybook before re-running. |
tdd — owns unit / hook tests.
This skill defers below the visual surface to it.test-provenance-guard —
run on the generated .test.stories.tsx to ensure the test imports
production component code, not a private shim.pr-reviewer — runs the visual check pass
and posts screenshots on the PR (Critical / High motion findings,
visual diffs).screen-recorder — captures short
videos of multi-frame interactions where a still screenshot cannot
prove the change (transitions, focus order, hover-revealed UI).ux — call after stories are scaffolded to audit
the rendered states for accessibility and microcopy.visual-design — call before
scaffolding when the component is new and the visual direction is
not yet committed (palette, type, signature details). Call after
scaffolding in review mode if the rendered variants look generic
or drift from the chosen direction. Pairs with ux — ux audits
the floor, visual-design shapes the ceiling.confidence — gate before declaring the
scaffold done if the user disputes a generated variant.rules/create-stories.md — visual
regression *.stories.tsx pattern: grouped variants, Playground
story, layout parameter, static mock data only.rules/interaction-tests.md —
*.test.stories.tsx hard requirements: /Tests namespace, awaited
userEvent, locator ladder, fn() spies, step() grouping.rules/react-native.md — Expo / React
Native flavor: @storybook/react-native differences, native
locators, mobile-only template paths.rules/auth.md — opt-in per-pathname auth: config
schema, OS-keychain commands, storageState reuse, multi-profile
routing, secret rotation.rules/playwright-cli.md — iteration
loop against the running Storybook URL: snapshot mode, --last-failed,
iframe routes, story permalinks, headed vs headless.rules/adversarial-validation.md
— opt-in Phase 6 (--validate): the probe harness, the adversarial
catalog, story-vs-component triage, the confidence-gated fix path, and
the loop cap.rules/visual-verification.md —
delegation rules for the pr-reviewer agent and screen-recorder
skill, when each is the right tool.rules/anti-patterns.md — full list of
patterns to refuse.references/platform-detection.md
— how the skill decides web vs native, and the Storybook builder
matrix per framework.references/flake-cookbook.md —
copy-paste decorator snippets for the five most common flake
sources (animations, fonts, dates, random IDs, theme drift).
Load only when an existing story has flaked or the user asks for
deterministic snapshots — adding all five preemptively is
cargo-culting.templates/component.stories.tsx
— web visual regression scaffold.templates/component.test.stories.tsx
— web interaction test scaffold.templates/component.native.stories.tsx
— React Native / Expo visual regression scaffold.templates/component.native.test.stories.tsx
— React Native / Expo interaction test scaffold.templates/auth.config.example.json
— auth-profile config schema with two example profiles.rules/anti-patterns.md)*.interactions.stories.tsx or
*.spec.stories.tsx instead of *.test.stories.tsx.new Date(), Math.random()) in story args —
guarantees Chromatic / Loki false positives.getByTestId..env, package.json, or the
story file itself.Playground story whose argTypes do not match the
component's actual prop types.--validate in CI — it drives a live browser and is not
reproducible.--validate, forcing a green run by swallowing the error,
deleting a probe, or .skip-ing a test, or editing component source
below a confidence of 90.--auth was given.<name>.stories.tsx written with a Default story (grouped
variants) and a Playground story (unless --no-playground).<name>.test.stories.tsx written under the /Tests namespace
(unless --no-interactions).--auth <profile> was used, storageState.json is written
under .agent/storybook/.auth/ and listed in .gitignore.--validate was used: applicable probes ran; findings triaged
as story or component; component fixes applied only at confidence
≥ 90 and pinned by a regression test; sub-90 findings reported; the
ephemeral probe script deleted and Storybook killed on exit.39b3f44
If you maintain this skill, you can claim it as your own. Once claimed, you can manage eval scenarios, bundle related skills, attach documentation or rules, and ensure cross-agent compatibility.