Skip to content

docs: add cloudflare documentation deployment website#1285

Merged
TabishB merged 14 commits into
Fission-AI:mainfrom
clay-good:docs/fumadocs-site
Jul 3, 2026
Merged

docs: add cloudflare documentation deployment website#1285
TabishB merged 14 commits into
Fission-AI:mainfrom
clay-good:docs/fumadocs-site

Conversation

@clay-good

@clay-good clay-good commented Jun 30, 2026

Copy link
Copy Markdown
Collaborator

What this adds

A documentation + marketing website for OpenSpec, at website/, built with Fumadocs and deployed as a static site to Cloudflare Pages. It also adds three new guides to docs/ for new users.

The problem it solves

OpenSpec's docs live as Markdown in docs/. There was no browsable, searchable home for them, and any separate site would drift from the source the moment someone edited a doc. This site fixes both: it's a real docs site, and it stays current on its own.

How it stays current (no manual updates)

The site's doc pages are generated from docs/*.md — that folder is the single source of truth. Every build re-mirrors the docs, so:

  • Edit a doc in docs/*.md → the site updates on the next build. Nothing to copy by hand.
  • A daily job + every merge to main rebuilds and redeploys to Cloudflare, so the published site can't fall behind the docs.

Only the marketing landing page is hand-authored; everything under /docs mirrors automatically.

New docs for new users (in docs/, so they appear on the site too)

  • Reviewing a Change — the two-minute pass on the plan the AI drafts, before any code.
  • Writing Good Specs — what a strong requirement and scenario look like, and how to right-size a change.
  • OpenSpec on a Team — how a change fits a branch, a pull request, and review.

⚠️ One-time setup before auto-deploy works (maintainer)

The pipeline is ready but stays dormant until three steps are done (full instructions in website/README.md):

  1. Create a Cloudflare Pages project named openspec-docs (production branch main).
  2. Add repo secrets CLOUDFLARE_API_TOKEN and CLOUDFLARE_ACCOUNT_ID.
  3. Merge this PR to main (GitHub Actions only runs the deploy triggers from main).

Until then, docs still mirror correctly on every build — they just don't reach Cloudflare on their own.

Note: the existing landing page

openspec.dev today is a separate Astro site. This PR ships its own Fumadocs landing page. Whether to keep it, port the Astro one into it, or serve only /docs is a maintainer decision — nothing else in the pipeline depends on it.

Scope

  • Self-contained under website/ (its own package.json/lockfile); not wired into the CLI build/test, so the published package is unaffected.
  • Outside website/: the three new docs/*.md guides (plus light cross-links in existing docs), the .github/workflows/deploy-docs.yml workflow, and a "Why teams adopt OpenSpec" section in the root README.md.
  • Verified: clean build, 26 doc pages generated, 87 static pages, no warnings, all internal links resolve.

🤖 Generated with Claude Code

Add a self-contained marketing + documentation site under website/, built
with Fumadocs (Next.js) and configured as a static export so it deploys
directly to Cloudflare Pages with no server runtime.

What's included:
- A marketing landing page (hero, the two-folder model, the four core
  ideas, the explore→propose→apply→archive loop, and the "why").
- 13 documentation pages rewritten for clarity and delight: introduction,
  installation, getting started, how commands work, core concepts, the
  workflow, explore first, existing projects, editing a change,
  customization, FAQ, and a reference section (slash commands, CLI,
  supported tools).
- Static client-side search (Orama), per-page Open Graph images, and
  llms.txt / llms-full.txt routes — fitting for an AI-native tool.
- website/README.md with one-table Cloudflare Pages deploy settings
  (root: website, build: npm run build, output: out).

Content is faithful to the docs/ overhaul from Fission-AI#1237, restated in a
simpler, friendlier voice. Verified with a clean `next build` (48 static
pages, no warnings).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@clay-good clay-good requested a review from TabishB as a code owner June 30, 2026 16:50
@coderabbitai

coderabbitai Bot commented Jun 30, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

A static website/ Next.js docs site is added with shared config, app routes and layouts, MDX support, a homepage, and a full OpenSpec documentation and reference content set.

Changes

OpenSpec Documentation Website

Layer / File(s) Summary
Project setup and shared utilities
website/package.json, website/next.config.mjs, website/tsconfig.json, website/postcss.config.mjs, website/source.config.ts, website/.gitignore, website/README.md, website/lib/shared.ts, website/lib/source.ts, website/lib/layout.shared.tsx, website/lib/cn.ts
Establishes the website package, static export Next.js config, Tailwind/PostCSS, Fumadocs source/schema wiring, strict TypeScript, shared site constants, source helpers, layout options, and the cn export bridge.
Root shell and client providers
website/app/layout.tsx, website/app/global.css, website/components/provider.tsx, website/components/search.tsx, website/components/mdx.tsx
Adds the root HTML shell with metadata and Inter font, global CSS and brand variables, the client RootProvider wrapper with search, the Orama-backed search dialog, and MDX component registration.
Home route and sections
website/app/(home)/layout.tsx, website/app/(home)/page.tsx
Adds the home layout wrapper and the landing page sections for the homepage.
Docs pages and generated routes
website/app/docs/layout.tsx, website/app/docs/[[...slug]]/page.tsx, website/app/api/search/route.ts, website/app/og/docs/[...slug]/route.tsx, website/app/llms.txt/route.ts, website/app/llms-full.txt/route.ts, website/app/llms.mdx/docs/[[...slug]]/route.ts, website/app/robots.ts, website/app/sitemap.ts
Adds the docs layout and dynamic docs page, plus search, OG image, robots, sitemap, and LLM text route handlers with static params and metadata generation.
Documentation content and navigation
website/content/docs/*, website/content/docs/reference/*
Adds the MDX documentation pages and navigation metadata for the docs section and its reference pages.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Suggested reviewers

  • TabishB
  • alfred-openspec

Poem

🐇 I hopped through routes and docs today,
With sitemap trails to guide the way.
MDX moons now softly glow,
And OpenSpec’s new pages flow.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 3.03% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title is broadly aligned with the PR, which adds a new docs website intended for static deployment on Cloudflare Pages.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@clay-good clay-good self-assigned this Jun 30, 2026
Completes the documentation work begun in Fission-AI#1237 by tightening the
Fumadocs site toward the quality bar of the stores user-guide:

- Intro now opens problem-first ("the requirements lived only in chat"),
  adds an honest "How it compares" table (Spec Kit / Kiro / nothing), and
  frames the tradeoff in a "When the ceremony isn't worth it" callout.
- New Stores guide (beta) distilled from docs/stores-beta/user-guide.md:
  the problem, the annotated shape, a five-minute walkthrough with real
  command output, a role-based story, the root-resolution order, and an
  honest-limitations section. Linked from Existing Projects.

Verified with a clean `next build` (51 static pages, no warnings).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (1)
website/content/docs/installation.mdx (1)

26-30: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

Yarn Berry users may be confused by yarn global add.

Modern Yarn (2+/Berry) no longer supports yarn global add by default. Consider adding a note for Yarn Berry users or using yarn dlx @fission-ai/openspec`` for one-off execution.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@website/content/docs/installation.mdx` around lines 26 - 30, The installation
example in the yarn tab uses a command that no longer works for Yarn Berry
users. Update the docs around the installation snippet in the installation.mdx
content to either add a clear note that `yarn global add` is only for classic
Yarn, or replace/augment it with the Yarn Berry-friendly `yarn dlx
`@fission-ai/openspec`` option. Keep the guidance near the existing yarn example
so users can choose the right command based on their Yarn version.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@website/app/docs/`[[...slug]]/page.tsx:
- Around line 30-33: The GitHub link built in the docs page view uses the wrong
blob path and points to content/docs/... instead of the actual
website/content/docs/... location. Update the githubUrl construction in the page
component that renders ViewOptionsPopover so the generated link is prefixed with
website/ and matches the repo path for these docs pages.

---

Nitpick comments:
In `@website/content/docs/installation.mdx`:
- Around line 26-30: The installation example in the yarn tab uses a command
that no longer works for Yarn Berry users. Update the docs around the
installation snippet in the installation.mdx content to either add a clear note
that `yarn global add` is only for classic Yarn, or replace/augment it with the
Yarn Berry-friendly `yarn dlx `@fission-ai/openspec`` option. Keep the guidance
near the existing yarn example so users can choose the right command based on
their Yarn version.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 0c48f2d6-06fa-4bce-bb61-5d96ddd872f6

📥 Commits

Reviewing files that changed from the base of the PR and between 546224e and 8c2f727.

⛔ Files ignored due to path filters (1)
  • website/package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (41)
  • website/.gitignore
  • website/README.md
  • website/app/(home)/layout.tsx
  • website/app/(home)/page.tsx
  • website/app/api/search/route.ts
  • website/app/docs/[[...slug]]/page.tsx
  • website/app/docs/layout.tsx
  • website/app/global.css
  • website/app/layout.tsx
  • website/app/llms-full.txt/route.ts
  • website/app/llms.mdx/docs/[[...slug]]/route.ts
  • website/app/llms.txt/route.ts
  • website/app/og/docs/[...slug]/route.tsx
  • website/components/mdx.tsx
  • website/components/provider.tsx
  • website/components/search.tsx
  • website/content/docs/core-concepts.mdx
  • website/content/docs/customization.mdx
  • website/content/docs/editing-changes.mdx
  • website/content/docs/existing-projects.mdx
  • website/content/docs/explore.mdx
  • website/content/docs/faq.mdx
  • website/content/docs/getting-started.mdx
  • website/content/docs/how-commands-work.mdx
  • website/content/docs/index.mdx
  • website/content/docs/installation.mdx
  • website/content/docs/meta.json
  • website/content/docs/reference/cli.mdx
  • website/content/docs/reference/meta.json
  • website/content/docs/reference/slash-commands.mdx
  • website/content/docs/reference/supported-tools.mdx
  • website/content/docs/the-workflow.mdx
  • website/lib/cn.ts
  • website/lib/layout.shared.tsx
  • website/lib/shared.ts
  • website/lib/source.ts
  • website/next.config.mjs
  • website/package.json
  • website/postcss.config.mjs
  • website/source.config.ts
  • website/tsconfig.json

Comment thread website/app/docs/[[...slug]]/page.tsx

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@website/content/docs/index.mdx`:
- Around line 76-81: The comparison table in the docs has an unlabeled first
column, so update the markdown table in the index content to give that header an
explicit name such as Tool or Option. Keep the existing table structure and
ensure the first column header in the OpenSpec/Spec Kit/Kiro comparison is
clearly labeled so the table is easier to scan and more accessible.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: a83a1878-aa75-4c4c-9098-f70581fd9c43

📥 Commits

Reviewing files that changed from the base of the PR and between 8c2f727 and a52b728.

📒 Files selected for processing (4)
  • website/content/docs/existing-projects.mdx
  • website/content/docs/index.mdx
  • website/content/docs/meta.json
  • website/content/docs/stores.mdx
✅ Files skipped from review due to trivial changes (2)
  • website/content/docs/meta.json
  • website/content/docs/existing-projects.mdx

Comment thread website/content/docs/index.mdx Outdated
clay-good and others added 3 commits June 30, 2026 12:20
…page

Continue the Fission-AI#1237 docs completion with a stronger product story:

- Landing page now reads like a real product site:
  - "Works with the tools you already use" strip (15 named assistants + more)
  - "What a change actually looks like" — three real artifacts
    (proposal.md, a spec delta, tasks.md) so the workflow is concrete
  - "The honest middle" comparison block (Spec Kit / Kiro / no specs)
  - Robust hero gradient via color-mix instead of v3 theme() syntax
- New Examples & Recipes page: seven copy-pasteable, narrated walkthroughs
  (small feature, bug fix, explore-first, parallel changes, no-behavior
  refactor with --skip-specs, step-by-step, onboard). Linked from the intro
  and getting-started.

Verified: clean `next build` (54 static pages, no warnings); Tailwind
opacity/color-mix utilities confirmed in the generated CSS; all internal
links resolve.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
… site

- Branded SVG favicon (app/icon.svg) in the OpenSpec indigo.
- Static sitemap.xml covering the home page and every doc, built from the
  content source and NEXT_PUBLIC_SITE_URL.
- robots.txt allowing all and pointing at the sitemap.

All three are emitted by the static export. Clean `next build`, 57 pages.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…overage

Final pass completing the Fission-AI#1237 documentation work.

Reposition stores (beta) as the team adoption story, consistently:
- README.md gains a prominent "Why teams adopt OpenSpec" section right
  after the demo (cross-repo features, shared requirements, plan before
  code), leading with stores.
- Landing page gains a matching "Why teams adopt OpenSpec" section.
- Docs intro gains a teams card + callout pointing at stores.
- Stores page expanded with full References and Worksets technical
  examples (the cross-team requirements story, workset create/open).

Incorporate the remaining source-doc knowledge so the site is complete:
- New pages: Glossary, Troubleshooting, Multi-Language, and an
  Agents & Automation reference (the machine-readable --json surfaces and
  workflow primitives that make OpenSpec AI-native).
- The Workflow page now covers ff-vs-continue, a three-dimension verify
  example, and the update-vs-start-fresh decision guide.
- Nav restructured with a Help section; reference section gains Agents.

Build hardening: `build` now runs `fumadocs-mdx && next build` so the
content source is always regenerated. Clean build: 69 static pages, no
warnings; all internal links verified.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
website/app/(home)/page.tsx (1)

17-17: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Reuse the shared docs route constant.

website/lib/shared.ts already centralizes the docs base path, so hardcoding /docs/stores here makes the new section the first place that drifts if that route ever changes.

Suggested diff
-import { links } from '`@/lib/shared`';
+import { docsRoute, links } from '`@/lib/shared`';
...
-            <Link href="/docs/stores" className="font-medium text-fd-primary underline">
+            <Link
+              href={`${docsRoute}/stores`}
+              className="font-medium text-fd-primary underline"
+            >
               stores
             </Link>
...
-            href="/docs/stores"
+            href={`${docsRoute}/stores`}

Also applies to: 379-403

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@website/app/`(home)/page.tsx at line 17, The home page is still hardcoding
the docs section path instead of reusing the shared route constant. Update the
relevant links in the home page component and any related docs references to use
the centralized value from links in website/lib/shared.ts, so the path stays
consistent if the docs base route changes. Use the existing imports and
identifiers in page.tsx to locate and replace the hardcoded /docs/stores usage
with the shared constant.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@website/app/`(home)/page.tsx:
- Line 17: The home page is still hardcoding the docs section path instead of
reusing the shared route constant. Update the relevant links in the home page
component and any related docs references to use the centralized value from
links in website/lib/shared.ts, so the path stays consistent if the docs base
route changes. Use the existing imports and identifiers in page.tsx to locate
and replace the hardcoded /docs/stores usage with the shared constant.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: adc34dd9-9655-4919-91d8-69dd375ac718

📥 Commits

Reviewing files that changed from the base of the PR and between 1db6b4e and 109f8c9.

📒 Files selected for processing (12)
  • README.md
  • website/app/(home)/page.tsx
  • website/content/docs/glossary.mdx
  • website/content/docs/index.mdx
  • website/content/docs/meta.json
  • website/content/docs/multi-language.mdx
  • website/content/docs/reference/agents.mdx
  • website/content/docs/reference/meta.json
  • website/content/docs/stores.mdx
  • website/content/docs/the-workflow.mdx
  • website/content/docs/troubleshooting.mdx
  • website/package.json
✅ Files skipped from review due to trivial changes (6)
  • website/content/docs/reference/meta.json
  • README.md
  • website/content/docs/reference/agents.mdx
  • website/content/docs/the-workflow.mdx
  • website/content/docs/stores.mdx
  • website/content/docs/index.mdx
🚧 Files skipped from review as they are similar to previous changes (2)
  • website/package.json
  • website/content/docs/meta.json

@alfred-openspec alfred-openspec left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

One blocker before this lands: the docs page GitHub source/edit links point at the wrong path.

website/app/docs/[[...slug]]/page.tsx builds URLs under /content/docs/${page.path}, but these files live under /website/content/docs/${page.path} in this PR. That means the ViewOptionsPopover link will 404 on every deployed docs page.

The rest of the static export shape looks healthy: I ran npm install && npm run build in website/ and it generated 69 static pages successfully.

- page.tsx: prefix ViewOptionsPopover githubUrl with website/ so the
  "view/edit source" links resolve to website/content/docs/... instead
  of 404-ing on every deployed docs page (Alfred blocker).
- installation.mdx: note that `yarn global add` is Classic Yarn only and
  point Yarn Berry users at `yarn dlx` / npm / pnpm.
- index.mdx: label the comparison table's first column ("Option").
- (home)/page.tsx: use the shared docsRoute constant for all /docs links
  instead of hardcoded paths.

Verified with `npm run build` in website/ — 69 static pages, and the
built getting-started page links to blob/main/website/content/docs/...

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@clay-good

Copy link
Copy Markdown
Collaborator Author

Thanks @alfred-openspec and @coderabbitai — all four points addressed in a726e91:

  1. Blocker (Alfred): ViewOptionsPopover githubUrl now prefixes website/, so source/edit links resolve to blob/main/website/content/docs/... instead of 404-ing. Confirmed in the built HTML.
  2. installation.mdx: added a note that yarn global add is Classic Yarn (1.x) only, pointing Yarn Berry users at yarn dlx / npm / pnpm.
  3. index.mdx: labeled the comparison table's first column (Option).
  4. (home)/page.tsx: all /docs/* links now use the shared docsRoute constant.

Re-ran npm run build in website/ — 69 static pages generated successfully.

@coderabbitai

coderabbitai Bot commented Jun 30, 2026

Copy link
Copy Markdown
Contributor

Tip

For best results, initiate chat on the files or code changes.

@clay-good Thanks for the thorough follow-up — those updates sound good, and the rebuild result is a strong confirmation. Nice catch on the website/ GitHub path prefix as well.

🐇✨


If you found this review helpful, would you consider giving us a shout-out on X?

Thank you for using CodeRabbit!

alfred-openspec
alfred-openspec previously approved these changes Jul 1, 2026

@alfred-openspec alfred-openspec left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Thanks for addressing this. I rechecked the source links and the built output now points at website/content/docs/...; CI is green, and a fresh npm ci && npm run build in website/ passed locally with 69 static pages. Good to merge.

@clay-good clay-good changed the title docs: add Fumadocs documentation site (Cloudflare Pages-ready) [Docs] Add Fumadocs documentation + marketing site (Cloudflare Pages-ready) Jul 1, 2026
@clay-good clay-good changed the title [Docs] Add Fumadocs documentation + marketing site (Cloudflare Pages-ready) [Docs] Add Fumadocs documentation for marketing site (Cloudflare Pages-ready) Jul 1, 2026
Make the repository's docs/*.md the single source of truth for the docs
site instead of maintaining a parallel set of hand-written MDX pages that
silently drift.

- scripts/sync-docs.mjs mirrors ../docs into content/docs/ on every build:
  derives title/description, injects Fumadocs frontmatter (+ githubSource),
  rewrites internal *.md links to /docs routes, and emits meta.json. Pages
  are written as .md so <placeholders>/{braces} in the docs stay literal
  and never break the MDX build.
- docs.sync.config.mjs is the one manifest deciding which docs publish and
  their slug/section/icon. content/docs/ is now generated + git-ignored;
  the curated .mdx pages are removed. The marketing landing page stays
  hand-authored.
- build/dev/types:check run sync:docs first, so the site is always current.
- .github/workflows/deploy-docs.yml rebuilds and deploys to Cloudflare
  Pages via Wrangler on push to docs/**|website/**, daily on a schedule,
  on demand, and as a build-only check on PRs. Needs CLOUDFLARE_API_TOKEN
  + CLOUDFLARE_ACCOUNT_ID secrets and the DOCS_SITE_URL variable.
- source.config.ts carries githubSource so "edit this page" opens the real
  docs/*.md; website/README.md documents the pipeline.

Verified: clean build, 23 pages generated, 78 static pages, no warnings;
all internal doc links resolve; MDX-hazard docs (cli, customization) build.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@clay-good clay-good changed the title [Docs] Add Fumadocs documentation for marketing site (Cloudflare Pages-ready) [Docs] Fumadocs site that auto-mirrors docs/*.md + deploys to Cloudflare on a cadence Jul 1, 2026
clay-good and others added 3 commits July 1, 2026 12:10
… is empty

The deploy workflow passes NEXT_PUBLIC_SITE_URL from the DOCS_SITE_URL repo
variable, which resolves to an empty string when unset. `?? fallback` does
not catch '' (only null/undefined), so `metadataBase: new URL('')` crashed
`next build` with ERR_INVALID_URL while collecting page data. Use `||` so an
empty value also falls back. Verified: `NEXT_PUBLIC_SITE_URL='' npm run build`
now generates all 78 static pages.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Fill the biggest gaps a new user hits, in the plain-language voice of the
stores user guide:

- reviewing-changes.md: the two-minute human review of an AI-drafted plan
  before /opsx:apply — what to open, in what order, and the red flags per
  artifact — plus the /opsx:verify pass after code.
- writing-specs.md: what a strong requirement and scenario are made of,
  choosing ADDED/MODIFIED/REMOVED, and right-sizing a change.
- team-workflow.md: how a change maps onto a branch and a pull request,
  reviewing spec deltas in a PR, when to archive, and parallel changes —
  framed as convention, since OpenSpec never touches git.

Wire them into the docs map (README), the site nav (docs.sync.config.mjs),
and light "next steps" cross-links from getting-started, editing-changes,
and workflows. Verified: site builds clean, 26 pages, all internal links
resolve.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Spell out the three maintainer steps that activate auto-deploy (create the
openspec-docs Pages project, add CLOUDFLARE_API_TOKEN/ACCOUNT_ID secrets,
merge to main), and note that the pipeline mirrors docs on build regardless.
Also flag that openspec.dev is a separate Astro landing page and whether to
keep/port this Fumadocs landing page is a maintainer decision.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@clay-good clay-good changed the title [Docs] Fumadocs site that auto-mirrors docs/*.md + deploys to Cloudflare on a cadence Add a documentation website that auto-mirrors docs/ and deploys to Cloudflare Jul 1, 2026
@clay-good clay-good changed the title Add a documentation website that auto-mirrors docs/ and deploys to Cloudflare [Docs] Add a documentation website that auto-mirrors docs/ and deploys to Cloudflare Jul 1, 2026

@alfred-openspec alfred-openspec left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

One deploy-path blocker before merge: the Cloudflare deploy step still runs on push, schedule, and workflow_dispatch whenever the repo is Fission-AI/OpenSpec, even if the one-time Cloudflare setup has not happened yet.

The PR body/README says the pipeline stays dormant until CLOUDFLARE_API_TOKEN and CLOUDFLARE_ACCOUNT_ID are configured, but missing secrets expand to empty values and this step will try to deploy and fail on main. Please either guard the deploy step on non-empty Cloudflare credentials, or make the setup-before-merge requirement explicit and remove the “dormant” framing.

I rechecked the mirror/build path locally: npm ci, npm run sync:docs, and npm run build all pass, generating 26 mirrored docs and 87 static pages. The docs mirror itself looks healthy.

@alfred-openspec

Copy link
Copy Markdown
Collaborator

Reviewed the new guide commit too. The three docs additions look strong: reviewing-changes, writing-specs, and team-workflow all fit the product voice, links resolve through the docs mirror, and a fresh website build passes locally with 26 mirrored docs / 87 static pages.

The remaining blocker is still the deploy activation path from my review: either guard the Cloudflare deploy step on non-empty secrets, or make setup-before-merge explicit without saying the workflow stays dormant. Right now the README still says dormant, but the workflow would run and fail on main if the secrets/project are missing.

@TabishB TabishB left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Note

This is an AI-generated review (Claude, running a multi-agent fan-out: 7 domain reviewers — CI/CD, supply chain, sync engine, static-export correctness, docs accuracy, landing page, build verification — with adversarial verification of findings and a full build actually executed). Treat the judgment calls accordingly; every line comment below is anchored to concrete evidence.

Verdict: no blocking issues

Everything found is low-severity or informational. Four items are worth addressing before merge (marked [fix] inline): the production-deploy guard on workflow_dispatch, a phantom zod dependency, the unused cnfast package, and a doubled intro paragraph on every generated docs page. The rest are nits and notes.

What was verified by execution (not just read)

  • The PR's claims are true. npm ci + npm run build + npm run types:check all pass with zero warnings: exactly 26 docs pages synced, 87/87 static pages — matching the PR description.
  • All links work. 1,075 internal hrefs across the built out/ resolve to real files; all 43 fragment anchors resolve; git status stays clean after a full build (generated dirs are properly gitignored).
  • No hallucinated dependencies. Every version in website/package.json exists on npm and is current; all 443 lockfile entries resolve to registry.npmjs.org with sha512 integrity hashes; no git/tarball deps.
  • No hallucinated docs. Every CLI command, slash command, flag, and described behavior in the three new guides matches src/; all internal links resolve both on GitHub and after site rewriting.
  • No fabricated marketing. The landing page has no invented testimonials/stats; terminal samples trace verbatim to canonical docs; the “15 + 15 more” tools arithmetic is exactly right against the 30 enabled tools in src/core/config.ts.
  • Secrets are safe from forks. pull_request trigger (not pull_request_target) with contents: read, and the only step touching Cloudflare secrets is skipped on PRs.
  • The docs mirror is lossless and deterministic. Byte-identical output across runs; a masked diff of all 26 generated pages against their sources shows nothing dropped or duplicated; none of the link-rewrite regex edge cases occur in the real corpus.

Nice work overall — this is an unusually clean PR for its size.

Comment thread .github/workflows/deploy-docs.yml Outdated

- name: Deploy to Cloudflare Pages
# Skip on pull requests (build-only check) and on forks without secrets.
if: ${{ github.event_name != 'pull_request' && github.repository == 'Fission-AI/OpenSpec' }}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

[fix] A workflow_dispatch from any branch deploys that branch to production.

This condition only excludes pull_request, and the wrangler command below hardcodes --branch=main — which marks the deployment as production regardless of which git ref was actually built. So manually dispatching this workflow on a feature branch (e.g. “just to test the build”) silently overwrites the live docs site.

Suggested change
if: ${{ github.event_name != 'pull_request' && github.repository == 'Fission-AI/OpenSpec' }}
if: ${{ github.event_name != 'pull_request' && github.ref == 'refs/heads/main' && github.repository == 'Fission-AI/OpenSpec' }}

Push, schedule, and main-dispatch runs all still satisfy this; non-main dispatches become build-only.


# Never run two deploys at once; let an in-flight deploy finish.
concurrency:
group: deploy-docs

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

[nit] PR checks share this concurrency group with deploys — pending PR runs can get canceled.

GitHub keeps one running + at most one pending run per group, and cancel-in-progress: false only protects the running one. Scenario: a main deploy is running, PR A's build check queues, then PR B (or the cron) triggers → PR A's run is canceled and its check shows as canceled on the PR, which reads like a failure.

Consider scoping PR builds per-ref and only serializing real deploys, e.g.:

concurrency:
  group: deploy-docs-${{ github.event_name == 'pull_request' && github.ref || 'deploy' }}
  cancel-in-progress: ${{ github.event_name == 'pull_request' }}

- '.github/workflows/deploy-docs.yml'
schedule:
# Daily at 06:00 UTC — picks up any docs changes merged since the last run.
- cron: '0 6 * * *'

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

[note] The daily cron redeploys byte-identical content.

The build is fully deterministic from repo state (every published page comes from docs/**, and every push to main touching docs/** or website/** already deploys immediately), so the cron only serves as self-healing. Downside: if the Cloudflare token is ever rotated or removed, this produces a failing run every day. Weekly would give the same self-heal with less noise — or drop it entirely. Fine to keep as-is if the liveness signal is wanted.

Comment thread website/package.json Outdated
},
"dependencies": {
"@orama/orama": "^3.1.18",
"cnfast": "^0.0.8",

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

[fix] cnfast is dead code — nothing imports it.

The only reference in the whole tree is website/lib/cn.ts (export { cn } from 'cnfast';), and nothing imports lib/cn or calls cn( anywhere. The package itself was inspected and is benign (author Aiden Bai, no install scripts), but it's a 13-day-old pre-1.0 single-maintainer package — pure supply-chain surface for zero benefit.

Suggest removing it from dependencies and deleting website/lib/cn.ts. If a class-merge helper is needed later, clsx is already in the lockfile as a transitive dep.

Comment thread website/package.json
"fumadocs-mdx": "^15.0.13",
"fumadocs-ui": "^16.10.7",
"lucide-react": "^1.22.0",
"next": "16.2.9",

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

[note] npm audit shows 5 moderate advisories — all upstream in Next itself, not fixable here.

They all chain to GHSA-qx2v-qp2m-jg93 (postcss < 8.5.10), pinned inside next@16.2.9 (node_modules/next/node_modules/postcss@8.4.31). Even the latest stable Next still ships it; only the 16.3 canary bumps past it. Your top-level postcss (8.5.x) is fine, and this is build-time-only for a static export. No action needed — just bump next once a stable release ships postcss ≥ 8.5.10.

const websiteRoot = resolve(dirname(fileURLToPath(import.meta.url)), '..');
const docsRoot = resolve(websiteRoot, docsDir);
const outRoot = join(websiteRoot, 'content', 'docs');
const gitBranch = 'main';

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

[nit] gitBranch/gitBlobBase duplicate gitConfig in website/lib/shared.ts.

The values currently agree, but a repo rename or branch change has to be made in two places or the sync script's GitHub-fallback links drift from the site's other GitHub links. Since this .mjs can't import the .ts, consider moving the repo/branch constants into a small shared .mjs module both can import — or at least add cross-referencing comments.

export const revalidate = false;

export function GET() {
return new Response(llms(source).index());

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

[nit] llms.txt (and llms-full.txt) emit root-relative links, not absolute URLs.

The built out/llms.txt contains links like [Installation](/docs/installation) — an LLM or crawler fetching the file in isolation can't resolve those without knowing the origin. The sitemap and robots.txt get this right (absolute URLs from siteUrl).

Suggest prefixing with the site base URL here and in llms-full.txt/route.ts so all three machine-readable outputs are consistent.

Comment thread website/lib/shared.ts
// CI runs where the variable is unset or empty (an empty string would otherwise
// crash `new URL()` at build time).
export const siteUrl =
process.env.NEXT_PUBLIC_SITE_URL || 'https://openspec.dev';

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

[note] Mind the fallback before first deploy: unset DOCS_SITE_URL → absolute URLs point at a domain serving a different site.

If the workflow deploys before the DOCS_SITE_URL repo variable is set (it's optional), the site is served from *.pages.dev but its sitemap.xml, robots.txt, and OG image URLs will all point at openspec.dev — which currently serves the separate Astro landing page, where those paths 404. The mechanism itself is correct; this is a deploy-ordering footgun worth a line in the README's setup checklist. (Ties into the two-landing-pages decision the PR description already flags.)

Comment thread docs/team-workflow.md Outdated

## One rule: OpenSpec doesn't touch git

OpenSpec reads and writes plain Markdown under `openspec/`. It never commits, branches, pushes, or pulls — same as it never does for a [store](stores-beta/user-guide.md). That means:

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

[fix] Slight overstatement: openspec store create does commit by default.

Store creation runs git init plus an initial commit (src/commands/store.ts --init-git, default on; src/core/store/git.ts describes “setup-time git init plus one initial commit” as the entire write surface). The stores guide is deliberately narrower (“never clones, syncs, or pushes anything on its own”) — it omits “commits” for exactly this reason.

Suggested change
OpenSpec reads and writes plain Markdown under `openspec/`. It never commits, branches, pushes, or pulls — same as it never does for a [store](stores-beta/user-guide.md). That means:
OpenSpec reads and writes plain Markdown under `openspec/`. It never commits, branches, pushes, or pulls in your project — and it never clones or syncs a [store](stores-beta/user-guide.md) on its own. That means:

Ship your first change in five minutes
</h2>
<p className="mx-auto mt-4 max-w-xl text-fd-muted-foreground">
Works with 30+ AI assistants — Claude Code, Cursor, Codex, Windsurf,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

[note] “30+” is right (well — exactly 30), but it exposes a stale “20+” in the root README.

src/core/config.ts has exactly 30 tools with available: true, and the ToolStrip's “15 + 15 more” arithmetic checks out. But README.md still says “works with 20+ AI assistants”, so the two now disagree. Worth bumping the README in this PR while you're touching it — and consider “30” over “30+” since the count is exactly 30.

Comment thread website/package.json
@@ -0,0 +1,35 @@
{

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

[fix] Please switch website/ to pnpm for consistency with the rest of the repo.

The main repo is pnpm (ci.yml runs pnpm install --frozen-lockfile against the root pnpm-lock.yaml), but this package introduces npm + a package-lock.json. One package manager per repo keeps contributor muscle memory and tooling simple. Concretely:

  • Replace website/package-lock.json with a website/pnpm-lock.yaml (cd website && pnpm import && rm package-lock.json, or just delete the lockfile and pnpm install).
  • In .github/workflows/deploy-docs.yml: add pnpm/action-setup@v4 (same as ci.yml), switch setup-node to cache: pnpm with cache-dependency-path: website/pnpm-lock.yaml, and change npm cipnpm install --frozen-lockfile.
  • Update the npm run ... commands in website/README.md accordingly.

Please don't add a pnpm-workspace.yaml — keeping website/ a standalone package (as you have it) is right; this is only about which package manager it uses.

clay-good and others added 2 commits July 2, 2026 09:26
Maintainer review (TabishB) + Alfred blocker:

- deploy-docs.yml: guard the Cloudflare deploy on `github.ref ==
  refs/heads/main`. A `workflow_dispatch` on a feature branch previously
  passed the guard and, since wrangler hardcodes `--branch=main` (a
  production deploy), would overwrite the live docs site. Non-main
  dispatches are now build-only. Also resolves Alfred's deploy-path blocker.
- package.json: drop the direct `cnfast` dependency and delete the dead
  `lib/cn.ts` (nothing imports it; a class-merge helper isn't used).
- package.json: declare `zod` (^4.4.3) — it was a phantom dep only
  resolving via fumadocs-mdx's hoisted copy. Refresh the lockfile.
- docs page: omit the on-page <DocsDescription>. The frontmatter
  description is derived from the first body paragraph, so it rendered
  the intro twice on every page. Kept in generateMetadata for SEO/OG.
- team-workflow.md: `openspec store create` does an initial commit, so
  scope "never commits" to the user's project and reframe the store
  clause as "never clones or syncs on its own."
- README.md: bump stale "20+ AI assistants" to "30+" to match the site.

Verified: npm run types:check + npm run build pass, 26 docs synced,
intro paragraph now renders once per page.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Per maintainer review (TabishB): the root repo is pnpm (ci.yml runs
`pnpm install --frozen-lockfile` against a v9 `pnpm-lock.yaml`), but
`website/` had introduced npm + a `package-lock.json`. Standardize on
one package manager:

- Replace website/package-lock.json with website/pnpm-lock.yaml
  (lockfileVersion 9.0, generated with pnpm v9 to match root).
- deploy-docs.yml: add pnpm/action-setup@v4 (version 9, before
  setup-node, as in ci.yml), switch setup-node to `cache: pnpm` /
  `cache-dependency-path: website/pnpm-lock.yaml`, and
  `npm ci` → `pnpm install --frozen-lockfile`, `npm run build` →
  `pnpm run build`.
- package.json scripts + README: `npm run ...` → `pnpm run ...`.

website/ stays a standalone package (no pnpm-workspace.yaml), as before.

Verified: `pnpm install --frozen-lockfile`, `pnpm run build`, and
`pnpm run types:check` all pass — 26 docs synced, 87/87 static pages.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@clay-good clay-good changed the title [Docs] Add a documentation website that auto-mirrors docs/ and deploys to Cloudflare docs: add cloudflare documentation deployment website Jul 2, 2026
@TabishB

TabishB commented Jul 3, 2026

Copy link
Copy Markdown
Contributor

@clay-good Keen to get this merged in, I'll comment out the deploy for now so I can setup the cloudflare config on my end, so that dosen't block this PR.

@alfred-openspec alfred-openspec left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Re-approving after latest changes. CI is green, deploy remains build-only until Cloudflare setup is ready, and the package-manager cleanup now consistently uses pnpm for the website.

@TabishB TabishB added this pull request to the merge queue Jul 3, 2026
Merged via the queue into Fission-AI:main with commit 65a7233 Jul 3, 2026
10 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.

3 participants