Skip to content

feat(site): migrate landing page and public docs to Nimbus - #60

Merged
edheltzel merged 20 commits into
masterfrom
eh/atl-nimbus-migrate-01-doskills-site-513c
Nov 6, 2026
Merged

edheltzel merged 20 commits into
masterfrom
eh/atl-nimbus-migrate-01-doskills-site-513c

Conversation

@edheltzel

@edheltzel edheltzel commented Nov 5, 2026 •

Copy link
Copy Markdown
Owner

Intent

Migrate edheltzel/doskills-site into edheltzel/Do-Skills under site/, using Nimbus (@cloudflare/nimbus-docs), continuing the existing Nimbus migration branch eh/atl-nimbus-migrate-01-doskills-site-513c (PR #60) rather than a competing implementation.

User requirements: ONE Nimbus/Astro static build with the existing landing page at / and public documentation. Preserve the current design, artwork, content, installation instructions, and useful URLs (/, /docs/, /docs/do-grit/, /og.png, /favicon.svg, /loop/*, sitemap). Use Do-Skills/docs/global/** and docs/project/** as canonical sources consumed at build time (Nimbus git source with repo ".." at the build commit), not independently maintained copies. Keep docs/plans, handoffs, and agent-only material unpublished. Pin compatible dependencies (nimbus-docs 0.19.3 exact, astro 7.3.3 as in the Nimbus template-empty reference, lockfile) and Node >= 22.12 (.nvmrc 22.12.0, engines). Static output. Keep site tooling isolated in site/ (own package.json/lockfile, own CI workflow .github/workflows/site.yml) from the repo's skill tooling.

Decisions in this round: fix Pullfrog's finding that repo-relative directory links 404 by a Satteri hast plugin (site/src/lib/repo-links.ts) that sends folders under docs/{global,project} to anchored docs hub sections and other repo paths to GitHub; canonical docs keep repo-relative links per .agents/writing-docs.md. The user explicitly accepted that the generated Markdown outputs (.md/.mdx/llms-full.txt) keep those 3 directory links as written (Nimbus documented behavior, no hook) - do not edit the canonical docs to absolute URLs and do not post-process dist. Added a built-output link checker (HTML only), ported the old site's contrast/flash/install-box checks unchanged, derived landing skill counts from skills/ at build (old hard-coded counts were stale), restored the install-guide CTA to the README install section as on the old site, removed the og.png route shadowed by public/og.png. Added docs/plans/2026-11-06-doskills-pages-cutover.md: Cloudflare Pages cannot change a project's source repo (verified with a scratch project; PATCH ignored), so production moves to a new Pages project "doskills" (root site, npm run build, dist, NODE_VERSION 22.12.0, SITE_URL) with an exact domain cutover and rollback. No production or Cloudflare changes happen in this PR; merge and cutover wait for explicit user approval.

Round 2 context: the previous gate run (01M6RYF33YTJXSM7WPGG7TCRFN) failed in Lint with "daemon shutting down" after Review/Test/Document. Because this is a GitButler workspace (no axi sync --recover), its review and document fixes were re-applied as focused commits on the branch (template cleanup, shared theme key, sidebar ancestors, rendered contrast check, HEAD-only docs ref, docs). One deliberate change from that run: its npm overrides forced Astro's own pinned @astrojs/markdown-satteri (0.4.1 -> 0.4.3) and unifont (~0.7.5 -> 0.7.4) outside their declared ranges to fit Node 22.12.0; that was replaced by pinning Node 22.23.4 (the highest engine any locked package declares, still satisfying the user's "at least 22.12"), with the original lockfile and no overrides. The only remaining engine mismatch is the optional @img/sharp-win32-ia32 binary, which declares ^20.9.0 and never installs on Linux or macOS. Further removal of Nimbus template features (ImageZoom, API/version scaffolding, Banner, WebMCP, per-page OG cards, robots Content-Signal) is out of scope for this migration: they come from the Nimbus reference template and are kept so nimbus-docs upgrade/diff tooling stays aligned. The lint:docs scripts were removed because Nimbus lint reads only .mdx and this site has none.

Round 3 context: after run 01M6S1DJ0F3BN0TKT6K1C9GMGT pushed and CI passed (site check, Cloudflare Pages preview, pullfrog), the replacement Pages project "doskills" was created in Cloudflare (production deployments off, previews only for this branch; no domain, no production change). Its hostname is doskills.pages.dev. This round only updates docs/plans/2026-11-06-doskills-pages-cutover.md to name that real hostname and route every Cloudflare API call through cf(), which fails on HTTP errors or success:false (curl -f plus jq -e .success).

What Changed

  • Consolidate the landing page, artwork, installation commands, and compatibility routes into one static Nimbus/Astro build under site/.
  • Load canonical public docs from the build commit, exclude internal material, and add docs navigation, shared themes, Markdown/LLM endpoints, and HTML directory-link rewriting.
  • Pin site dependencies and Node, add dedicated site CI checks, and document the doskills.pages.dev cutover and rollback with API failure checks.

Risk Assessment

✅ Low: The static migration respects the amended requirements and recorded decisions, with no substantiated material defects found in the source or revised rollback.

Testing

The pinned-runtime build, targeted checks, corrected live browser flows and screenshot review passed; an extended paint check filled gaps in the baseline flash check, runbook commands passed against a disposable API, and real Cloudflare cutover remains intentionally deferred. Disposable processes and files were removed.

  • Live validation: ✅ go - 9 of 10 scenarios driven live against the product
Scenario Result Live Evidence
Build on Node 22.23.4 and serve the generated static site ✅ pass live build.log; live-results.json
View landing artwork, installation commands, current skill totals and the README install-guide link ✅ pass live landing-light-desktop.png; landing-dark-desktop.png; live-results.json
Open preserved URLs, original assets and sitemap; receive HTTP 404 for a missing page ✅ pass live live-results.json; do-grit-compatibility.png; not-found.png
Read canonical public docs while plans and agent material remain unavailable ✅ pass live live-results.json; docs-lfg-desktop.png
Follow directory links to docs hub anchors and repository links to GitHub; retain an authored Markdown directory link ✅ pass live directory-link-hub-anchor.png; live-results.json; links.log
Filter sidebar groups, retain visible ancestors, reject unmatched terms and restore navigation after clearing ✅ pass live sidebar-core-filter.png; live-results.json
Search for LFG, open it by keyboard and receive no results for an unmatched query without exposing private plans ✅ pass live search-lfg.png; live-results.json
Persist themes across landing, docs and reload; preserve rendered palettes and avoid wrong-theme painted frames ✅ pass live docs-dark-desktop.png; contrast.log; paint-results.json; live-results.json
Use mobile navigation and section controls in portrait and landscape without horizontal page overflow ✅ pass live docs-mobile-navigation.png; docs-mobile-portrait-viewport.png; docs-mobile-landscape.png; install-box.log
Perform the documented Cloudflare cutover and rollback in a real account ⏸️ untested no Executed the actual Bash commands with curl/jq against a disposable local HTTP API, covering interrupted rollback and HTTP/API failures. Real Cloudflare mutations are explicitly deferred by this PR. L…
Evidence: Visual evidence report
<!doctype html><html lang="en"><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><title>Nimbus migration test evidence</title><style>body{font:16px/1.5 system-ui,sans-serif;color:#172025;background:#f4f4f2;margin:0}main{max-width:1200px;margin:auto;padding:36px 24px}h1{font-size:36px;margin:0 0 12px}h2{font-size:23px;margin:10px 0}p{max-width:900px}figure{margin:22px 0;background:white;padding:20px;border:1px solid #ddd;border-radius:12px}img{width:100%;max-height:850px;object-fit:contain;object-position:top;display:block;background:#fafafa}figcaption{margin:10px 0;color:#52606b}li{padding:3px 0}a{color:#795400}.pass{color:#166534}code{font-size:14px}</style><main><h1>Nimbus migration test evidence</h1><p>Commit <code>94241c10af43ad2cf59a98664efb3f44848a01dd</code>. Production build completed on Node 22.23.4. These screenshots show the real static build served locally at 127.0.0.1:4327.</p><ul>
<li class="pass">PASS: Landing preserves artwork, installation commands, dynamic skill totals and install guide</li>
<li class="pass">PASS: Useful URLs, original assets, sitemap and 404 responses remain available</li>
<li class="pass">PASS: Canonical public Markdown renders as docs while plans and agent material stay unpublished</li>
<li class="pass">PASS: Repo-relative directory links open docs hub anchors and other repo links target GitHub</li>
<li class="pass">PASS: Sidebar group filters reveal ancestor groups, clear correctly and show no false matches</li>
<li class="pass">PASS: Search finds a public skill, opens it by keyboard and excludes private plans</li>
<li class="pass">PASS: Saved light and dark choices persist across landing, docs, reload and return navigation</li>
<li class="pass">PASS: Mobile layout fits portrait and landscape; navigation, section selection and scrolling work</li>
</ul><p><a href="live-results.json">Full browser results</a> · <a href="build.log">Static build</a> · <a href="contrast.log">Rendered contrast</a> · <a href="paint-results.json">Paint-observed themes</a> · <a href="runbook-api-results.json">Isolated runbook execution</a></p><p>The initial browser driver made incorrect assumptions about hidden H1s, light-mode attributes and tokenized search queries. The corrected final driver passes. The baseline flash check missed first-paint data in two cases; the extended check observed 28–30 painted frames per case with zero wrong-theme frames. The Cloudflare shell snippets passed against a disposable local API, including partial cutover recovery and API/HTTP failures. This is simulation evidence, not a live Cloudflare cutover. No production, DNS or account state was changed.</p>
<figure><h2>Landing, light theme</h2><figcaption>Original canvas artwork, installation commands, live totals and README install-guide link.</figcaption><a href="landing-light-desktop.png"><img loading="lazy" src="landing-light-desktop.png" alt="Landing, light theme"></a></figure>
<figure><h2>Landing, dark theme</h2><figcaption>The saved dark choice carries into the docs.</figcaption><a href="landing-dark-desktop.png"><img loading="lazy" src="landing-dark-desktop.png" alt="Landing, dark theme"></a></figure>
<figure><h2>Landing at 390px</h2><figcaption>The six-step workflow restacks; installation commands remain readable.</figcaption><a href="landing-mobile.png"><img loading="lazy" src="landing-mobile.png" alt="Landing at 390px"></a></figure>
<figure><h2>Public docs hub</h2><figcaption>Public Global and Project collections from canonical Markdown.</figcaption><a href="docs-hub-desktop.png"><img loading="lazy" src="docs-hub-desktop.png" alt="Public docs hub"></a></figure>
<figure><h2>LFG documentation</h2><figcaption>Quickstart code, navigation and table of contents.</figcaption><a href="docs-lfg-desktop.png"><img loading="lazy" src="docs-lfg-desktop.png" alt="LFG documentation"></a></figure>
<figure><h2>Documentation, dark theme</h2><figcaption>The shared saved preference applies after navigation and reload.</figcaption><a href="docs-dark-desktop.png"><img loading="lazy" src="docs-dark-desktop.png" alt="Documentation, dark theme"></a></figure>
<figure><h2>Core group filter</h2><figcaption>Its Global ancestor and matching links stay visible.</figcaption><a href="sidebar-core-filter.png"><img loading="lazy" src="sidebar-core-filter.png" alt="Core group filter"></a></figure>
<figure><h2>Search, public result</h2><figcaption>Keyboard selection opens LFG; unmatched queries show no results.</figcaption><a href="search-lfg.png"><img loading="lazy" src="search-lfg.png" alt="Search, public result"></a></figure>
<figure><h2>Directory link destination</h2><figcaption>Repo-relative directory links land on an existing docs hub section.</figcaption><a href="directory-link-hub-anchor.png"><img loading="lazy" src="directory-link-hub-anchor.png" alt="Directory link destination"></a></figure>
<figure><h2>Mobile navigation</h2><figcaption>The drawer contains the same public page tree.</figcaption><a href="docs-mobile-navigation.png"><img loading="lazy" src="docs-mobile-navigation.png" alt="Mobile navigation"></a></figure>
<figure><h2>Mobile section selection</h2><figcaption>The selected section is visible beneath the sticky header.</figcaption><a href="docs-mobile-portrait-viewport.png"><img loading="lazy" src="docs-mobile-portrait-viewport.png" alt="Mobile section selection"></a></figure>
<figure><h2>Landscape section tracking</h2><figcaption>The reading band uses the 390px viewport height and updates after resize.</figcaption><a href="docs-mobile-landscape.png"><img loading="lazy" src="docs-mobile-landscape.png" alt="Landscape section tracking"></a></figure>
<figure><h2>Preserved do-grit URL</h2><figcaption>The old useful URL still points to the skill source.</figcaption><a href="do-grit-compatibility.png"><img loading="lazy" src="do-grit-compatibility.png" alt="Preserved do-grit URL"></a></figure>
<figure><h2>Missing URL</h2><figcaption>The custom not-found page is served with HTTP 404.</figcaption><a href="not-found.png"><img loading="lazy" src="not-found.png" alt="Missing URL"></a></figure>
</main></html>

Landing page

Mobile section navigation

Landscape section tracking

Evidence: Live browser and HTTP results
{
  "origin": "http://127.0.0.1:4327",
  "commit": "94241c10af43ad2cf59a98664efb3f44848a01dd",
  "scenarios": [
    {
      "name": "Landing preserves artwork, installation commands, dynamic skill totals and install guide",
      "result": "pass",
      "live": true,
      "details": {
        "commands": [
          "npx skills add https://github.com/edheltzel/Do-Skills/tree/master/skills/global -g",
          "npx skills add https://github.com/edheltzel/Do-Skills/tree/master/skills/project/<group>",
          "npx skills add https://github.com/edheltzel/Do-Skills/tree/master/skills/global -g",
          "npx skills add https://github.com/edheltzel/Do-Skills/tree/master/skills/project/<group>"
        ],
        "counts": {
          "Skills": 76,
          "Global": 45,
          "Project": 31,
          "Groups": 13
        },
        "images": [
          {
            "src": "/loop/icon-01-d.png",
            "loaded": true
          },
          {
            "src": "/loop/icon-01-l.png",
            "loaded": true
          },
          {
            "src": "/loop/icon-02-d.png",
            "loaded": true
          },
          {
            "src": "/loop/icon-02-l.png",
            "loaded": true
          },
          {
            "src": "/loop/icon-03-d.png",
            "loaded": true
          },
          {
            "src": "/loop/icon-03-l.png",
            "loaded": true
          },
          {
            "src": "/loop/icon-04-d.png",
            "loaded": true
          },
          {
            "src": "/loop/icon-04-l.png",
            "loaded": true
          },
          {
            "src": "/loop/icon-05-d.png",
            "loaded": true
          },
          {
            "src": "/loop/icon-05-l.png",
            "loaded": true
          },
          {
            "src": "/loop/icon-06-d.png",
            "loaded": true
          },
          {
            "src": "/loop/icon-06-l.png",
            "loaded": true
          }
        ],
        "guide": "README.md#installation",
        "navigation": "/ → /docs/"
      }
    },
    {
      "name": "Useful URLs, original assets, sitemap and 404 responses remain available",
      "result": "pass",
      "live": true,
      "details": {
        "statuses": {
          "/": 200,
          "/docs/": 200,
          "/docs": 200,
          "/docs/do-grit/": 200,
          "/docs/do-grit": 200
        },
        "assets": [
          {
            "path": "/og.png",
            "bytes": 91282,
            "sha256": "ce60000bf8883f2a745ffd7932e9ba11ad0c339f75189e8c71044b42886b5b5a"
          },
          {
            "path": "/favicon.svg",
            "bytes": 163,
            "sha256": "56a1585f4b9f1a37c2c48fbf4f8fc34825b168d685d2a958712c9e7a67b05a4e"
          },
          {
            "path": "/favicon.ico",
            "bytes": 2976,
            "sha256": "a329e04cb8629b2632a1ec17a96d1e598e9713af25346dbb8900e826e0f7321e"
          },
          {
            "path": "/loop/icon-01-d.png",
            "bytes": 1540,
            "sha256": "969944ff5bcd015a835174ede6deb6174f9da1770632bf91a833a70ef8825f9b"
          },
          {
            "path": "/loop/icon-01-l.png",
            "bytes": 1560,
            "sha256": "813a8932de860a166f3618ef8e2a864eeaf3abc0d7d2fe562970c8c5e8a1f23a"
          },
          {
            "path": "/loop/icon-02-d.png",
            "bytes": 1414,
            "sha256": "559b714c1994ad46c6e2107436d5c4b18e6c6bc2fa72f0be4550e521369ea772"
          },
          {
            "path": "/loop/icon-02-l.png",
            "bytes": 1420,
            "sha256": "c8510ed474cf131842060436b1363e41b02d7bc69654a3fe182e5ca9055553a9"
          },
          {
            "path": "/loop/icon-03-d.png",
            "bytes": 1641,
            "sha256": "c669320cab096a06881857ea8f24e97b06a26d1d89ca1e1ac113ad77a60bd1a5"
          },
          {
            "path": "/loop/icon-03-l.png",
            "bytes": 1637,
            "sha256": "524fcfff406e670dd2bc41bef838f09f35dc8fce0398767fdc2464fec91fb0ae"
          },
          {
            "path": "/loop/icon-04-d.png",
            "bytes": 1140,
            "sha256": "4f775b538f3e3ed9bda32e6754404b91e1bf080f691a7ddf698da4f6d6e7aad4"
          },
          {
            "path": "/loop/icon-04-l.png",
            "bytes": 1136,
            "sha256": "d51923e09eaa3939909d90080ece9d1d15b47e186955095d3d4b78eefa5914d1"
          },
          {
            "path": "/loop/icon-05-d.png",
            "bytes": 1512,
            "sha256": "fdb3392ba73e51d086d1987b9c715689d63987e59dcbf1b8005cf9504d53dfb1"
          },
          {
            "path": "/loop/icon-05-l.png",
            "bytes": 1539,
            "sha256": "7204e2cc66afd166242719a3d099e1bb3a183b15f1f371eba159ea4972924f28"
          },
          {
            "path": "/loop/icon-06-d.png",
            "bytes": 1183,
            "sha256": "915652e010ad30860e8419bfb81c8cf594a92809f4a89ef63a1e10d959462ecf"
          },
          {
            "path": "/loop/icon-06-l.png",
            "bytes": 1189,
            "sha256": "69e162bda66320a297753c9f5eba694dc5ee5cdd1b153187bcedf14f1f6aa4e7"
          }
        ],
        "sitemap": "/sitemap-index.xml → /sitemap-0.xml",
        "missingStatus": 404
      }
    },
    {
      "name": "Canonical public Markdown renders as docs while plans and agent material stay unpublished",
      "result": "pass",
      "live": true,
      "details": {
        "publicPages": [
          {
            "path": "/project/typescript/parse-dont-validate/",
            "title": "Parse, Don't Validate"
          },
          {
            "path": "/project/typescript/ts-standards/",
            "title": "TypeScript Coding Standards"
          },
          {
            "path": "/project/typescript/typescript-refactoring/",
            "title": "TypeScript Refactoring"
          },
          {
            "path": "/project/typescript/write-typescript/",
            "title": "Pragmatic TypeScript"
          },
          {
            "path": "/project/tooling/create-cli/",
            "title": "CreateCLI"
          },
          {
            "path": "/project/tooling/lean-ts-patterns/",
            "title": "Lean TypeScript Patterns"
          },
          {
            "path": "/project/tooling/perf/",
            "title": "Perf"
          },
          {
            "path": "/project/swift/cleanup-swift/",
            "title": "Cleanup Swift"
          },
          {
            "path": "/project/swift/macos-swift-desktop/",
            "title": "macOS Swift Desktop"
          },
          {
            "path": "/project/swift/review-ios/",
            "title": "iOS Code Review"
          },
          {
            "path": "/project/product/marketing/",
            "title": "Marketing"
          },
          {
            "path": "/project/frontend/astro/",
            "title": "Astro"
          },
          {
            "path": "/project/frontend/cleanup-web/",
            "title": "Web Cleanup Pass"
          },
          {
            "path": "/project/frontend/design-system/",
            "title": "Design Systems"
          },
          {
            "path": "/project/frontend/landing-page/",
            "title": "Landing Page"
          },
          {
            "path": "/project/frontend/modern-css/",
            "title": "Modern CSS"
          },
          {
            "path": "/project/frontend/no-use-effect/",
            "title": "No useEffect"
          },
          {
            "path": "/project/frontend/redesign/",
            "title": "Redesign"
          },
          {
            "path": "/project/frontend/review-frontend/",
            "title": "Frontend Code Review"
          },
          {
            "path": "/project/frontend/ux-flow-plan/",
            "title": "UX Flow Plan"
          },
          {
            "path": "/project/backend/backend/",
            "title": "Backend"
          },
          {
            "path": "/global/workflow/brainstorm/",
            "title": "Brainstorm"
          },
          {
            "path": "/global/workflow/commit/",
            "title": "Commit"
          },
        

... [5078 bytes truncated] ...

re/agent-docs/"
              },
              {
                "text": "ARCHITECTURE.md Generator",
                "href": "/global/core/architecture-md/"
              },
              {
                "text": "Behavioral Testing",
                "href": "/global/core/behavioral-testing/"
              },
              {
                "text": "Code Comments",
                "href": "/global/core/code-comments/"
              },
              {
                "text": "Design Patterns (Gang of Four)",
                "href": "/global/core/design-patterns-gof/"
              },
              {
                "text": "First Principles",
                "href": "/global/core/first-principles/"
              },
              {
                "text": "Humanize",
                "href": "/global/core/humanize/"
              },
              {
                "text": "No Comments",
                "href": "/global/core/no-comments/"
              },
              {
                "text": "Red Team",
                "href": "/global/core/redteam/"
              },
              {
                "text": "Simplify",
                "href": "/global/core/simplify/"
              },
              {
                "text": "Skill Craft",
                "href": "/global/core/skill-craft/"
              }
            ]
          },
          {
            "term": "frontend",
            "links": [
              {
                "text": "Astro",
                "href": "/project/frontend/astro/"
              },
              {
                "text": "Design Systems",
                "href": "/project/frontend/design-system/"
              },
              {
                "text": "Frontend Code Review",
                "href": "/project/frontend/review-frontend/"
              },
              {
                "text": "Landing Page",
                "href": "/project/frontend/landing-page/"
              },
              {
                "text": "Modern CSS",
                "href": "/project/frontend/modern-css/"
              },
              {
                "text": "No useEffect",
                "href": "/project/frontend/no-use-effect/"
              },
              {
                "text": "Redesign",
                "href": "/project/frontend/redesign/"
              },
              {
                "text": "UX Flow Plan",
                "href": "/project/frontend/ux-flow-plan/"
              },
              {
                "text": "Web Cleanup Pass",
                "href": "/project/frontend/cleanup-web/"
              }
            ]
          },
          {
            "term": "workflow",
            "links": [
              {
                "text": "Brainstorm",
                "href": "/global/workflow/brainstorm/"
              },
              {
                "text": "Commit",
                "href": "/global/workflow/commit/"
              },
              {
                "text": "Debug",
                "href": "/global/workflow/debug/"
              },
              {
                "text": "Doc review",
                "href": "/global/workflow/doc-review/"
              },
              {
                "text": "Docs",
                "href": "/global/workflow/docs/"
              },
              {
                "text": "gh-stack",
                "href": "/global/workflow/gh-stack/"
              },
              {
                "text": "Git Safe PR Workflow",
                "href": "/global/workflow/git-safe-pr-workflow/"
              },
              {
                "text": "Git Worktree Management",
                "href": "/global/workflow/git-worktree/"
              },
              {
                "text": "GitHub Projects CLI",
                "href": "/global/workflow/gh-pm/"
              },
              {
                "text": "LFG",
                "href": "/global/workflow/it/"
              },
              {
                "text": "Plan",
                "href": "/global/workflow/plan/"
              },
              {
                "text": "PR Review Triage",
                "href": "/global/workflow/git-pr-review-triage/"
              },
              {
                "text": "README Update",
                "href": "/global/workflow/readme-update/"
              },
              {
                "text": "Technical Writing",
                "href": "/global/workflow/tech-writing/"
              },
              {
                "text": "Work",
                "href": "/global/workflow/work/"
              }
            ]
          }
        ],
        "unmatchedVisibleLinks": 0,
        "clearedVisibleLinks": 52
      }
    },
    {
      "name": "Search finds a public skill, opens it by keyboard and excludes private plans",
      "result": "pass",
      "live": true,
      "details": {
        "query": "LFG",
        "results": "LFG\n\nLFG. LFG. Quickstart: npx skills add edheltzel/Do-Skills --skill=do-it npx skills update do-it Source. What it does. do-it is the LFG runner: one explicit end-to-end ask, no menus, from the request\n\nLFG\nLFG\nWhat it does",
        "opened": "/global/workflow/it/",
        "privatePlanQueryPublicMatches": [
          "/global/workflow/it/",
          "/global/workflow/it/#lfg",
          "/global/workflow/it/#what-it-does",
          "/global/workflow/it/#when-to-reach-for-it",
          "/global/workflow/tech-writing/",
          "/global/workflow/tech-writing/#technical-writing",
          "/global/workflow/tech-writing/#when-to-reach-for-it",
          "/global/workflow/tech-writing/#the-rules-that-do-the-work",
          "/global/content/illo/",
          "/global/content/illo/#illo",
          "/global/content/illo/#what-it-does",
          "/global/content/illo/#when-to-reach-for-it",
          "/global/workflow/git-safe-pr-workflow/",
          "/global/workflow/git-safe-pr-workflow/#git-safe-pr-workflow",
          "/global/workflow/git-safe-pr-workflow/#when-to-reach-for-it",
          "/global/workflow/git-safe-pr-workflow/#the-safe-posture",
          "/project/product/marketing/",
          "/project/product/marketing/#marketing",
          "/project/product/marketing/#what-it-does",
          "/project/product/marketing/#when-to-reach-for-it",
          "/global/workflow/commit/",
          "/global/workflow/commit/#commit",
          "/global/workflow/commit/#what-it-does",
          "/global/workflow/commit/#when-to-reach-for-it",
          "/global/workflow/brainstorm/",
          "/global/workflow/brainstorm/#brainstorm",
          "/global/workflow/brainstorm/#what-it-does",
          "/global/workflow/brainstorm/#when-to-reach-for-it",
          "/global/core/no-comments/",
          "/global/core/no-comments/#no-comments",
          "/global/core/no-comments/#when-to-reach-for-it",
          "/global/core/no-comments/#its-working-if",
          "/global/workflow/work/",
          "/global/workflow/work/#work",
          "/global/workflow/work/#what-it-does",
          "/global/workflow/work/#when-to-reach-for-it",
          "/global/workflow/plan/",
          "/global/workflow/plan/#plan",
          "/global/workflow/plan/#what-it-does",
          "/global/workflow/plan/#when-to-reach-for-it"
        ],
        "unmatchedQuery": "No results found."
      }
    },
    {
      "name": "Saved light and dark choices persist across landing, docs, reload and return navigation",
      "result": "pass",
      "live": true,
      "details": {
        "landingDarkToDocs": "dark",
        "reloadedDocs": "dark",
        "docsLightToLanding": "light",
        "stored": {
          "value": "light",
          "obsolete": null
        }
      }
    },
    {
      "name": "Mobile layout fits portrait and landscape; navigation, section selection and scrolling work",
      "result": "pass",
      "live": true,
      "details": {
        "portrait": "390×844, no horizontal overflow",
        "landscape": "844×390, The run selected while scrolling",
        "resized": "When to reach for it",
        "navigation": "LFG → Behavioral testing",
        "sectionSelection": "the-run"
      }
    }
  ],
  "consoleErrors": []
}
  • Evidence: Paint-observed theme results (local file: ~/.no-mistakes/evidence/01M6S3WC5FZ8BPGA3ZAW1A5EWC/paint-results.json)
  • Evidence: Runbook execution against disposable API (local file: ~/.no-mistakes/evidence/01M6S3WC5FZ8BPGA3ZAW1A5EWC/runbook-api-results.json)
Evidence: Rendered contrast results

> do-skills-site@0.0.1 contrast
> node scripts/contrast.mjs

dark
  ok   text 16.25  --text on --bg
  ok   text 15.08  --text on --s1
  ok   text 13.73  --text on --s2
  ok   text  7.36  --t2 on --bg
  ok   text  6.83  --t2 on --s1
  ok   text  6.22  --t2 on --s2
  ok   text  5.66  --t3 on --bg
  ok   text  5.25  --t3 on --s1
  ok   text  4.78  --t3 on --s2
  ok   text  9.18  --l2 on --bg
  ok   text  8.52  --l2 on --s1
  ok   text  7.75  --l2 on --s2
  ok   text  9.32  --acc on --bg
  ok   text  8.65  --acc on --s1
  ok   text  7.88  --acc on --s2
  ok   text 13.36  --acc2 on --bg
  ok   text 12.40  --acc2 on --s1
  ok   text 11.29  --acc2 on --s2
  ok   text 17.94  --btn-fg on --btn-bg
  ok   text 11.18  --callout on note tint
  ok   text 10.60  --callout on tip tint
  ok   text  8.45  --acc on note tint
  ok   text 11.49  --acc2 on tip tint
  ok   line  9.32  --acc on --bg
  ok   line  8.65  --acc on --s1
  ok   line  7.88  --acc on --s2
  ok   line 13.36  --acc2 on --bg
  ok   line 12.40  --acc2 on --s1
  ok   line 11.29  --acc2 on --s2
  ok   line  4.03  --mid on --bg
  ok   line  3.74  --mid on --s1
  ok   line  3.40  --mid on --s2
  ok   line  8.45  note border on its tint
  ok   line 11.49  tip border on its tint
  hairlines (decorative, not gated): --b1 1.11, --b2 1.22, --b3 1.43, --b4 1.93
  lowest text 4.78 (--t3 on --s2)
  lowest line 3.40 (--mid on --s2)

light
  ok   text 17.31  --text on --bg
  ok   text 18.25  --text on --s1
  ok   text 15.82  --text on --s2
  ok   text  8.12  --t2 on --bg
  ok   text  8.56  --t2 on --s1
  ok   text  7.42  --t2 on --s2
  ok   text  5.85  --t3 on --bg
  ok   text  6.17  --t3 on --s1
  ok   text  5.35  --t3 on --s2
  ok   text  6.32  --l2 on --bg
  ok   text  6.66  --l2 on --s1
  ok   text  5.78  --l2 on --s2
  ok   text  5.42  --acc on --bg
  ok   text  5.72  --acc on --s1
  ok   text  4.96  --acc on --s2
  ok   text 10.86  --acc2 on --bg
  ok   text 11.45  --acc2 on --s1
  ok   text  9.93  --acc2 on --s2
  ok   text 17.31  --btn-fg on --btn-bg
  ok   text 11.65  --callout on note tint
  ok   text 11.15  --callout on tip tint
  ok   text  4.94  --acc on note tint
  ok   text  9.46  --acc2 on tip tint
  ok   line  5.42  --acc on --bg
  ok   line  5.72  --acc on --s1
  ok   line  4.96  --acc on --s2
  ok   line 10.86  --acc2 on --bg
  ok   line 11.45  --acc2 on --s1
  ok   line  9.93  --acc2 on --s2
  ok   line  4.33  --mid on --bg
  ok   line  4.56  --mid on --s1
  ok   line  3.96  --mid on --s2
  ok   line  4.94  note border on its tint
  ok   line  9.46  tip border on its tint
  hairlines (decorative, not gated): --b1 1.17, --b2 1.28, --b3 1.48, --b4 1.93
  lowest text 4.94 (--acc on note tint)
  lowest line 3.96 (--mid on --s2)

dark-nojs
  ok   text 16.25  --text on --bg
  ok   text 15.08  --text on --s1
  ok   text 13.73  --text on --s2
  ok   text  7.36  --t2 on --bg
  ok   text  6.83  --t2 on --s1
  ok   text  6.22  --t2 on --s2
  ok   text  5.66  --t3 on --bg
  ok   text  5.25  --t3 on --s1
  ok   text  4.78  --t3 on --s2
  ok   text  9.18  --l2 on --bg
  ok   text  8.52  --l2 on --s1
  ok   text  7.75  --l2 on --s2
  ok   text  9.32  --acc on --bg
  ok   text  8.65  --acc on --s1
  ok   text  7.88  --acc on --s2
  ok   text 13.36  --acc2 on --bg
  ok   text 12.40  --acc2 on --s1
  ok   text 11.29  --acc2 on --s2
  ok   text 17.94  --btn-fg on --btn-bg
  ok   text 11.18  --callout on note tint
  ok   text 10.60  --callout on tip tint
  ok   text  8.45  --acc on note tint
  ok   text 11.49  --acc2 on tip tint
  ok   line  9.32  --acc on --bg
  ok   line  8.65  --acc on --s1
  ok   line  7.88  --acc on --s2
  ok   line 13.36  --acc2 on --bg
  ok   line 12.40  --acc2 on --s1
  ok   line 11.29  --acc2 on --s2
  ok   line  4.03  --mid on --bg
  ok   line  3.74  --mid on --s1
  ok   line  3.40  --mid on --s2
  ok   line  8.45  note border on its tint
  ok   line 11.49  tip border on its tint
  hairlines (decorative, not gated): --b1 1.11, --b2 1.22, --b3 1.43, --b4 1.93
  lowest text 4.78 (--t3 on --s2)
  lowest line 3.40 (--mid on --s2)

light-nojs
  ok   text 17.31  --text on --bg
  ok   text 18.25  --text on --s1
  ok   text 15.82  --text on --s2
  ok   text  8.12  --t2 on --bg
  ok   text  8.56  --t2 on --s1
  ok   text  7.42  --t2 on --s2
  ok   text  5.85  --t3 on --bg
  ok   text  6.17  --t3 on --s1
  ok   text  5.35  --t3 on --s2
  ok   text  6.32  --l2 on --bg
  ok   text  6.66  --l2 on --s1
  ok   text  5.78  --l2 on --s2
  ok   text  5.42  --acc on --bg
  ok   text  5.72  --acc on --s1
  ok   text  4.96  --acc on --s2
  ok   text 10.86  --acc2 on --bg
  ok   text 11.45  --acc2 on --s1
  ok   text  9.93  --acc2 on --s2
  ok   text 17.31  --btn-fg on --btn-bg
  ok   text 11.65  --callout on note tint
  ok   text 11.15  --callout on tip tint
  ok   text  4.94  --acc on note tint
  ok   text  9.46  --acc2 on tip tint
  ok   line  5.42  --acc on --bg
  ok   line  5.72  --acc on --s1
  ok   line  4.96  --acc on --s2
  ok   line 10.86  --acc2 on --bg
  ok   line 11.45  --acc2 on --s1
  ok   line  9.93  --acc2 on --s2
  ok   line  4.33  --mid on --bg
  ok   line  4.56  --mid on --s1
  ok   line  3.96  --mid on --s2
  ok   line  4.94  note border on its tint
  ok   line  9.46  tip border on its tint
  hairlines (decorative, not gated): --b1 1.17, --b2 1.28, --b3 1.48, --b4 1.93
  lowest text 4.94 (--acc on note tint)
  lowest line 3.96 (--mid on --s2)

PASS

Pipeline

Updates from git push no-mistakes

✅ **Intent** - passed

✅ No issues found.

✅ **Rebase** - passed

✅ No issues found.

🔧 **Review** - 2 issues found → auto-fixed ✅
  • ⚠️ docs/plans/2026-11-06-doskills-pages-cutover.md:97 - If the old-domain deletion at :77 succeeds but the new-domain creation at :78 fails, neither project owns the domain. Rollback then unconditionally deletes the absent new association at :97; its not-found error is fatal under cf() and set -e, preventing restoration at :98–100. Make rollback handle the actual association state, including an already-restored old association at :98 after an interrupted rollback, while retaining checks for unrelated API errors.
  • ⚠️ docs/plans/2026-11-06-doskills-pages-cutover.md:80 - Round three requires “route every Cloudflare API call through cf()”, but this changed command still uses curl ... | jq -r .result.status directly. An HTTP-success response containing success:false prints null and exits successfully. Route this remaining read through the shared validator; cf() at :51 will also need to preserve the validated response so the status can be displayed.

🔧 Fix applied.
✅ Re-checked - no issues remain.

✅ **Test** - passed

✅ No issues found.

  • Live validation: ✅ go - 9 of 10 scenarios driven live against the product
Scenario Result Live Evidence
Build on Node 22.23.4 and serve the generated static site ✅ pass live build.log; live-results.json
View landing artwork, installation commands, current skill totals and the README install-guide link ✅ pass live landing-light-desktop.png; landing-dark-desktop.png; live-results.json
Open preserved URLs, original assets and sitemap; receive HTTP 404 for a missing page ✅ pass live live-results.json; do-grit-compatibility.png; not-found.png
Read canonical public docs while plans and agent material remain unavailable ✅ pass live live-results.json; docs-lfg-desktop.png
Follow directory links to docs hub anchors and repository links to GitHub; retain an authored Markdown directory link ✅ pass live directory-link-hub-anchor.png; live-results.json; links.log
Filter sidebar groups, retain visible ancestors, reject unmatched terms and restore navigation after clearing ✅ pass live sidebar-core-filter.png; live-results.json
Search for LFG, open it by keyboard and receive no results for an unmatched query without exposing private plans ✅ pass live search-lfg.png; live-results.json
Persist themes across landing, docs and reload; preserve rendered palettes and avoid wrong-theme painted frames ✅ pass live docs-dark-desktop.png; contrast.log; paint-results.json; live-results.json
Use mobile navigation and section controls in portrait and landscape without horizontal page overflow ✅ pass live docs-mobile-navigation.png; docs-mobile-portrait-viewport.png; docs-mobile-landscape.png; install-box.log
Perform the documented Cloudflare cutover and rollback in a real account ⏸️ untested no Executed the actual Bash commands with curl/jq against a disposable local HTTP API, covering interrupted rollback and HTTP/API failures. Real Cloudflare mutations are explicitly deferred by this PR. L…
  • git diff 258d4b8fcfaf9f5e0f97c543a8d28eb3aa3eed83 94241c10af43ad2cf59a98664efb3f44848a01dd after GitButler rejected the bare-backed worktree.
  • npm ci --prefix site --no-audit --no-fund; installed disposable workspace-local Node 22.23.4 and Chromium.
  • npm run build from site/ using Node 22.23.4.
  • npm run check:links.
  • npm run contrast, npm run flash and npm run install-box with workspace-local Chromium.
  • npm run preview -- --host 127.0.0.1 --port 4327.
  • node .qa/live.mjs: real-browser navigation, HTTP responses, assets, canonical docs, privacy, links, search, filters, themes and mobile layouts; corrected final driver exited 0.
  • node .qa/paint.mjs: four theme cases under 4× CPU throttling, with observed painted frames and zero wrong-theme frames.
  • python3 .qa/runbook-test.py: documented Bash against a disposable HTTP API, including rollback recovery and rejection handling.
  • node .qa/mobile-shot.mjs and visual review of desktop, mobile, search and theme screenshots.
  • Stopped the preview, confirmed its port closed, removed disposable files and dependencies, and verified no worktree changes remained.
✅ **Document** - passed

✅ No issues found.

⚠️ **Lint** - 1 info
  • ℹ️ site/scripts/flash.mjs:93 - Astro check passes with three TS2568 hints for window.__frames at lines 93, 96, and 114. Resolving them requires test-script annotations; this phase forbids test edits.
✅ **Push** - passed

✅ No issues found.

Scaffold a pinned Nimbus Astro site that serves the amber B landing
page at / and the public skill pages from docs/{global,project} in the
same static build. Plans and other internal docs stay unpublished.

Co-authored-by: Mr. ED <edheltzel@users.noreply.github.com>

@pullfrog pullfrog Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Important

Three links in the published documentation resolve to 404s because repository-relative directory links are not rewritten for the site.

Reviewed changes Review of the new static Nimbus site, its canonical documentation ingestion, and its public navigation and agent interfaces.

  • Landing page: Adds the amber landing page, animated hero, theme controls, and copyable installation commands.
  • Public documentation: Publishes docs/{global,project} through a grouped docs hub and skill pages, while excluding internal plans.
  • Documentation UI: Adds responsive navigation, search, TOCs, pagination, and page actions.
  • Static interfaces: Adds Markdown/source endpoints, LLM indexes, discovery metadata, social cards, sitemap, and robots output without changing live deployment configuration.

Validation: the production build and typecheck pass, including a build pinned to the reviewed commit. Browser checks covered desktop/mobile rendering, search, and mobile drawer navigation; an output-level link audit confirmed the three broken links noted inline. Nimbus's check returned no findings but explicitly does not lint the 51 .md pages.

Pullfrog  | Fix all ➔ | Fix 👍s ➔ | View workflow run | Using gpt-6.1-sol | 𝕏

Comment thread site/src/content.config.ts Resolved
The canonical docs link to folders relative to their repo path, which
404 under the site's page URLs. Folders under docs/{global,project}
now go to an anchored docs hub section; other repo paths go to GitHub.
check-links walks dist/ and fails on any same-origin link or #fragment
that does not resolve. contrast, flash and install-box come from
doskills-site unchanged.
…de link

The hard-coded counts were stale (67 vs 76 skills). The install CTA
points at the README install guide again, as on doskills-site.
The site publishes plain .md docs only. Remove the MDX component
registry, partials collection, Render, the server-MCP connect button,
the API coordinates route, and their UI components. MDX validation is
off since there is no MDX. From the no-mistakes review.
Docs used ui-mode while the landing page used doskills-theme, so a
dark choice on / was lost on /docs/. From the no-mistakes review.
Compare computed colours with JavaScript on and off instead of parsing
token source. From the no-mistakes review.
DOCS_REF could point the docs at another commit than the landing page
and counts. From the no-mistakes review.
@astrojs/prism needs >=22.23.4 and undici >=22.19.0, so 22.12.0 ran
outside declared engines. Raising the pin keeps every declared range,
unlike overriding Astro's own satteri and unifont versions. Also drop
the lint:docs scripts: Nimbus lint reads only .mdx and this site has none.
@edheltzel edheltzel changed the title feat(site): Nimbus landing + public docs under site/ feat(site): migrate landing page and public docs to Nimbus Nov 6, 2026

@pullfrog pullfrog Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ No new issues found.

Reviewed changes Reviewed the changes since 01d9a3d, including the directory-link fix and subsequent site, CI, and documentation updates.

  • Fixed directory navigation: Routed repository directory links to anchored docs hub sections and added a built-output link audit.
  • Corrected landing metadata: Derived skill counts from skills/ and restored the canonical installation guide link.
  • Improved documentation UI: Shared theme preferences between landing and docs, revealed ancestors for sidebar group matches, and corrected TOC viewport bands and resize tracking.
  • Added validation: Introduced site CI, rendered contrast, theme-flash, and mobile install-box checks; pinned Node and documentation ingestion to the checkout's HEAD.
  • Trimmed template code and clarified publishing: Removed unused Nimbus components and routes, updated authoring guidance, and documented Pages deployment, cutover, and rollback without performing a live cutover.

Validation: build, typecheck, link audit, contrast, theme-flash, and mobile install-box checks pass. All 5,046 audited same-origin links resolve; browser checks also verified shared themes, nested-group filtering, and desktop/mobile TOC tracking after resizing.

Pullfrog  | View workflow run | Using gpt-6.1-sol | 𝕏

…errors

The project now exists, so the runbook names its real hostname instead
of looking it up. Every call goes through cf(), which fails on an HTTP
error or success:false.

@pullfrog pullfrog Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ No new issues found.

Reviewed changes Reviewed the cutover runbook changes since 90c4a2e.

  • Recorded the verified hostname: Replaced hostname discovery with doskills.pages.dev and documented the successful preview.
  • Hardened API failures: Routed commands through a helper that rejects HTTP failures and unsuccessful API responses.
  • Made rollback resumable: Checked both projects' domain associations before conditionally removing or restoring them.

Validation: mocked execution passed all four rollback association states, successful cutover, and HTTP/API/invalid-response failure cases. Checked Cloudflare's documented response contracts; no live infrastructure changes were performed.

Pullfrog  | View workflow run | Using gpt-6.1-sol | 𝕏

@edheltzel
edheltzel merged commit 54d2978 into master Nov 6, 2026
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants