Migrate docs to Astro Starlight — Phase 1: scaffold, routing and theme - #13
Merged
Conversation
Brief and hard rules for moving docs.opendialog.ai from GitBook to Astro Starlight on Cloudflare Workers static assets. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Routes come from a page's position in the SUMMARY.md nav tree, not from its file path. Four pages sit on disk somewhere other than their nav position; path-based derivation puts them at URLs that 404 on the live site. Nav-based derivation covers all 204 pages with no special cases. Snapshot the live sitemap and llms.txt into reference/ as the acceptance oracle, since they disappear when GitBook is switched off. scripts/routes.mjs writes route-map.json and exits non-zero on any divergence from the snapshot. 204 derived, 204 live, 0 unreachable. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Scanned all 11 .mdx candidates for braces surviving outside code fences: one line, caused by misplaced backticks in the source. Dropping LinkCard would take .mdx from 11 files to 2 rather than zero, since Steps and CardGrid force it regardless. Keeping LinkCard. convert.mjs will escape bare braces in prose when emitting .mdx. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Astro 7.1.5 and Starlight 0.41.5, static build with no Cloudflare adapter. Brand colours and fonts taken from opendialog.ai: accent #0023ff, grey ramp shifted onto the blue-tinted brand greys while keeping Starlight's contrast-tuned lightness values. Inter and Fragment Mono are self-hosted via Fontsource, so the build makes no external font requests. src/content/docs holds four hand-converted pages for the Phase 1 gate only. convert.mjs must clear that directory before writing. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Every live GitBook URL is the no-trailing-slash form and returns 200 there. Cloudflare's default html_handling answered those with a 307 to the slashed path, putting a temporary redirect in front of all 204 URLs and changing the canonical shape. drop-trailing-slash serves /foo from /foo/index.html directly, and Astro's trailingSlash: never keeps internal links and canonical URLs in the same shape so navigation does not redirect the other way. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Captures matched viewports of docs.opendialog.ai and the preview deployment for side-by-side review. Phase 4 needs this for the top 30 pages by traffic; pass those in with --paths. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Render the frontmatter description under the page title. GitBook shows it as lead text; Starlight uses it only for meta description, so 71 pages were dropping content the reader can currently see. Use the transparent brand mark the GitBook site serves rather than the marketing favicon, which is the same mark on a blue tile and read as an app icon. Mark the current sidebar entry with weight and colour instead of Starlight's solid accent fill. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Phase 1 budgets brand tokens only; matching GitBook's layout chrome means component overrides, which had no home in the plan. Runs after assets, the first point where the site is comparable, and before verification, whose gate is human sign-off on a visual comparison. Verification and cutover become phases 5 and 6. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Deploying with
|
| Status | Name | Latest Commit | Updated (UTC) |
|---|---|---|---|
| ❌ Deployment failed View logs |
opendialog-docs | caee0ed | Jul 29 2026, 11:54 AM |
There was a problem hiding this comment.
Pull request overview
Phase 1 scaffold for migrating docs.opendialog.ai from GitBook to an Astro Starlight static site deployed on Cloudflare Workers (assets-only), including initial branding, routing parity groundwork, and committed reference snapshots to preserve URL equivalence.
Changes:
- Adds Astro + Starlight project scaffolding/config (TypeScript config, Starlight content collection, site config, and dependencies) plus OpenDialog theme tokens and a
PageTitleoverride to render frontmatterdescription. - Establishes Cloudflare Workers static-assets deployment configuration (
wrangler.jsonc) with explicit no-trailing-slash handling and custom 404 behavior. - Introduces route derivation/verification groundwork (
scripts/routes.mjs+ committedroute-map.json) and commits live-site reference snapshots (reference/), plus a Playwright screenshot utility for visual parity work.
Reviewed changes
Copilot reviewed 19 out of 24 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| wrangler.jsonc | Configures Workers static assets deployment, including trailing-slash and 404 handling. |
| tsconfig.json | Enables strict Astro TypeScript config and excludes build output. |
| src/styles/custom.css | Defines OpenDialog brand tokens (colors/fonts) and small Starlight style overrides. |
| src/content/docs/tutorials/ai-agent-creation-overview/index.mdx | Phase 1 placeholder content page using Starlight <Steps>. |
| src/content/docs/index.md | Phase 1 placeholder introduction page for the preview site. |
| src/content/docs/getting-started-1/getting-ready/index.md | Phase 1 placeholder content page for the preview site. |
| src/content/docs/core-concepts/the-opendialog-model/index.mdx | Phase 1 placeholder content page using Starlight components. |
| src/content.config.ts | Configures Starlight docs collection loader/schema. |
| src/components/PageTitle.astro | Overrides Starlight page title area to render description under the H1. |
| scripts/screenshots.mjs | Adds Playwright script to capture live vs preview screenshots for parity checks. |
| scripts/routes.mjs | Derives routes from source/SUMMARY.md and validates against committed sitemap snapshot. |
| route-map.json | Committed derived mapping of source paths to live URLs/targets for routing parity work. |
| reference/sitemap.xml | Committed snapshot of the live sitemap index (acceptance oracle input). |
| reference/sitemap-pages.xml | Committed snapshot of live page URLs (204) for route parity verification. |
| reference/llms.txt | Committed snapshot of live llms.txt for reference/acceptance purposes. |
| package.json | Adds Astro/Starlight/font deps and Playwright dev dependency with basic scripts. |
| MIGRATION-NOTES.md | Records decisions/anomalies and reconciled counts for the migration plan. |
| MIGRATION-BRIEF.md | Adds the migration brief/spec (phases, rules, expected counts, acceptance criteria). |
| CLAUDE.md | Adds standing rules/gotchas for the migration workflow and constraints. |
| astro.config.mjs | Configures Starlight site settings, branding, sidebar placeholder, and trailingSlash behavior. |
| .gitignore | Ignores generated/build artifacts and the git-ignored source/ input directory. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Comment on lines
+24
to
+27
| const argOf = (name, fallback) => { | ||
| const i = args.indexOf(`--${name}`); | ||
| return i === -1 ? fallback : args[i + 1]; | ||
| }; |
| ## Hard rules | ||
|
|
||
| 1. **`documentation` branch is read-only.** GitBook syncs to it bidirectionally. Writing to it corrupts the live site. Work on a feature branch. | ||
| 2. **Never hand-edit files in `src/content/docs/`.** They are generated. Found a bug? Fix `scripts/convert.mjs` and re-run. A manual edit is silently destroyed on the next run and creates a bug that reappears at cutover. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
FEATURE
Phase 1 of moving docs.opendialog.ai off GitBook onto Astro Starlight, deployed to Cloudflare Workers static assets. Scaffolds the site with OpenDialog branding, establishes the URL routing model against the live sitemap, and deploys a working preview. No content is converted yet — that is Phase 2.
Docs
Jira - none. This is infrastructure migration work with no ticket; branch is named descriptively per the create-pr skill's no-ticket path.
Brief and standing rules are in
MIGRATION-BRIEF.mdandCLAUDE.md. Decisions and anomalies are logged inMIGRATION-NOTES.md.Preview: https://opendialog-docs.opendialog.workers.dev
Solution overview
Current behavior
Docs are served by GitBook from the
documentationbranch, which GitBook syncs bidirectionally. 204 published pages, 1,589 assets weighing 541 MB.mainheld a single emptyREADME.md.Approach in this PR
Routing is derived from nav position, not file paths. The brief assumed URLs follow the directory structure with "a handful of quirks" patched by redirects. They do not — GitBook routes by position in the
SUMMARY.mdnav tree. Path-based derivation scores 200 of 204; nav-based scores 204 of 204 with no exceptions. The four failures are pages filed on disk away from their nav home, and their path-derived URLs return 404 on the live site, so no redirects are owed.scripts/routes.mjsemitsroute-map.jsonand exits non-zero on any divergence from the committed sitemap snapshot.Trailing slashes. Cloudflare's default
html_handlinganswered no-slash paths with a 307 to the slashed variant. Every live GitBook URL is the no-slash form and returns 200, so the default would have put a temporary redirect in front of all 204 URLs — Google does not consolidate ranking signals through a 307, and it changes the canonical shape, making any post-cutover traffic drop impossible to attribute. Fixed withdrop-trailing-slashplus Astro'strailingSlash: 'never'.Reference data is committed, not fetched.
reference/holds snapshots of the live sitemap andllms.txt. They are the acceptance oracle and they disappear when GitBook is switched off. Notesitemap.xmlis an index; the 204 real URLs are insitemap-pages.xml. A verifier parsing the obvious file finds one entry and reports a false pass.Branding is taken from opendialog.ai rather than invented: accent
#0023ff, grey ramp shifted onto the brand's blue-tinted greys while keeping Starlight's contrast-tuned lightness values. Inter and Fragment Mono are self-hosted via Fontsource, so the build makes zero external font requests.Frontmatter
descriptionis rendered under the page title via aPageTitleoverride. GitBook shows it as lead text; Starlight uses it only for<meta name="description">, so 71 pages would have silently dropped visible content.Two corrections to the brief's figures are recorded in
MIGRATION-NOTES.md: there are 204 live URLs, not ~131 (that is thellms.txtnav count), and a look-and-feel phase has been added as Phase 4, moving Verification and Cutover to 5 and 6.Breaking changes
None. Nothing user-facing changes until DNS is repointed at cutover, which is a manual step Pat owns.
Dependencies
main.documentationmust be excluded from build triggers — GitBook writes to it continuously and it has nopackage.json, so every sync would fire a failing build.src/content/docs/currently holds four hand-written placeholder pages for the Phase 1 gate.convert.mjsmust clear that directory wholesale before writing.ffmpegis required for Phase 3 to re-encode a 28 MB GIF that exceeds Cloudflare's 25 MiB per-file cap. Not currently installed.Artifacts
Screenshots -
scripts/screenshots.mjscaptures matched viewports of the live site and the preview for side-by-side comparison.