Skip to content

Building & publishing the docs site

This documentation site is built from ./docs (plus README.md) with VitePress, driven by the BoB docs-site skill. The engine workspace lives under .docs-site/ and is generated (gitignored) — you never edit it by hand. Everything you commit stays in docs/ and docs-site.json.

Prerequisites

  • Node 20+ (VitePress builds fine on Node 22).
  • No Cloudflare account or external hostname is needed for local build/preview.

Preview locally (hot reload)

sh
/docs-site dev

Or, from a plain terminal:

sh
~/.claude/scripts/docs-site/dev.sh

This starts the VitePress dev server with hot reload on the project's docs port (http://localhost:6653 — the app's dev port +3). Edits under docs/ refresh live. Add --print-port to see the resolved port without starting the server.

Build the static site

sh
/docs-site build

Or:

sh
~/.claude/scripts/docs-site/build.sh

This syncs docs/ into the engine workspace and emits flat static HTML to .docs-site/public/. A successful run ends with build complete -> …/.docs-site/public.

Clean

sh
/docs-site clean          # drop build output, keep installed deps
/docs-site clean --hard   # drop the whole .docs-site/ workspace

Authoring gotcha: angle brackets in prose

VitePress passes non-fenced Markdown to the Vue compiler, so a bare <Something> in prose (e.g. a placeholder like <Entity>) is read as an unclosed HTML/component tag and fails the build. Wrap such placeholders in inline code — `<Entity>` — or escape them (&lt;Entity&gt;). Inside fenced code blocks they are safe.

Refreshing walkthrough screenshots

The getting-started walkthrough embeds screenshots of the admin. They're generated by a committed script, so they can be refreshed when the UI changes:

sh
dev-up                  # local app running + seeded
pnpm docs:screenshots   # re-capture into docs/getting-started/images/first-track/

The script (scripts/docs-screenshots/capture-first-track.mjs) drives each screen with Playwright and writes one PNG per step. Set DOCS_BASE_URL if your dev server isn't on http://localhost:6650.

Publishing

The public host is docs.nanaselect.iwpi.com — POC-only (like the app's nanaselect.iwpi.com, see POC access), gated by the same Cloudflare Access application/policy that covers the app, so one allowlist admits reviewers to both. Until published, the hostname serves the local VitePress dev server over the cloudflared tunnel (already Access-gated) — publishing replaces that laptop dependency with Cloudflare Pages.

Precondition — gate pages.dev before the FIRST deploy. Any deploy (manual /docs-site deploy included) self-provisions the Pages project and makes the docs publicly reachable at paulirv-nanaselect-docs.pages.dev, which the hostname's Access app does not cover. Enable Access on the Pages project's pages.dev domain immediately at creation (step 3 below) — never leave a deploy standing ungated. (Learned 2026-07-15: an ungated first deploy had to be rolled back; the full cutover is tracked in #1436.)

The repeatable publish path is CI: .github/workflows/docs-deploy.yml builds, gate-checks, and deploys to the Cloudflare Pages project paulirv-nanaselect-docs on every push to main that touches docs/, README.md, CLAUDE.md, or docs-site.json (PRs get preview deploys with a sticky comment). Deploy config lives in docs-site.json. A one-off manual publish is also available: /docs-site deploy.

CI deploying is off until three human-owned repo settings exist (build and doc-drift gate run regardless, so breakage is still caught):

  1. Repo secret CLOUDFLARE_API_TOKEN — a token with Pages:Edit on the paul@iwpi.com account.
  2. Repo secret CLOUDFLARE_ACCOUNT_ID — the account UUID (in wrangler.jsonc comments).
  3. Repo variable DOCS_SITE_DEPLOY_ENABLED = true.

Then, to move the hostname from the tunnel to Pages (order matters, mirroring the app-host flip in POC access):

  1. Delete the docs.nanaselect.iwpi.com CNAME to the tunnel (iwpi.com zone).
  2. In the Pages project, add docs.nanaselect.iwpi.com as a custom domain (Cloudflare creates the proxied record in the zone; the existing Access app keeps gating the hostname).
  3. Gate the pages.dev URL too: paulirv-nanaselect-docs.pages.dev serves the same content and is NOT covered by the hostname's Access app — in Zero Trust, enable Access on the Pages project's pages.dev domain (Cloudflare offers this as a one-click option on the Pages project) or add it to the Access application. Without this the "gated" docs are public at the pages.dev URL.
  4. Verify: anonymous curl -sI https://docs.nanaselect.iwpi.com → 302 to iwpi.cloudflareaccess.com; OTP login → docs render; the pages.dev URL also 302s.