Skills and agents
The Claude tooling in this repo's .claude folder: the skills, agents, rules and references, what each does and how to run it.
Overview
Everything under .claude/ is the Claude Code tooling for this repo: the skills you
invoke as /<name>, the sub-agents the component pipeline runs, the rules
Claude reads before editing a given kind of file, and the references and plans behind them. Most
of it came with the template this repo was generated from and keeps arriving through
/sync-upstream; the ELB-specific parts — the motion-spec digest, the ELB Figma
inventories, the SSO references and the working plans — are this project's own.
It is built for one job above all: turning ELB's Figma files into typed vanilla-extract
components, then keeping the content model, the tickets and the docs in step with the code.
Generated token contracts are the source of truth throughout — no skill hand-writes a token
value; changes route through tokens.json and the @v4/token-parser
regeneration loop.
Layout
.claude/
├── mcp.json Figma MCP server (npx figma-developer-mcp, FIGMA_PAT in root .env)
├── manifest.json machine-readable asset registry, Figma file keys, templateCommit (the template baseline)
├── rules/
│ ├── frontend/ component-architecture · vanilla-extract-conventions · theme-variant-patterns · fork-refactor · intermediate-rungs · motion
│ ├── testing/ test-conventions (.test.tsx, vitest)
│ ├── documentation/ storybook-conventions · ai-tooling-docs (this page's currency rule)
│ ├── model/ contentful-model (the @v4/model hard rules + field lessons) · contentful-apps (app registry → lint-apps → sync-apps → lock)
│ └── tickets/ acceptance-criteria · tickets-as-code · platform-and-client
├── reference/tokens/ token-reference.md — THE canonical Token Studio ↔ contract mapping
├── reference/motion/ elb-motion-spec.md — the digest of ELB's motion spec (patterns, tokens, decisions)
├── reference/figma/ ghost-core, ghost-content and ghost-basketball inventories and plans, the ELB – Web – Core chrome inventory, the ghost-video plan, the C9–C14 content briefs
├── reference/model/ contentful-model-plan.md — the @v4/model build plan + deployment contract
├── reference/SSO/ the Cortex SSO developer overview (PDF) and sso-mvp-plan.md — the plan @v4/cortex-sso was built from
├── reference/tickets/ tickets-plan.md — the @v4/tickets contract
├── plans/ working plans and audits for in-flight campaigns (motion spec, basketball, video, news, analytics, …)
├── skills/ 38 skills (36 with frontmatter; add-feature and sync-upstream have none)
└── agents/ design-to-code/ + quality-gates/ sub-agent definitions
.mcp.json (repo root) the docs-MCP server, v4-docs (packages/docs-mcp)
One structural principle runs through it: one canonical body per concern. Where
a skill and an agent cover the same ground (accessibility, test ids), the skill holds the
content and the agent is a thin wrapper; the Token Studio ↔ contract mapping exists once, in
reference/tokens/token-reference.md.
Ownership. .claude/skills, agents,
rules and reference are template-owned paths: a
/sync-upstream pull request patches them, so a local edit to a template file
conflicts with the next update unless it is made in the template too. Files that exist only here
(the ELB references) are left alone, and .claude/plans/ and
manifest.json are never offered — they are this project's. See
Take template updates.
Skills catalogue
.claude/skills/ holds thirty-eight skills, each invocable as
/<name>. Thirty-five of them do work in this repo and are listed in three
tables below: ten for building components and taking template updates, fifteen for the content
model and the rest of the site, and ten for tickets. The other three arrive with the template's
.claude/ but have no job here — see the note at the end.
Component and template-update skills
| Skill | What it does |
|---|---|
generate-from-figma |
The flagship: generate a typed vanilla-extract component in
@v4/ghost-core — or any sibling package with
--package=<name> (default ghost-core) — from a Figma
component set: token extraction, contract-first .theme.ts, tests, stories,
quality gates, and a ≥90% visual-comparison loop (max 5 iterations). Seven phases with
tiered orchestration (sequential-blocking → parallel sub-agents → main-context vision) and
a hard "no more Figma calls" checkpoint. For ELB, point it at the ELB file, not Ghost —
the forks preserve node ids (see /fork-status).
|
extract-figma-tokens |
Pull Token Studio bindings for a component from the Figma REST API into
tokens/states/*.json + manifest — colour-set-aware, with the primary-variant
rule that prevents 700-node bloat, and a new Phase 7 that diffs extracted tokens against
the generated contract. Package-aware via --package=<name> (default
ghost-core).
|
sync-figma-styles |
Refresh a component's theme wiring against Figma without hand-writing token values.
Contract gaps route to tokens.json + regeneration; only structural styles and
hand-authored (code-only) themes are edited directly. Keeps the 3-step approval flow.
|
review-against-figma |
Evidence-driven exhaustive audit of a built component against Figma — anti-sampling rules, recursive child review (30-component cap), severity model, three fix modes, and a refuse-to-auto-fix list that now includes generated files. |
convert-css-modules-to-vanilla |
Convert an SCSS-module component from Stadion's previous (v3) platform into a typed
vanilla-extract component, treating the SCSS as behavioural reference only — the visual
truth is the Figma file. Ships with a legacy v3 CSS-variable lookup so old values can be
traced to contract paths. Rarely needed here: the site's components are built from ELB's
Figma with /generate-from-figma.
|
validate-registrations |
Audits the six registration points a component must keep in sync, including contract wiring: generated contracts with no consumer, and Token Studio namespaces unclaimed by code. |
component-accessibility |
Static WCAG A/AA review of a component — semantic HTML, ARIA, keyboard and focus, screen-reader text, contrast structure, motion — with safe auto-fixes. Stable check IDs (A2.1–A8.2), widget ARIA patterns, live-region politeness rules. |
add-test-ids |
Add data-testid via the PH_PREFIX constants model, with a
type-check verification step.
|
add-feature |
Add a template domain this site does not have yet (it has content,
video and basketball). Restores the domain's files from the
template ref (the template's own domains.json says what the domain owns), its
ownership-map block and composition entry, the apps/web deps + transpile wiring, then
re-baselines the model and composes. Prints the Contentful-space migration + bespoke
wiring as follow-ups.
|
sync-upstream |
Take template updates into this repo as a PR. Diffs
templateCommit..template/<ref> over the template-owned paths (design
system, tooling, model core/content + this site's domains, .claude), applies
with git apply --3way onto a branch, records the new baseline, and (with
--create-pr) opens the PR. Never touches what this project owns
(club.config.ts, the club token package, migrations/club/, the
ticket board config). See
Take template updates.
|
Content model and site skills
| Skill | What it does |
|---|---|
model-migration |
The ONE way content-model changes happen: scaffold the numbered migration, expand/contract lint, sandbox-apply on an ephemeral env clone, regenerate schema + types against it, curate fragments/transforms, commit as one change. The PR gate re-proves the pairing in CI. |
model-review |
Review a model PR: expand/contract discipline, ledger integrity, fragment pruning, generated-artefact drift, protected-env safety. |
model-bootstrap-club |
Stand up a Contentful space onto the model-as-code: baseline apply, ledger init, app
installs, webhooks, locales and key scoping. Used once here, when the space
12gd2cvfgb6b replaced the trial space (9 Oct 2026); needed again only if the
site moves to a new space. This project's own model changes go in
migrations/club/, never in core/.
|
model-fragment |
Curate a fragment + transform for one surface: all-fields draft from the vendored
schema.graphql, pruning review (every kept field must have a consumer),
codegen validation, paired transform + test. Page queries stay in the app, spreading these
fragments.
|
model-dictionary |
Manage localised copy keys: vocabulary lives in
src/dictionary/keys.ts (reviewed), labels in Contentful. Add a key → seed the
entry (push-dictionary) → regenerate typed locale maps (committed, not
drift-gated). promote --from --to copies labels between environments —
create+update for vocabulary keys, never touching anything else; protected targets refused
outside CI. Proven live on a throwaway env clone.
|
model-locale |
Add a locale to the model via scripts/add-locale.mjs (CMA —
contentful-migration doesn't manage locales), then regenerate schema + types + dictionary
maps in one drift run and record the baseline. Surfaces the translation gap
as an editorial task.
|
new-package |
Bootstrap a sibling @v4/ghost-* package by copying ghost-video,
with every banked trap as a step: owner-keyed theme emission (OWN_THEMES +
createPackageTheme), the global-surface namespace and club adapter,
register-LAST, Storybook top-level group, e2e, the hardcoded package lists, and a
fresh-Storybook proof before writing components. A package created here is this project's
own (like @v4/ghost-basketball), not a template domain.
|
generate-token-contracts |
Drive @v4/token-parser to turn Token Studio tokens.json into the
generated defaults and typed per-component contracts + icons, safely — surfacing the
modify-extension traps (darken/lighten/alpha, hsl quantisation) that once
collapsed every brand ramp.
In this repo, never run the club token package's sync
(pnpm --filter @v4/tokens-euro-league sync-tokens): it pulls
stadionHQ/elb-web-tokens, which is older than the repo's copy, and silently
reverts the ELB palette. Token Studio commits
packages/tokens-euro-league/tokens.json straight to the repo; run that
package's generate after each push.
|
new-route |
Scaffold a route in a domain route-package
(content-app/video-app) as a per-route factory, wired through
routes.json, codegen and the pnpm compose shims — the product
surface that previously had no tooling.
|
content-type |
The content-type lifecycle — add, update or delete a Contentful content type end-to-end as
an expand/contract-safe migration plus schema, generated types, fragments and transforms
in one reviewed change. Extends model-migration for whole-type operations.
|
preflight |
Prepare a branch for PR: run verify + docs-drift, then enforce
the cross-cutting "same-commit" obligations that are silent when forgotten — catalogue
currency, the e2e↔token coupling, expand/contract markers, and explicit-path staging on a
shared worktree.
|
fork-status |
Where a client Figma fork and this repo disagree, in one pass: which designs are FINISHED, which components are measuring the WRONG file (the fork preserves node ids, so a bridge naming upstream resolves perfectly while being built to a design the client is not using), and which finished designs have no component at all. Then CROSSES them — on ELB the 34 components "measuring the wrong design" and the 11 that were design-complete had an EMPTY intersection, so the loud backlog was not the queue. |
write-e2e-test |
Author a Playwright component e2e (apps/e2e) that asserts resolved token
values, per-instance overrides, RTL and per-rung breakpoints — encoding the ~15 hard-won
harness traps (viewport-not-project, tabTo, aria-disabled,
page.evaluate races, kebab story ids, cold-server timing). Promotes the
e2e-test-generator agent to a directly invocable skill.
|
model-seed |
Populate a Contentful environment with a coherent DEMO site so the pages render end-to-end
(a bootstrapped environment has the model but zero entries) — how develop
got its demo content. Reviewed fixtures in
packages/model/seed/<domain>/*.json, created + published in dependency
order, idempotent, scoped to this site's domains, and guarded against protected envs like
the migrate runner.
|
test-caching-revalidation |
Full-scale LIVE test of the caching stack against a deployed environment: the Next→Redis
on-demand path (Contentful publish → webhook → /api/revalidate →
revalidateTag, coarse + slug tags) AND the Cloudflare edge in front of it.
Publishes a throwaway articlePage, asserts it reaches origin + edge, the
article sitemap refreshes, a re-publish updates the OWN page, unpublish removes it — then
deletes it. Also guards the frozen-cache class (a stale
[object Object] body).
|
Ticket skills (tickets as code)
This repo works in Client mode: its board is ELB's own (ELBWEB), and
once a ticket is on it, Jira is the source of truth — the
.ticket.ts files in packages/tickets are the template's blueprint of
each feature, not the live specification. The rules live in .claude/rules/tickets/ —
platform-and-client.md first (which source each tool reads in this mode), then
tickets-as-code.md and acceptance-criteria.md. Full detail:
@v4/tickets.
| Skill | What it does |
|---|---|
ticket-new |
Draft a ticket — or a linked set for a feature — as typed code in
packages/tickets to the house standard, scoped to a real component, page or
feature. Claude writes it; you approve it.
|
ticket-work |
Pick a ticket up by Jira key or code slug, read its built-in guidance, implement it on a
ticket-ID branch running the skills it names, run the repo's gates, open a PR and update
Jira. Jira-first here: without a Jira connection it stops rather than reading the
.ticket.ts.
|
ticket-setup |
The entry point for the ticket tooling — run it before any other
ticket-* skill on a new machine. Checks credentials, asks for the board, one
Figma file per domain and the Contentful space, writes
jira.defaultProject and figma.files on approval, then DETECTS
whether the board needs a push or an adopt (and stops when the evidence is ambiguous).
Ends with tickets-doctor.
|
ticket-review |
Review a ticket against the standard and, where Jira is connected, report drift between the code ticket and its issue. Here Jira is authoritative: drift means the board has moved on from the blueprint, not that the board is wrong. |
ticket-push |
ONE-WAY push to the ELBWEB board: create-only (--create, one epic at a time),
records the returned keys, wires blocker and Relates links. Jira is the
source of truth once a ticket lands there, and a resync refuses any ticket whose
description someone edited in Jira.
|
ticket-design |
Match a client Figma file's pages and components to tickets and populate their design
links. Screenshots only once the design is final — which design-status.mjs is
how you check.
|
ticket-board |
Render the current ticket set to a shareable board preview, grouped by epic in the house layout, and publish it for sign-off — the quick “show me the board” command. |
ticket-status |
Pull the live Jira status of the set into a standup view (read-only): status, assignee, blockers, and what is done, in progress or blocked, grouped by epic. |
ticket-update |
Brings ONE Jira ticket to ready-for-development: reads it against the client’s Figma and Contentful, works out what the client has customised against the component code, attaches the screenshot, and proposes rewrites to CMS, TECH, acceptance criteria and the Claude guidance for approval. |
ticket-update-epic |
/ticket-update for a whole epic: lists the epic's tickets FROM JIRA
(list-epic; locked tickets named and skipped, a repo ticket not on the board
reported, never drafted), drafts each ticket's panels as the client's specification from
the live description, the code, the client's Figma and Contentful, asks its questions in
batches, and only after approval writes through write-panels, syncs the
screenshots, and labels each written ticket refined-for-client. Never
rewrites a .ticket.ts, never resyncs or creates.
|
Three skills come with the template's .claude/ and do nothing in this repo:
new-club cuts a new client repo from the template (it is how this one was made),
new-contentful-app scaffolds into apps/contentful, which lives only
in the template — the Contentful apps installed in this space are built there and installed
here by sync-apps — and ticket-resolve works on the template's own
board and refuses to run here.
Agents, rules & references
Sub-agents
Agents are the parallel workers generate-from-figma orchestrates. Design-to-code
agents build; quality gates verify. Every agent takes the owning package (--package
on the skill, default ghost-core) and resolves its paths, --filter,
registrations and story/e2e folders from it.
| Agent | Role |
|---|---|
design-to-code/figma-parser |
Node-map and variant-axis classification, wrapper-frame detection, and master-node resolution — an instance shows one variant, the master carries all of them. |
design-to-code/component-scaffolder |
Owns the scaffold and every component file template (.component.tsx,
.css.ts, contract-first .theme.ts, .types.ts,
.test.tsx, stories, MDX docs), so the generation detail lives here rather
than in the skill.
|
design-to-code/prop-inference |
Detection rules (repeated INSTANCE → typed array; Selected=Yes/No → boolean; 3+-state axis
→ CSS-only) plus accessibility-requirement inference; writes
props-inference.json and confirms before generation.
|
quality-gates/code-quality-gate |
Tier-1 early-bail static checks (including the ph prefix, never
gam, and no hand-edited generated content) then lint/type phases; one-line
output contract.
|
quality-gates/visual-regression-check |
Static story validation, then the iterative capture/compare/fix loop (≥90%, max 5). Wrong values traced to a generated contract are flagged upstream, never hand-edited. CI-grade regression stays with Chromatic. |
quality-gates/accessibility-review, add-test-ids |
Thin wrappers over their canonical skills, so each checklist exists in one place. |
quality-gates/e2e-test-generator |
Phase 2.9 (Tier 3): generates apps/e2e/tests/{package}/{name}.e2e.ts (specs
are foldered by owning package) — computed token resolution against manifest values,
per-instance overrides, interaction states, RTL and both breakpoint projects.
|
quality-gates/extract-to-utils |
Shared-code extraction with target homes in the @v4/ghost-core theme/utils
layer, the owning package's own src/utils, or a planned
packages/core (there is no @v4/theme); a component family
sharing 3+ artefacts triggers a family-refactor suggestion.
|
Rules
-
frontend/component-architecture.md— per-file responsibilities, flat component dirs, the six registration points, contract-first theming with a code-only fallback, and the "naming convention is the API" rule (Figma namespace ↔ component name ↔--ph__*vars). -
frontend/vanilla-extract-conventions.md—style()vsrecipe()vsglobalStyle(), the what-goes-where table (.theme.ts= colours/spacing/radius;.css.ts= layout/states/breakpoints), motion utilities with automatic reduced-motion, and performance rules. -
frontend/theme-variant-patterns.md— colour sets are the theming axis, never anonDarkprop; the five override levels, owner-keyed theme emission, and how the app emits the ELB theme in parts. -
frontend/fork-refactor.md— the playbook for how this project's design works: ELB's Figma files are COPIES of the Ghost files, modified heavily in place, and we refactor the code to match. The fork PRESERVES node ids, so a bridge naming the upstream file resolves perfectly while measuring the wrong design — four of four components audited on ELB were built to upstream. Covers the preserved-id trap, why a coverage percentage means "matches whichever file the extraction came from", hollow client masters, bindings that contradict their own render, and the ordered sequence that actually works. -
frontend/intermediate-rungs.md— the two bands the design does not draw (tablet 768–1023, laptop 1024–1439): a band binds the page measure (min(100% − 2 × gutter, ContainerWidth.XL)) on its outermost container, families declare anmdstep from the M grid, the header hands off at 1440 by design, and the rungs stay measured (census script, audit defaults, Playwrighttablet/laptop). -
frontend/motion.md— what moves and how much, from ELB's design-owned motion spec (v0.3, 27 Oct 2026; digest atreference/motion/elb-motion-spec.md): every animation names its spec pattern (P-CASCADE,P-REORDER…), values come from themotion.*tokens and never literals, reduced motion gets the complete page instantly, entrances play once per visit, ads and logos never animate, the animation budget is measured, and each pattern is tested in both directions. -
testing/test-conventions.md—.test.tsx, vitest, required coverage list, colour-set render cases,--ph__*token-override assertions. -
documentation/storybook-conventions.md— stories live inapps/storybook, category map, the requiredAllColourSetsstory, and the figma.mdx / accessibility.mdx companion-doc specs. -
documentation/ai-tooling-docs.md— this catalogue stays current: any commit that adds, removes or repurposes a skill, agent, rules file or reference updates these pages (and CLAUDE.md's skill list) in the same commit. -
model/contentful-model.md— the model-as-code spine: domain-sliced migrations with ownership lint, expand/contract discipline, the vendored-schema drift gate, fragment curation rules and the dictionary-key flow. -
model/contentful-apps.md— the Contentful apps installed in the space. Their source is built and released in the template; what this repo has is the registry, the lock and the sync. Declared only inpackages/model/apps/registry.json, checked bylint-apps, installed and bound bysync-apps(whichmigrate.mjsruns after the migrations) and recorded in the generatedapps.lock.json. Migrations bind an app by slug, never by definition id; each app has adevelopand aproductionrelease channel that follows the environment. -
tickets/tickets-as-code.md— tickets are authored as typed TS inpackages/ticketsand pushed ONE-WAY to Jira: the spine, the board bindings, and the hard rules (derived titles and labels, one Figma feature frame per ticket, the resync fingerprint that refuses a ticket someone edited in Jira). -
tickets/acceptance-criteria.md— the single source for what an acceptance criterion says and how it is worded: written for a QA tester or an editor, purely functional, no developer vocabulary, and every content type and field named as Contentful shows it.lint-ac-voiceandlint-cms-fieldsenforce it. -
tickets/platform-and-client.md— this repo is in Client mode: the ELBWEB board, the Contentful space and ELB's own Figma files are authoritative, not the repo. Read before changing where any ticket tool reads facts from: a tool that silently assumes the repo is authoritative passes every gate and is wrong on the board.
Reference
reference/tokens/token-reference.md is the
single canonical Token Studio ↔ contract-path mapping. Every skill points here instead
of embedding its own table. Where it and the generated
packages/tokens/src/__generated__/tokens.ts disagree, the generated file wins.
The other references:
-
reference/motion/elb-motion-spec.md— the digest of ELB's motion spec: every pattern, value and open decision, with a "code today" column. -
reference/figma/— the component inventories and build plans (ghost-core, ghost-content, ghost-basketball, the ELB – Web – Core chrome inventory, the ghost-video plan) and the ghost-content batch briefs. Read the ghost-core and ghost-content inventories with the fork rule in mind: they record Ghost node ids, which resolve in ELB's files too. -
reference/model/contentful-model-plan.md— the@v4/modelbuild plan and the deployment contract. -
reference/SSO/— the Cortex SSO developer overview and the MVP plan@v4/cortex-ssowas built from. -
reference/tickets/tickets-plan.md— the full@v4/ticketscontract behind the ticket rules.
Working plans for in-flight campaigns live beside these in .claude/plans/; they are
records of a piece of work rather than standing rules.
How the pieces fit together
Several skills, agents and rules cover neighbouring ground. These are the boundaries, so you reach for the right one and do not expect two of them to do the same job.
One canonical body per concern
-
Accessibility.
/component-accessibilityholds the checklist (stable check ids, the widget ARIA table, live-region politeness rules). Thequality-gates/accessibility-reviewagent is a thin wrapper over it. - Test ids. Likewise
/add-test-idsand its agent. -
Token mapping. The Token Studio ↔ contract table exists once, in
reference/tokens/token-reference.md; where it disagrees with the generatedpackages/tokens/src/__generated__/tokens.ts, the generated file wins. -
Generation detail.
/generate-from-figmais the seven-phase orchestration; the Figma parsing lives in thefigma-parseragent and the file templates in thecomponent-scaffolderagent, which its first phases run.
Reviewing a component against Figma: which skill
-
/review-against-figma— the exhaustive audit-and-fix: every token, spacing, typography, colour and child component, recursively. Colour gaps it finds are routed back to the token pipeline. -
/sync-figma-styles— the targeted refresh of theme wiring and structural styles. It ignores colours and routes contract gaps totokens.json. -
/fork-status— run first, before either: it says which ELB designs are finished and which components are bridged to the wrong file. Reviewing a component against a design that is still moving, or against Ghost instead of ELB, is the expensive mistake (.claude/rules/frontend/fork-refactor.md).
House terms the tooling assumes
Every skill uses the same vocabulary: colour set (code key colourSet1,
never "color set" or "colourTheme"), the ph CSS-variable prefix (never
gam), @v4/ghost-core for the theme helpers (there is no separate
@v4/theme package), the six registration points a component must keep in sync, and
compoundVariants over contract paths for the colour-set × state matrix. A skill
that says otherwise is out of date — raise it rather than following it.
Frontmatter
36 of the 38 skills carry YAML frontmatter, with names matching their directories;
add-feature and sync-upstream have none, so Claude Code lists them
without a description, but they run as /add-feature and
/sync-upstream all the same.
Gaps: what the tooling does not cover yet
Work this project does by hand today because no skill covers it. New skills arrive from the
template through /sync-upstream, so a gap that applies beyond this site is best
raised there.
| Gap | Status | What it would do |
|---|---|---|
performance-review |
Open |
A Tier-2 quality gate for re-renders, CSS output size and bundle hygiene. Today the
performance work (the club theme emitted in parts, the global layer on
:root) is found by Lighthouse runs and done by hand.
|
| Motion patterns | Open |
No skill builds or tests a motion pattern; .claude/rules/frontend/motion.md
and the spec digest are followed by hand, and the developer pack (motion tokens) has not
arrived yet.
|
Using the tooling today
Everything listed in the catalogue is live in this repo. The Figma MCP server
(.claude/mcp.json) and the Figma-dependent skills need FIGMA_PAT in
the root .env; the ticket skills need JIRA_EMAIL and
JIRA_API_TOKEN there too. Skills invoke as /generate-from-figma,
/review-against-figma, and so on; how to run each one, with or without Claude, is
on the next page.
Running a skill: manually vs /skill
Every skill under .claude/skills/ can be run two ways, and they read from the same
source. /<name> in Claude Code loads that skill's SKILL.md and
Claude executes it. Running it manually means following the same
SKILL.md yourself — and for a large share of the skills a deterministic
pnpm/node command IS the heart of the procedure, so the "manual path"
is just invoking that command with the right arguments.
So the useful question is not "which skills have a manual path" (all of them do — the
SKILL.md) but "does a single command do the real work, or is the work judgment?".
That splits the thirty-five skills used here cleanly in two: twenty script-backed, fifteen
orchestrated by Claude. (The three template-only skills — new-club,
new-contentful-app, ticket-resolve — are left out; see the catalogue.)
Script-backed skills — a command is the deterministic core
Here a pnpm/node entrypoint does the mutating work. The skill wraps it
with an interview (collect the arguments), a sandbox step (an ephemeral Contentful clone for the
model skills), and verification (drift/regen/tests) — but you can drive the command directly
when you already know the arguments, and CI does exactly that. Run the skill for the guided
flow; run the command when you want just the one step.
| Skill | Deterministic entrypoint (the manual path) | What the skill adds around it |
|---|---|---|
new-package |
pnpm --filter @v4/<name> build && … check-types && … test |
Scaffolds the package skeleton (package.json, tsconfig, exports) before the build/verify. |
new-route |
pnpm compose |
Authors the route factory in the domain's route package, then regenerates the app shims. |
add-feature |
pnpm add-feature -- --domain=<name> [--ref=main] |
Restores a template domain this site does not have yet from the template ref, re-baselines the model and composes; prints the Contentful-space migration + bespoke wiring follow-ups. |
sync-upstream |
pnpm sync-upstream -- [--ref=main] [--create-pr] |
Diffs this repo's templateCommit against the template ref over the
template-owned paths, 3-way applies to a branch, and opens a PR for review.
|
model-migration |
node packages/model/scripts/lint-migrations.mjs →
node packages/model/scripts/migrate.mjs --env=<clone>
|
Scopes the change, scaffolds the numbered .cjs, applies on an ephemeral
clone, regenerates and curates fragments/transforms as one change.
|
content-type |
node packages/model/scripts/migrate.mjs --env=model-dev-<topic> |
The model-migration flow specialised to creating a whole content type. |
model-fragment |
edit src/<domain>/fragments/*.graphql →
pnpm --filter @v4/model generate
|
Picks the fields the surface consumes (prune, never select-all); codegen validates them against the vendored schema. |
model-review |
pnpm --filter @v4/model drift |
Reads the schema+regen diff and reports what a model PR would change. |
model-seed |
pnpm --filter @v4/model seed -- --env=develop [--only=…] [--dry] |
Authors/curates the demo fixtures under seed/<domain>/ before the
idempotent, domain-scoped push.
|
model-locale |
node packages/model/scripts/add-locale.mjs --code=… --name="…" |
Adds the locale (contentful-migration cannot) and covers the fragment/dictionary follow-ups. |
model-dictionary |
edit src/dictionary/keys.ts →
pnpm --filter @v4/model push-dictionary / sync-dictionary
|
Adds the reviewed key + default copy, seeds the entry (never overwrites editors' labels), pulls the generated locale files. |
model-bootstrap-club |
node packages/model/scripts/migrate.mjs --env=<env> (full core
sequence)
|
Applies the composed baselines to a new space plus locales, webhooks and per-env delivery keys. Done once for this project's space. |
generate-token-contracts |
pnpm --filter @v4/tokens-euro-league generate (and
pnpm --filter @v4/tokens generate for the Ghost defaults)
|
Regenerates the typed contracts and reviews the diff for the modify traps. In
this repo Token Studio commits the club's tokens.json directly, so skip the
skill's sync-tokens step: the club package's sync reverts the ELB palette.
|
preflight |
node scripts/verify.mjs (= pnpm verify) and
node scripts/hooks/docs-drift.mjs
|
The machine gates are only the first half: the skill then walks the same-commit checklist (catalogue currency, e2e ↔ token coupling, expand/contract markers…) — obligations no command checks, which are judgment. |
fork-status |
node packages/token-parser/scripts/design-status.mjs --file <clientFileKey>
[--ready] [--unbuilt]
and
node packages/token-parser/scripts/fork-diff.mjs --upstream <ghostKey> --client
<clientKey>
|
Runs both and crosses them: which components' designs are finished, which measure the wrong file, and which finished designs have no component. |
test-caching-revalidation |
node .claude/skills/test-caching-revalidation/run.mjs [--read-only] [--json]
|
Checks the prerequisites (a deployed environment, the webhook secret, origin and edge URLs) and reads the result against the caching test plan. |
ticket-setup |
pnpm --filter @v4/tickets tickets-doctor (then adopt-board /
register-epics)
|
Writes the board, Figma files and Contentful settings, and decides push vs adopt. |
ticket-push |
pnpm --filter @v4/tickets push-jira -- --epic=<slug> [--create] [--apply
--verify]
|
Refreshes the model and Figma links first (build-cms-model,
match-figma), pushes one epic at a time, then registers epics and syncs
screenshots.
|
ticket-design |
pnpm --filter @v4/tickets match-figma <file-key> [--write] /
sync-screenshots [--apply]
|
Matches the client file's frames to tickets; screenshots only for finished designs. |
ticket-board |
pnpm --filter @v4/tickets render-board <out.html> |
Publishes the rendered board as an artifact for sign-off. |
Claude-orchestrated skills — the work is judgment, not a command
These have no single mutating command: the work is gathering evidence (from the Figma REST API,
or across the codebase) and making calls a script cannot — which token a node binds, whether a
discrepancy is a bug or a cleanup, which WAI-ARIA pattern applies. The SKILL.md is
the manual procedure, step by step. The command listed is only the verification or
build step you run after the judgment work — never a substitute for it.
| Skill | Manual procedure | Verification / build step |
|---|---|---|
generate-from-figma |
The 7-phase pipeline in its SKILL.md: extract → contract-first theme →
component/tests/stories → quality gates → ≥90% visual loop. Targets
packages/<package> with --package=<name> (default
ghost-core).
|
pnpm --filter @v4/tokens sync-icons (icons), then the package build/tests.
|
extract-figma-tokens |
Walk the Figma node subtree via the REST API into tokens/states/*.json +
manifest (primary-variant rule).
|
pnpm --filter @v4/tokens build |
sync-figma-styles |
Diff a component against Figma; route contract gaps to tokens.json +
regeneration; edit only structural / code-only themes.
|
pnpm --filter @v4/tokens build |
review-against-figma |
Evidence-driven exhaustive diff against the REST API — anti-sampling, recursive child review, severity model, three fix modes. | pnpm check-types |
convert-css-modules-to-vanilla |
Port an SCSS-module component from Stadion's previous (v3) platform to vanilla-extract, tracing legacy variables to contract paths. Rarely needed here. | pnpm --filter @v4/ghost-core check-types |
add-test-ids |
Add the TEST_ID entry to constants.ts and wire
data-testid through the component (BEM child derivation).
|
pnpm check-types |
component-accessibility |
Audit semantics/ARIA/keyboard/contrast against the actual component files; write the
.accessibility.mdx.
|
Story a11y gate (a11y: { test: "error" }). |
validate-registrations |
Audit the six registration points (barrel, theme registry, init.css,
figma.json, stories, token contract) for drift.
|
pnpm --filter @v4/ghost-core build |
write-e2e-test |
Author apps/e2e/tests/<package>/<name>.e2e.ts encoding the
harness traps (viewport-not-project, tabTo, kebab story ids, per-rung
breakpoints).
|
pnpm --filter @v4/e2e test |
ticket-new, ticket-review |
Draft or review a .ticket.ts against the acceptance-criteria and
tickets-as-code rules (and, for review, against its Jira issue).
|
pnpm --filter @v4/tickets lint-tickets;
verify-ticket -- --only=<slug>
|
ticket-update, ticket-update-epic |
Read the Jira ticket with the client's Figma, Contentful and the code; propose panel
rewrites for approval. Never rewrites a .ticket.ts.
|
pnpm --filter @v4/tickets write-panels -- --key=<KEY> --proposal=<file>
[--apply]
|
ticket-work |
Read the Jira ticket (Jira-first; it stops without a Jira connection here), build it on a ticket-ID branch, run the skills it names, open a PR. | pnpm verify |
ticket-status |
Read-only standup view of the board's live statuses, grouped by epic. | — |
Rule of thumb
Reach for the command when you already know the single step you need — a
fragment regen, a drift check, a compose — or when you're in CI. Reach for
the skill when you want the guided flow (interview, ephemeral sandbox, regen
+ tests as one reviewed change) or when the work is judgment the command can't make for you.
Either way the SKILL.md is the definition of record — this page just says which
half of it does the work.