Keeping nself.org in sync with SPORT
How to update marketing copy, pricing, and plugin counts when SPORT source files change.
All version strings, prices, and plugin counts on nself.org are generated at build time from authoritative SPORT source files. Hand-editing these values in the website source will cause your changes to be overwritten on the next build.
What is SPORT?
SPORT (Single Point of Reference Truth) is a set of 15 Markdown files at
.claude/docs/sport/F01-F15.md inside the nself monorepo root. These files are
code-verified and read-only. They are the canonical source for:
- Plugin counts (F03, F04)
- Bundle membership (F06)
- Pricing tiers (F07)
- Version strings (F01 / MASTER-VERSIONS.md)
How the build pipeline works
SPORT source files → build scripts → generated files → Next.js pages
Three scripts run before every pnpm dev and pnpm build in web/org:
| Script | Input | Output |
|---|---|---|
scripts/sync-sport.mjs |
SPORT + MASTER-VERSIONS | src/generated/sport.json |
scripts/gen-pricing.mjs |
F06, F07, sport.json | src/data/generated-pricing.ts |
scripts/validate-sport-json.mjs |
sport.json | CI gate (exits non-zero on errors) |
The pages that consume generated data:
/pricing: importsGENERATED_TIERSandGENERATED_BUNDLES/plugins: importsGENERATED_PLUGIN_COUNTSfor header stats
Updating prices or bundle membership
-
Edit the authoritative SPORT file:
- Pricing changes →
.claude/docs/sport/F07-PRICING-TIERS.md - Bundle membership changes →
.claude/docs/sport/F06-BUNDLE-INVENTORY.md
- Pricing changes →
-
Regenerate the TypeScript data module:
cd web/org node scripts/gen-pricing.mjs -
Verify the output in
src/data/generated-pricing.tsmatches your intent. -
Run tests to confirm no canonical values regressed:
pnpm vitest run
Updating version strings
-
Edit
MASTER-VERSIONS.mdat the nself monorepo root (.claude/docs/MASTER-VERSIONS.md). -
Regenerate sport.json:
cd web/org node scripts/sync-sport.mjs -
The
/pricingand/pluginspages pick up the new counts automatically via sport.json.
Updating plugin counts
Plugin counts are no longer derived from F03/F04 (those are now pointer-only docs). They
come from plugins/counts.json (LOCKED SCHEMA v1, produced by
plugins/scripts/plugin-counts.sh in the public nself-org/plugins repo), which
sync-sport.mjs reads directly into sport.json’s counts.* fields. To update:
- Add or remove plugins in
plugins/orplugins-pro/, then regeneratecounts.jsonwithplugins/scripts/plugin-counts.shin that repo. - Run
node scripts/sync-sport.mjs(from a checkout with a siblingplugins/repo present) to updatesport.json. - Run
node scripts/gen-pricing.mjsto propagate counts togenerated-pricing.ts.
The plugins page header, /pricing, and any docs page importing
GENERATED_PLUGIN_COUNTS from @/data/generated-pricing will now show the correct
counts. Never hand-type a plugin count in prose — see PLUGIN_COUNT_PROSE_TARGETS in
validate-sport-json.mjs, which fails CI on exactly that.
CI validation
validate-sport-json.mjs runs in CI as part of the “SPORT Drift Check” job
(.github/workflows/ci.yml). It fails if:
- sport.json is missing required keys (
generatedAt,versions,bundles,pricingTiers,counts) - CLI version is not in
vX.Y.Zformat - Any superseded tier name (Basic, Pro, Elite, Business) appears in
pricingTiers - Free plugin count drops below 25, or paid plugin count drops below 30
counts.totalPluginCountdoesn’t equal free + paid minus the tier-paired overlap- Any page in
PLUGIN_COUNT_PROSE_TARGETSstates a literal plugin-count digit that disagrees withcounts.*
Fix validation failures by regenerating sport.json or fixing the prose to render from
GENERATED_PLUGIN_COUNTS, not by patching validate-sport-json.mjs.
Never hand-edit these files
| File | Why |
|---|---|
web/org/src/generated/sport.json |
Overwritten on every build |
web/org/src/data/generated-pricing.ts |
Overwritten by gen-pricing.mjs |
Changes to these files will be silently discarded.