One SvelteKit codebase that builds eleven static sites: the apex
nullmenu.ai plus a subdomain per product
(claw.nullmenu.ai, hub.nullmenu.ai, …). Svelte 5, static adapter,
fully prerendered — no server anywhere.
src/lib/site/sites.js ← the registry: theme, copy, docs sections per site
src/lib/home/ ← MenuHome (apex) + ProductHome (template)
content/<site>/docs/ ← markdown docs (section/slug.md with frontmatter)
content/<site>/product.json ← product-page data (hero, metrics, install, features)
build/<site>/ ← one deployable static site per id
pnpm install
pnpm dev # apex (menu) on :5173
pnpm dev:claw # claw on :5174 — or: PUBLIC_SITE=<id> vite devnode scripts/build-all.js # all sites → build/<id>
node scripts/build-all.js claw hub # just someEvery site ships llms.txt, sitemap.xml, and robots.txt. The LLM index links
the same canonical HTML documentation that people read; raw duplicates are not
published because GitHub Pages cannot attach noindex response headers to them.
Three theme modes — system, light and dark — derive from each product's accent
via color-mix. The preference is persisted across the product subdomains.
The hero runs a WebGPU Navier–Stokes ink simulation (canvas fallback), and
product pages bake platform-aware binary downloads from GitHub Releases.
- Add an entry to
src/lib/site/sites.js(accent, course, docsSections, …). - Drop
content/<id>/product.json+content/<id>/docs/<section>/<slug>.md. - Configure DNS and GitHub Pages for the repository named by the registry entry.
The build list and deployment targets are derived from the registry; there is
no second matrix to keep in sync. pnpm check:content and pnpm check:infra
fail if content, domains or repositories drift.
Push to main — .github/workflows/deploy.yml builds every site, deploys
the ten product builds to staged refs, promotes their gh-pages branches with
lease protection, then deploys the apex last. Promotion or apex failures roll
the product refs back without overwriting a ref changed by another publisher.
Subdomain pushes require NULLMENU_DEPLOY_TOKEN with contents: write on the
product repositories.
nullclaw.io and nullhub.io cannot return real cross-domain 308 responses
from GitHub Pages. pnpm build:redirects therefore produces Cloudflare Pages
workers and equivalent Vercel rules. To activate the workflow deploys:
- Create Cloudflare Pages projects named
nullclaw-io-redirectandnullhub-io-redirect. - Add repository secrets
CLOUDFLARE_API_TOKENandCLOUDFLARE_ACCOUNT_ID; the token needs Pages edit access. - Bind
nullclaw.ioandnullhub.io(including the desiredwwwaliases) to those projects and remove their GitHub Pages custom-domain bindings. - Verify with
curl -Ithat representative legacy paths return308and the expectedLocationheader.
Without both secrets the legacy job intentionally reports that it is inactive; the generated bundles are still validated in CI.
Download recommendations are pinned to the tags and SHA-256 values in
src/lib/content/release-digests.json. When intentionally updating a product
version, update the site registry and regenerate the manifest from the published
assets:
node scripts/update-release-digests.js --generate
pnpm test:release
pnpm test:release:networkThe weekly workflow streams and re-hashes all pinned assets; it does not adopt a new tag automatically.
MIT — see LICENSE. Bundled fonts are OFL-licensed (attribution).