Octonode Playbook

Storybook (apps/studio) — GOAL MODE

Canonical Octonode repository documentation.

Storybook (apps/studio) — GOAL MODE

Every component has a story. No exceptions. If you create a component, you create its story in the same change. If you edit a component and it has no story yet, add one. A PR that adds or changes a Studio component without its *.stories.tsx is incomplete.

Setup lives in apps/studio/.storybook/ (main.ts globs src/**/*.stories.@(ts|tsx); preview.tsx wraps every story in the app's real providers — dark theme, React Query, TooltipProvider). Run it: yarn workspace @octonode/studio storybook (dev on :6006) or yarn workspace @octonode/studio build-storybook (static build → storybook-static/, which emits the index.json the storybook MCP reads).

Where the story lives. Next to its component, named after it — never in the barrel:

ComponentName/
  ComponentName.tsx
  ComponentName.types.ts
  ComponentName.stories.tsx   # ← required; do NOT export it from index.ts
  index.ts

The shape of a story (CSF3). Match the ui/ reference stories (apps/studio/src/components/ui/button.stories.tsx is the canonical example):

import type { Meta, StoryObj } from "@storybook/react-vite";
import { ComponentName } from "./ComponentName";

const meta = {
  title: "Studio/<FolderPath>/ComponentName",   // "UI/<Name>" for ui/ atoms
  component: ComponentName,
  tags: ["autodocs"],
  args: { /* realistic props built from ComponentName.types.ts */ },
} satisfies Meta<typeof ComponentName>;

export default meta;
type Story = StoryObj<typeof meta>;

export const Default: Story = {};
// one extra story per meaningful state the props support (variants, status, empty/loading)

Rules (do not violate):

  • preview.tsx already supplies the dark theme, QueryClientProvider, and TooltipProvider. Don't re-wrap stories in those — add a story-local decorators array only for context a component genuinely needs (e.g. <ReactFlowProvider> for any @xyflow/react node/edge, a sized container for canvas components).
  • Build args from the component's real .types.ts. Never invent prop names.
  • Cover the states that matter — variants for atoms, status (ok/running/error/skipped) for run/execution views, populated vs empty for lists. One story per state, kept minimal.
  • A page-level component that self-fetches via hooks renders empty without a running server; that's acceptable — note it with a // ponytail: comment rather than mocking the whole API.
  • Stories never import from a barrel's siblings by deep path and never modify the component.

Storybook MCP. .mcp.json (repo root) registers the storybook-mcp server pointed at http://localhost:6006/index.json. Start Storybook first (yarn workspace @octonode/studio storybook), then the MCP can list components, read story args/props, and screenshot stories.

Visual regression

GitHub Actions runs yarn test:visual in the pinned Linux Playwright container and compares stories whose transitive imports changed from the PR base commit (or the previous commit on pushes). Changes to the shared Storybook preview or build configuration select every story; releases run the full catalog. The check fails when any selected screenshot changes, a new story lacks a baseline, or a removed story leaves a stale baseline.

Normal CI treats this job as advisory and writes a hosted review link to the Actions job summary. Open that link, select intended changes, choose Use latest, and select Update selected baselines. Approval creates one baseline commit on the source branch; the triggered CI rerun is the authority that decides whether the new baselines pass. Release candidates keep the strict, full-catalog gate.

If the hosted service is unavailable, download and extract the visual-review artifact, then run VISUAL_REVIEW_DIR=/path/to/visual yarn test:visual:review. Select the intended changes, choose Use latest, and select Update selected baselines. Leave Keep baseline selected when the UI should be fixed instead. The artifact records Linux as its platform, so approval updates the canonical files under tests/visual/baselines/linux/ on macOS without running Storybook, Playwright, or Docker. Commit the locally approved baselines and push again. The review client is a React/Vite app in apps/visual-review.

For CI-equivalent debugging on Linux, yarn test:visual compares affected stories against main (VISUAL_BASE=<branch> overrides it), yarn test:visual:full runs the full catalog, and VISUAL_STORY="Studio/Flow/Node/Default" yarn test:visual checks one story. Screenshot comparison is skipped on other platforms so they cannot accidentally replace the Linux baselines.

Every checked story writes its current capture to test-results/visual/latest before comparison. Failures emit one-line VISUAL_MISMATCH, VISUAL_MISSING_BASELINE, VISUAL_RENDER_ERROR, or VISUAL_STALE_BASELINE JSON logs. Agents should use the named baseline/latest/diff files, changed-pixel count, percentage, and changedBounds coordinates to inspect and fix the exact affected region. Never approve a new baseline merely to make the gate green.

yarn test:visual:update replaces every Linux baseline and removes stale ones, so reserve it for an explicitly approved bulk redesign in the pinned container. CI uploads the self-contained visual-review artifact on every run.

On this page