Project-specific rules for working in this repo. These are hard constraints — follow them exactly.
A static rebuild of the OpenFront wiki: Astro 5 + Tailwind v4, output to
dist/, auto-deployed to Cloudflare Pages (Git integration) on every push to
main. Homepage is src/pages/index.astro; articles are generated by
src/pages/[slug].astro from src/data/pages.json.
- The build MUST remain a pure static export (
astro build→dist/of HTML/CSS/JS/assets). - Do NOT add an SSR adapter, set
output: "server"/"hybrid", add server endpoints/API routes (src/pages/**/*.{js,ts}that return responses), useexport const prerender = false, or introduce any runtime backend, database, or server process. - No build step may require network access to a private service. Anything dynamic must be done client-side with public data, or precomputed at build time.
- Cloudflare Pages serves static files only — if it can't be served as a flat file
from
dist/, it doesn't belong here.
- Never commit API tokens, keys, passwords, or
.envfiles with secrets. - The site needs no secrets to build or run. Deployment auth lives in Cloudflare's dashboard, not in this repo.
- Don't add code that reads secret env vars at build or runtime.
Before committing any change that affects the rendered site (pages, components,
styles, content), you MUST build and visually verify with the run-openfront
skill in .claude/skills/run-openfront/:
# one-time per machine
bash .claude/skills/run-openfront/setup.sh
# verify a change
npm run build # must succeed with no errors
npm run dev -- --host --port 4321 & # or use a running dev server
node .claude/skills/run-openfront/shot.mjs http://localhost:4321/<path> /tmp/shot.png 1440 1000Then read the screenshot and confirm it renders correctly (desktop, and mobile
at 390 844 for layout-affecting changes) before committing. shot.mjs also
prints any console/page errors — there should be none. A change is not "done"
until it has been screenshot-verified.
Three licenses coexist — see LICENSING.md. Code is MIT; brand assets
(public/assets, public/fonts, favicons) are proprietary to OpenFront Inc.;
wiki content (src/data/pages.json, public/images) is CC BY-SA 4.0. Don't
relicense or move assets between these buckets.
Article content is generated, not hand-authored. Two pipelines feed
src/data/pages.json:
Primary: crawl with .claude/skills/run-openfront/crawl-wiki.mjs, then clean
with scripts/prepare-content.mjs → src/data/pages.json. To refresh content,
re-run those rather than editing the JSON by hand.
The crawl source is the live MediaWiki at openfront.miraheze.org (via its
API). openfront.wiki itself now serves this static rebuild, so it is not a
valid source — don't point the crawler back at it.
Secondary (Liquipedia): scripts/liquipedia-fetch.mjs (API-only, rate-limited,
cached — never scrape HTML; keep the custom User-Agent) → scripts/prepare-liquipedia.mjs
→ pages.json. This pipeline is a manual-refresh snapshot that goes stale; images
use a filename allow-list (isHostableImage). Re-run the scripts periodically to
refresh — new pages may require tuning deriveCats heuristics.
Legacy pages: A few substantive pages once lived on the old wiki but have no
equivalent on the current source, so a crawl can't recover them. They're preserved
(pre-cleaned) in scripts/legacy-pages.json with any images in
scripts/legacy-images/, and prepare-content.mjs merges them back in
automatically (upstream wins if a slug ever reappears). Edit those files to
add/remove a legacy page — not pages.json.
npm install
npm run dev # http://localhost:4321
npm run build # -> dist/ (must stay static)
npm run preview