Commands
Every command a person runs in this repo, by area, with what it does and the page that explains it.
Every command a person runs in this repo, by area. Run them from the repo root
unless the command says otherwise; pnpm --filter <package> <script> runs one
package's script, and arguments for the script go after --. Each row links to
the page that explains when and why. Scripts that only CI runs (scripts/ci/*,
the prepare and prebuild hooks) are left out, apart from the two worth
running locally.
Setup and dev
| Command | What it does | Explained in |
|---|---|---|
pnpm install |
Installs the workspace; the prepare hook points git at scripts/hooks, so the pre-commit hook is on from the first install |
Installation |
pnpm dev |
Runs every package's dev task through Turbo — the web app on :3000 | Installation |
pnpm --filter @v4/web dev |
The web app alone, on :3000 | Installation |
pnpm --filter @v4/web build then pnpm --filter @v4/web start |
A production build of the web app and a server for it (the build sets a 12 GB heap) | Deployment |
pnpm --filter @v4/storybook dev |
Storybook on :6006 (stages the Figma reference images first) | Testing |
pnpm --filter @v4/docs dev |
This docs site on :4400, with the docs chat | Docs assistants |
pnpm --filter @v4/cortex-sso stage-test |
A standalone app for trying a real sign-in against Cortex's stage platform | @v4/cortex-sso |
Build, lint, test
| Command | What it does | Explained in |
|---|---|---|
pnpm build |
Turbo-cached build of every package and app | Monorepo and packages |
pnpm lint |
ESLint everywhere, zero warnings allowed | Pull requests and gates |
pnpm check-types |
TypeScript in every package | Pull requests and gates |
pnpm test |
Every package's unit suite, the story suite and the e2e, through Turbo | Testing |
pnpm --filter <package> test |
One package's unit suite (test:watch where the package has it) |
Testing |
pnpm format / pnpm format:check |
Prettier: write, or check only | Pull requests and gates |
pnpm verify |
The cheap CI gates in one run: Prettier, lint, types, unit suites, the bridge check, composition drift and app codegen drift | Pull requests and gates |
pnpm --filter @v4/storybook test |
The story suite: every story rendered in a browser, with its play function and accessibility check | Testing |
pnpm --filter @v4/e2e test |
The Playwright e2e on every project; boots Storybook on :6006 or reuses a running one | Testing |
pnpm --filter @v4/e2e test:chromium / test:cross-browser / test:full-matrix / test:ui |
The Chromium projects only; WebKit and Firefox only; every spec on every project; Playwright's UI | Testing |
E2E_PORT=6016 pnpm --filter @v4/e2e test -- <spec> |
The e2e against a Storybook on another port, when :6006 belongs to another checkout | Troubleshooting |
node scripts/hooks/docs-drift.mjs --range=origin/develop..HEAD |
The docs-drift check CI runs: asks whether the docs mapped to the changed paths still hold (needs ANTHROPIC_API_KEY) |
Pull requests and gates |
Components and Storybook
| Command | What it does | Explained in |
|---|---|---|
pnpm --filter @v4/ghost-core new-component <kebab-name> |
Scaffolds a ghost-core component's files and registrations | Create a component |
pnpm --filter @v4/ghost-content check-dist (and ghost-video, ghost-basketball) |
Checks a sibling package's build output and that its OWN_THEMES list matches its themes |
Create a component |
pnpm --filter @v4/storybook visual-diff -- --story <id> --ref <png> |
Scores a story against a Figma reference PNG (pixelmatch) | Testing |
node apps/storybook/scripts/contrast-table.mjs --story <id> (or --component <name>) |
Measures every text and background pair a story renders, for the accessibility page (Storybook running) | Accessibility |
pnpm --filter @v4/storybook build / chromatic |
A static Storybook; a Chromatic upload | Testing |
Tokens and Figma
These need FIGMA_PAT in the root .env, except where a row says offline.
| Command | What it does | Explained in |
|---|---|---|
pnpm --filter @v4/tokens-euro-league generate |
Regenerates the club's tokens and the competition theme layers from its tokens.json — run after every Token Studio push |
Token packages |
pnpm --filter @v4/tokens generate |
Regenerates the Ghost defaults from the vendored tokens.json |
Token packages |
pnpm --filter @v4/tokens check / pnpm --filter @v4/tokens-euro-league check |
Parses and validates a tokens.json without writing (offline) |
Token packages |
pnpm --filter @v4/tokens sync-icons |
Regenerates the icon components from the Ghost Figma file | Token packages |
pnpm --filter @v4/tokens drift |
The design-drift report: has the Ghost file moved since each bridge's version? | Token pipeline |
pnpm --filter @v4/tokens-euro-league coverage |
How much of the Ghost contract the club export re-specifies (offline) | @v4/tokens-euro-league |
pnpm --filter @v4/tokens-euro-league figma-colour-check |
Checks every colour the club tokens emit equals what Figma paints | @v4/tokens-euro-league |
pnpm --filter @v4/token-parser exec v4-tokens coverage -c <components-dir> [-n <component>] [--write] |
Recomputes binding coverage from the cached extractions (offline) | @v4/token-parser |
node packages/token-parser/scripts/check-bridges.mjs |
Offline: every bridge names a Figma file this repo is built from, and every cached extraction agrees with its bridge (also in pnpm verify) |
Refactor a component |
node packages/token-parser/scripts/design-status.mjs --file <key> [--ready] [--unbuilt] |
The design and development status the client's Figma file records per component | Refactor a component |
node packages/token-parser/scripts/fork-diff.mjs --upstream <ghostKey> --client <clientKey> [--only <component>] |
Diffs a component's bindings between the Ghost file and the client fork, ranked by difference | Refactor a component |
node packages/token-parser/scripts/design-drift.mjs [--only <component>] [--state <file>] |
Has the client design moved since each extraction was cached? | Refactor a component |
node packages/token-parser/scripts/extract-figma-bindings.mjs / extract-colour-ways.mjs |
Writes a component's Token Studio bindings (or its colour-way variants) into its tokens/ folder |
Create a component |
node packages/token-parser/scripts/export-figma-screenshots.mjs |
Exports a component's Figma reference PNGs | Testing |
node packages/token-parser/scripts/verify-against-figma.mjs / verify-bindings.mjs --components=a,b |
Checks a bridge and a component's bindings against the live file | Refactor a component |
Do not run pnpm --filter @v4/tokens-euro-league sync-tokens: Token Studio pushes the
club's tokens.json straight to the repo, and the old sync source would revert the
palette.
Model and Contentful
These read CONTENTFUL_SPACE_ID and CONTENTFUL_CMA_TOKEN from the root .env;
--env is always explicit, and protected environments are refused outside CI.
| Command | What it does | Explained in |
|---|---|---|
node packages/model/scripts/migrate.mjs --env=<env> [--dry] [--until=<migration>] [--skip-apps] |
Applies pending migrations, then syncs the Contentful apps | Change the content model |
node packages/model/scripts/lint-migrations.mjs |
Ownership, numbering and contract-marker checks on every migration | Change the content model |
pnpm --filter @v4/model drift |
Re-vendors the schema, regenerates the types and the app codegen, and fails on any difference | Change the content model |
pnpm --filter @v4/model sync-schema / generate |
The two halves of that: introspect the schema; regenerate the types | Code generation |
pnpm --filter @v4/web generate (and @v4/content-app, @v4/video-app, @v4/basketball-app) |
Regenerates one package's query types; drift does the same and fails on a difference |
Code generation |
pnpm --filter @v4/model seed -- --env=<env> [--only=content,video] [--dry] |
Creates and publishes the demo content, idempotently | Change the content model |
pnpm --filter @v4/model push-dictionary / sync-dictionary |
Seeds new dictionary keys in Contentful; pulls the labels into the generated snapshot | Dictionary keys |
pnpm --filter @v4/model sync-apps -- --env=<env> [--apply|--check] / lint-apps |
Installs and binds the Contentful apps (dry by default); lints the app registry | Change the content model |
pnpm --filter @v4/model sync-webhooks / sync-preview-urls (--env, --url) |
Points the space's webhooks and preview URLs at a site | Caching and revalidation |
node packages/model/scripts/add-locale.mjs --code=<locale> --name="…" [--env=<env>] |
Adds a locale to the space | Localisation |
node packages/model/scripts/import-articles.mjs --source=<file> [--map=<mapper>] |
Turns a foreign CMS export into article seed fixtures (writes nothing to Contentful) | Change the content model |
node packages/model/scripts/backfill-article-competition.mjs --env=<env> [--apply] |
Data script: sets each article's competition | Staging |
node packages/model/scripts/merge-players-into-profile.mjs --env=<env> [--apply] |
Data script: merges the player entries into their profiles | Staging |
node packages/model/scripts/migrate-text-tags.mjs --env=<env> [--apply] |
Data script: free-text tags to public tags | Content models |
pnpm --filter @v4/content-app check-addresses -- --env=<env> |
Checks the content addresses an environment's entries produce | @v4/content-app |
pnpm --filter @v4/competition-engine sync-spec / check-spec |
Re-vendors the Competition Engine's OpenAPI spec; reports whether it has moved | @v4/competition-engine |
pnpm --filter @v4/competition-engine generate / record-fixtures |
Regenerates the engine's API types; records live responses as typed mocks | @v4/competition-engine |
Composition and template updates
| Command | What it does | Explained in |
|---|---|---|
pnpm compose (-- --check in CI) |
Regenerates the route shims and the model composition from club.config.ts |
Template config |
pnpm add-feature |
Adds a bought domain to the site | Add a domain |
pnpm sync-upstream |
Offers the template's changes to this repo as a pull request | Take template updates |
pnpm new-club is also in the root scripts because it came with the template:
it is the command that cut this repo, and is not run here.
Tickets
pnpm --filter @v4/tickets <script>. Every board write is dry until --apply.
| Script | What it does | Explained in |
|---|---|---|
tickets-doctor |
Read-only: every ticket setting is set and working | @v4/tickets |
lint-tickets / lint-ac-voice / lint-cms-fields / drift |
Schema, criteria wording and CMS-field checks; the pre-push check | @v4/tickets |
verify-ticket -- --only=<slug> |
Plays a ticket back against the code, the model and Figma | @v4/tickets |
build-cms-model -- --from=contentful |
Rebuilds the content model the tickets are checked against | @v4/tickets |
push-jira -- [--epic=<slug>] [--only=<slugs>] [--apply] |
Pushes tickets to the board (--create, --design-only, --criteria-only, --links-only, --resync) |
@v4/tickets |
match-figma <file-key> --write / sync-screenshots |
Repoints design links at the client's files; attaches screenshots for finished designs | @v4/tickets |
adopt-board / register-epics |
Records a hand-cloned board's keys; records the epics | @v4/tickets |
write-panels -- --key=<KEY> --proposal=<file> / mark-refined / ready-for-dev |
Writes approved panels to one issue; labels it refined; moves it to ready for development | @v4/tickets |
render-board <out.html> / list-epic |
A board preview; an epic's tickets | @v4/tickets |
Release
| Command | What it does | Explained in |
|---|---|---|
Actions → release → Run workflow (version) |
Releases a release branch: fast-forwards main, tags, publishes the GitHub Release, marks the Jira version released |
Releasing |
node scripts/ci/release-jira.mjs build --ref=origin/release/<version> |
The release ticket report, dry (add --apply to write) |
Releasing |
node --test scripts/ci/release-lib.test.mjs |
Tests the release script's helpers | Releasing |
Sweeps of a running site
Run against the app on :3000 (or the paths given).
| Command | What it does | Explained in |
|---|---|---|
node scripts/page-audit.mjs [path …] |
Text the colour of its background, zero-size components, broken images, overflow and console errors, at five widths; CONTRAST=1 adds every pair below AA |
Testing |
node scripts/clip-sweep.mjs [path …] |
Content clipped out of reach (overflow: hidden with more inside) |
Testing |
node scripts/rung-census.mjs [--list] |
How many components step at each breakpoint, per package (reads the code) | Responsive rungs |
node scripts/loadtest/eviction-storm.mjs |
A load test of mass cache eviction (see scripts/loadtest/README.md) |
Scale and performance |
Claude skills
The /<skill> commands (/generate-from-figma, /preflight, /ticket-work and
the rest) run inside Claude Code; they are listed, with what each runs, in the
skills catalogue.