Orchestration repository for the OpenPhysics organization. Baton owns the operational side of the org: the reusable CI/CD workflows every simulation calls, the cross-repo automation scripts, the Dependabot templates, the machine-readable repository catalog, and the GitHub Pages simulation landing page.
Community-health defaults (license, contributing, code of conduct, security policy, issue/PR templates, org profile) live in OpenPhysics/.github — GitHub requires those in the special
.githubrepo so they are inherited org-wide.
| Path | Purpose |
|---|---|
.github/workflows/ci.yml |
Reusable CI workflow (audit, lint, type-check, test, build) |
.github/actions/security-audit/action.yml |
Composite action used by ci.yml: npm audit summary, blocks only on high/critical in direct deps |
.github/workflows/deploy.yml |
Reusable GitHub Pages deploy workflow |
.github/workflows/shared-codeql.yml |
Reusable CodeQL analysis |
.github/workflows/shared-dependency-review.yml |
Reusable dependency review |
.github/workflows/shared-compliance-check.yml |
README and repo-structure compliance audit |
.github/workflows/pages.yml |
Build and deploy the org simulation index to GitHub Pages |
.github/workflows/optimize-assets.yml |
Regenerate WebP card thumbnails from screenshots and commit them back |
.github/workflows/refresh-screenshots.yml |
Weekly/manual refresh of card screenshots from live Pages → WebP thumbnails + docs/index.html (opens a PR) |
.github/workflows/fleet-exec.yml |
Fan a command across many repos and open one PR each (manual dispatch) |
.github/workflows/fleet-health.yml |
Weekly lint / type-check / build / test of every simulation, reported as a table |
.github/workflows/sync-dependabot.yml |
Validate the Dependabot templates |
.github/workflows/baton-selfcheck.yml |
Validate Baton's own invariants (skills, catalog schema, Node-version sync, script syntax) |
scripts/ |
Repo catalog tools, compliance checks, Dependabot/metadata sync, screenshots |
config/ |
Canonical Dependabot + Claude-settings templates synced to member repos |
structure/repos.json |
Machine-readable catalog of org repositories |
structure/repos.schema.json |
JSON Schema for the catalog (schemaVersion 1.1.0) |
CONVENTIONS.md |
Shared codebase structure every SceneryStack sim must follow |
ACCESSIBILITY.md |
Shared accessibility pattern for SceneryStack sims |
skills/ |
SceneryStack development reference docs for AI assistants |
.claude-plugin/ |
Marketplace + plugin manifests that package skills/ as the scenerystack@openphysics Claude Code plugin |
docs/ |
Generated landing page (openphysics.github.io/Baton) |
doc/add-simulation.md |
Checklist for adding a sim to the catalog and landing page |
doc/fleet-git.md |
Cheat sheet: everyday git across local checkouts (pull/push/status all) |
doc/fleet-auth.md |
Setting up the FLEET_PAT / GitHub App that lets fleet-exec open PRs |
This repo doubles as a Claude Code marketplace. It publishes one
plugin, scenerystack, that bundles the skills/ reference docs so any sim repo can
load them as a unit instead of vendoring copies. The repo root is the plugin
(.claude-plugin/plugin.json); its skills/ are auto-discovered.
Member repos enable it from their .claude/settings.json (the canonical keys live in
config/claude-settings.json):
{
"extraKnownMarketplaces": {
"openphysics": { "source": { "source": "github", "repo": "OpenPhysics/Baton" } }
},
"enabledPlugins": { "scenerystack@openphysics": true }
}Or interactively: claude plugin marketplace add OpenPhysics/Baton then
claude plugin install scenerystack@openphysics. Validate manifest changes with
claude plugin validate .claude-plugin/marketplace.json.
Roll it out across the fleet with scripts/sync-claude-settings.sh,
which merges those keys into every SceneryStack repo's settings without clobbering existing config.
Each simulation's .github/workflows/ci.yml calls the reusable workflows from this repo:
jobs:
ci:
uses: OpenPhysics/Baton/.github/workflows/ci.yml@main
dependency-review:
if: github.event_name == 'pull_request'
uses: OpenPhysics/Baton/.github/workflows/shared-dependency-review.yml@main
codeql:
uses: OpenPhysics/Baton/.github/workflows/shared-codeql.yml@mainOptional compliance checking:
compliance:
uses: OpenPhysics/Baton/.github/workflows/shared-compliance-check.yml@main
with:
repo-name: ${{ github.event.repository.name }}ci.yml runs the test step automatically when the caller defines a test npm script — no per-repo
flag needed. Pass run-tests: "true" to force it on (e.g. before a test script exists) or
run-tests: "false" to opt out.
Pages deploy (sims that publish to GitHub Pages):
jobs:
deploy:
uses: OpenPhysics/Baton/.github/workflows/deploy.yml@main
permissions:
contents: read
pages: write
id-token: writeshared-compliance-check.yml runs weekly (Mondays 06:00 UTC)
and on manual dispatch. It reads structure/repos.json, clones each simulation repo,
and runs scripts/check-repo-compliance.sh. The gate enforces (FAIL
unless marked (warn)):
- Legal & README — no root
CONTRIBUTING.md/LICENSE(org defaults fromOpenPhysics/.github);README.mdhas the six sections in order with no extras (Features → Quick Start → Scripts → Tech Stack → License → Contributing). - CI wiring —
.github/workflows/ci.ymlcalls this repo's reusableci.ymlplusshared-dependency-review.ymlandshared-codeql.yml;.github/dependabot.ymlpresent. - Node pins —
engines.nodeis>=24and@types/nodemajor is24(matching the fleet Node version); a.nvmrc/.node-version, if present, agrees. - SceneryStack structure (sims only) — the five-file bootstrap chain with
main.tsimporting./brand.jsfirst;<Prefix>Namespace.ts,<Prefix>Colors.ts, and*Constants.tsat thesrc/root; thepreferences/trio;i18n/withStringManager.ts+en/es/frlocales; a*KeyboardHelpContent.ts;.claude/settings.jsonenabling thescenerystackplugin; no tests co-located undersrc/; no top-levelsrc/modelorsrc/view(warn). - Tests & hooks —
tests/memory-leak.test.ts+ avitest.config.tsthat sets--expose-gc;.githooks/{pre-commit,pre-push}activated via thepreparescript. - Docs & tooling —
doc/model.md+doc/implementation-notes.mdpresent and filled (warn if stub);biome.json$schemaversion matches the pinned@biomejs/biome. - GitHub security (when
ghis authenticated) — Dependabot vulnerability alerts + security updates, and secret scanning on public repos.
Simulation READMEs use the fixed six-section outline above. Items marked (warn) — plus hardcoded
colors and nested constants — surface as warnings, not failures: document each as a carve-out
under ## Compliance carve-outs in the sim's CLAUDE.md.
Run locally against a checkout:
scripts/check-repo-compliance.sh /path/to/sim-repostructure/repos.json lists all OpenPhysics repositories with metadata
(displayName, lineage, upstream, framework, deployed URL, physics topics, status, etc.).
Schema: structure/repos.schema.json (validated by
scripts/check-repos-catalog.sh). The compliance workflow,
Pages landing page, and the catalog scripts consume this file. Ground-truth upstream references
for sims live in the sibling Baseline repo (also
listed here as type: tool). See
scripts/README.md for the tooling:
scripts/check-repos-catalog.sh
scripts/parse-repos.sh names --simulation
scripts/parse-repos.sh names --lineage phet
scripts/list-repos.sh --json
scripts/sync-github-metadata.sh --dry-runAdding a new simulation (create from template, catalog, screenshot, WebP, Pages,
OpenPhysics README): run
scripts/create-sim.sh --onboard (add --pr to open PRs), then
see doc/add-simulation.md for any remaining hand edits
(.github profile tallies). The webpage is generated from repos.json + screenshots/ —
there is no separate Markdown card list to edit.
Scripts assume the Baton repo lives beside member repos in a shared workspace; set
OPENPHYSICS_WORKSPACE or pass --catalog /path/to/repos.json if your checkout differs.
Cross-repo automation, all driven from the catalog:
- Batch changes —
scripts/fleet-exec.shclones each selected repo, runs a command, and (with--apply) opens one PR per repo. Dry-run by default. Thefleet-exec.ymlworkflow exposes it as a manual dispatch (e.g. bump a shared dependency, runnpm run fix, apply a codemod). Opening PRs in other repos needs aFLEET_PATsecret with write access — the defaultGITHUB_TOKENis scoped to Baton only. Setup steps (fine-grained PAT or GitHub App):doc/fleet-auth.md. - Health report —
fleet-health.ymlruns weekly, fanning out one matrix job per active simulation (npm download cache reused across runs) to run lint, type-check, build, and test, then publishing a pass/fail table to the job summary. Read-only; surfaces sims broken by a shared-workflow or dependency change. - Compliance audit —
shared-compliance-check.ymlaudits README structure and CI wiring across the org. The dispatch/schedule run fans out one matrix job per sim and aggregates a single pass/fail table (see above). - Everyday git fan-out —
doc/fleet-git.mdis a cheat sheet for running git across your local checkouts (pull all,push all,status all), built onparse-repos.sh paths. Use it for ad-hoc local work; usefleet-exec.shto land the same change as PRs. - Add a simulation —
scripts/create-sim.shbootstraps from SceneryStackTemplate;doc/add-simulation.mdcovers catalog entry, screenshot capture, WebP thumbnails, and regenerating the Pages index.
The default Node version for the fleet is "24", declared in every Baton workflow that
runs setup-node — bump them together:
.github/workflows/ci.yml—node-versioninput default.github/workflows/deploy.yml—node-versioninput default.github/workflows/fleet-health.yml—setup-nodestep.github/workflows/fleet-exec.yml—setup-nodestep.github/workflows/optimize-assets.yml—setup-nodestep.github/workflows/refresh-screenshots.yml—setup-nodestep
scripts/check-node-version.sh enforces that they stay in
sync (run in CI by baton-selfcheck.yml), so a half-done
bump fails fast instead of drifting silently. When sibling member checkouts are present (local
OpenPhysics workspace), it also asserts each package.json matches the same major.
Member repos must keep:
engines.node:>=24(floor matching the workflow major)@types/node: major 24 (Dependabot ignores@types/nodemajor bumps — bump SceneryStackTemplate and repos together when CInode-versionchanges; seeconfig/dependabot-npm.yml)
scripts/check-repo-compliance.sh fails a sim if those pins
drift. Prefer no .nvmrc / .node-version; if present, the major must match the fleet.