Docs site workflow
Docs site workflow
Section titled “Docs site workflow”Tandem documentation uses two directories:
docs/is the canonical Markdown source.site/is the Astro Starlight project that renders and builds the static site.
Do not edit generated Markdown copies under site/src/content/docs/. Run the sync step after changing docs/.
Runtime and package manager policy
Section titled “Runtime and package manager policy”The docs site should use a supported even-numbered Node.js LTS runtime, not an arbitrary older pin. The current Astro/Starlight dependency set resolves Astro 7.0.3, whose published engines require Node.js >=22.12.0. Astro’s install docs also state that Astro requires Node.js v22.12.0 or higher and does not support odd-numbered Node.js releases. Node’s release policy says production use should stay on Active LTS or Maintenance LTS lines; as of 2026-06-30, Node 20 is EOL, while Node 22 and Node 24 are LTS.
The GitHub Pages workflow and local shortcuts read site/.node-version, currently 24. Node 24 is the current LTS line and satisfies Astro’s >=22.12.0 requirement without pinning to an obsolete or odd-numbered release. Node 22 would also satisfy the minimum, but it is already a Maintenance LTS line; prefer Node 24 for the deployment workflow unless a compatibility issue appears.
Use Bun for docs-site dependency management and script execution. The site has site/bun.lock; use bun install --frozen-lockfile when validating the committed lockfile. Keep site/package.json package-manager metadata aligned with the Bun version used to generate the lockfile. Bun is the default package manager per decision-2. Preserve an npm fallback only as a documented exception that records what Bun avenues were tried, why they failed, and what condition would allow revisiting the exception. The GitHub Pages workflow and just shortcuts install from bun.lock, run docs scripts with Bun, and keep the build entrypoint in CI before link validation.
Upstream references:
- Astro install docs: https://docs.astro.build/en/install-and-setup/
- Node.js release policy: https://nodejs.org/en/about/previous-releases
- Bun package manager install docs: https://bun.com/docs/pm/cli/install
Standalone Verdigris theme
Section titled “Standalone Verdigris theme”The docs site uses a standalone vendored Verdigris theme rather than a Starlight theme package. This keeps Astro 7/Starlight 0.41 compatibility, avoids peer-dependency drift from third-party theme packages, and makes the theme easy to review or vendor elsewhere.
Theme ownership is intentionally scoped to the site project:
site/astro.config.mjswires StarlightcustomCsstosite/src/styles/verdigris.cssand loads paired Expressive Code themes withExpressiveCodeTheme.fromJSONString(...).site/src/styles/verdigris.cssdefines the Verdigris palette, maps it to Starlight color roles, and styles headings, links, badges/tags, cards, callouts, sidebars, pagination, inline code, and Expressive Code frames.site/src/styles/shiki/verdigris-dark.jsoncandsite/src/styles/shiki/verdigris-light.jsoncprovide syntax highlighting themes whose UI chrome is synchronized with Starlight viauseStarlightUiThemeColors: true.- Expressive Code external stylesheet emission is disabled in the Starlight config so generated code blocks remain self-contained and do not point at stale hashed
ec.*.cssassets after theme changes. site/scripts/sync-docs.mjsclears Astro’s generated.astro/content cache before syncing Markdown, and the dev/build scripts pass Astro--force, so code-fence HTML is regenerated when theme or Expressive Code settings change.docs/guides/theme-tester.mdis the canonical visual maintenance page for exercising headings, links, code blocks, asides, cards, tags, lists, and tables.site/src/styles/README.mdis the vendoring boundary note for future packaging work.
Do not add starlight-theme-gruvbox, downgrade Astro/Starlight, or introduce another theme package unless that trade-off is explicitly approved. If the Verdigris theme is later published as a reusable package, keep this local CSS/Shiki asset boundary as the source to extract from and preserve any third-party license notices for newly vendored assets.
Relevant theme references:
- Starlight CSS customization: https://starlight.astro.build/guides/css-and-tailwind/
- Expressive Code themes: https://expressive-code.com/guides/themes/
- Starlight themes catalog: https://starlight.astro.build/resources/themes/
Install dependencies
Section titled “Install dependencies”From the repository root with Node.js 24 active (see site/.node-version):
cd sitebun installPreview locally
Section titled “Preview locally”cd sitebun run devThe predev hook syncs ../docs/ into Starlight before the dev server starts. The sync script and Astro --force flag clear generated content caches so code blocks pick up theme changes.
Build static output
Section titled “Build static output”just site-buildThe shortcut mirrors the GitHub Pages workflow’s install and build phase with bun install --frozen-lockfile, then bun run build; the prebuild hook runs bun run sync:docs, and Astro writes static output to site/dist/.
For the full local quality gate from inside site/, run:
bun run check:docscheck:docs builds the site and then runs the internal link checker against site/dist/.
Link check built output
Section titled “Link check built output”cd sitebun run buildbun run check:linkscheck:links validates local links, assets, and fragments in built HTML. It intentionally skips external URLs so docs CI does not fail because of transient remote outages or bot-blocking. Use manual browser checks or an external URL checker when changing outbound links that need extra scrutiny.
Manual sync
Section titled “Manual sync”cd sitebun run sync:docsUse this when you want to inspect the generated Starlight content before previewing or building.
Docs update checklist
Section titled “Docs update checklist”- Edit canonical Markdown under
docs/; never edit generated copies insite/src/content/docs/. - Update
site/astro.config.mjsnavigation when pages are added, removed, renamed, or moved. - Use
cd site && bun run devfor local preview. Thepredevhook syncs source docs first. - Use
cd site && bun run sync:docsonly when you need to inspect the generated Starlight content collection without starting Astro. - Before review, run
cd site && bun run check:docs. If dependencies changed, runbun install --frozen-lockfilefirst. - Check
git status --short --ignored site/src/content/docs: copied Markdown should be ignored, and only.gitignoreplusREADME.txtshould be tracked in that generated tree.
Maintenance notes
Section titled “Maintenance notes”- Commit source changes under
docs/and site tooling changes undersite/. - Do not commit
site/dist/,site/.astro/, orsite/node_modules/. - Keep generated
site/src/content/docs/**/*.mdout of version control; it exists only to bridge canonical docs into Starlight. The nested.gitignoreignores copied Markdown while allowing the tracked.gitignoreandREADME.txtnotice.
GitHub Pages deployment
Section titled “GitHub Pages deployment”The workflow .github/workflows/docs.yml builds the Starlight site with Node from site/.node-version, installs Bun with oven-sh/setup-bun, runs bun install --frozen-lockfile, runs bun run build, checks built internal links with bun run check:links, and deploys site/dist/ to GitHub Pages on pushes to main or manual dispatch. Pull requests run the build, link check, and upload step but skip deployment.
Production docs URL: https://trytandem.dev/. The Astro config uses site: 'https://trytandem.dev' and base: '/' so generated links and assets target the custom-domain root. The GitHub project Pages URL remains https://algorant.github.io/tandem/ and should redirect to the custom domain once GitHub Pages accepts the domain.
Repository setup required in GitHub:
- Open Settings → Pages.
- Set Build and deployment → Source to GitHub Actions.
- Set Custom domain to
trytandem.dev. - After DNS resolves and GitHub provisions the certificate, enable Enforce HTTPS.
- Ensure Actions are enabled for the repository and the
github-pagesenvironment can deploy.
Useful gh checks:
gh api repos/Algorant/tandem/pages \ --jq '{html_url, cname, https_enforced, build_type, source, https_certificate}'
gh api repos/Algorant/tandem/pages/healthIf the custom domain needs to be set from the CLI:
gh api --method PUT repos/Algorant/tandem/pages -f cname=trytandem.dev# Retry after DNS/certificate provisioning if GitHub reports that no certificate exists yet.gh api --method PUT repos/Algorant/tandem/pages -F https_enforced=trueDNS records for Namecheap Advanced DNS:
| Type | Host | Value |
|---|---|---|
| A | @ |
185.199.108.153 |
| A | @ |
185.199.109.153 |
| A | @ |
185.199.110.153 |
| A | @ |
185.199.111.153 |
| AAAA | @ |
2606:50c0:8000::153 |
| AAAA | @ |
2606:50c0:8001::153 |
| AAAA | @ |
2606:50c0:8002::153 |
| AAAA | @ |
2606:50c0:8003::153 |
| CNAME | www |
algorant.github.io |
Remove Namecheap parking/default @ and www records before adding the GitHub Pages records, do not add wildcard records, and allow up to 24 hours for DNS and certificate propagation. site/public/CNAME records the intended custom domain in the built artifact; for GitHub Actions Pages, the repository Pages setting is still the authority.
Launch verification:
dig trytandem.dev +noall +answer -t Adig trytandem.dev +noall +answer -t AAAAdig www.trytandem.dev +noall +answer -t CNAMEcurl -I https://trytandem.dev/curl -I https://www.trytandem.dev/curl -I https://algorant.github.io/tandem/