Documentation Site Generator
forge docsite hosts two architecturally separate families under one noun. They share no state, no manifest, no config key, and no output directory.
install/dev/build— scaffold and run a generator toolchain inside.forge/itself, so you can browse forge's own live state (specs, changes, decisions, branding) as a real site while you work.publish— renders forge's.forge/state into a public documentation site you already own — VitePress, Docusaurus, Starlight, Mintlify, or MkDocs Material — detecting the generator already in use and never destroying a hand-written page.
Not the same thing as forge docs
forge docs build\|serve renders forge's own internal dashboard — spec inventory, breaker/budget chips, the session timeline. docsite publish renders a public documentation site for people outside the team. docsite install/dev/build is a third thing again — forge's own live-content site, browsed locally while you work. All three read the same .forge/ state but produce different artifacts for different audiences.
Browse forge's own state live
The fastest way to see what is in .forge/ without leaving your terminal:
forge docsite install --target vitepress # once: scaffolds .forge/.vitepress + package.json
forge docsite dev # foreground dev server, Ctrl-C to stopinstall scaffolds a VitePress project into .forge/ itself and installs its dependencies. dev execs that project's dev server in the foreground, serving live .forge/ content — specs, changes, decisions, branding tokens with color swatches, mermaid diagrams — regenerated automatically as files change on disk.
forge docsite build --out .forge/.vitepress/distbuild runs the same generator's static build — no separate derive stage: it produces exactly what dev already serves, over the same generated config, so there is never more than one coherent generator project living in .forge/.
Both dev and build require install to have run first: they read the installed target from .forge/.docsite-install.json, never from .forge/config.yaml, and error naming install if nothing is installed yet. dev --print / build --print show the exact command instead of running it.
Publish a specification site from .forge/
This is the fastest path to a shippable public site — one command, no staging tree to hand-write:
forge docsite publish --target vitepress --out sitepublish reads .forge/specs/, the active .forge/changes/, and the immutable .forge/changes/archive/ directly, and produces three sections:
| Section | Source | Content |
|---|---|---|
capabilities/ | .forge/specs/<domain>/spec.md | Requirements and their Given/When/Then scenarios — what the system canonically does |
active/ | .forge/changes/<name>/ | Proposal intent/scope, design decisions, and the task list with status |
releases/ | .forge/changes/archive/<date>-<name>/ | The same shape as active/, minus tasks — an archived change has none open by definition |
plus a generated index.md landing page with counts for each section. When present, data model and contract definitions are included alongside the design decisions.
Deliberately not a dashboard
Operational fields a change carries for the team running forge — session events, spend, breaker/secscan counters — never reach these pages. This is a client-facing artifact: proposal, design, and task substance only. For the operational view, see the spec-viewer dashboard.
publish always derives fresh from .forge/ before rendering — there is no separate stage-then-render step to run by hand. --source-only stops after staging, leaving .forge/docsite/staging/ in place for manual review without ever rendering.
forge docsite publish --source-only # stage only; review .forge/docsite/staging/
forge docsite publish --target vitepress --out site # derive + renderThe full pipeline
forge docsite install [--target <t>] [--force] [--no-gitignore]
forge docsite dev [--print]
forge docsite build [--out <dir>] [--print]
forge docsite publish [--target <t>] [--out <dir>] [--source-only]installscaffolds the chosen generator's template set into.forge/and installs its dependencies. Refuses a conflicting already-installed target unless--force(which removes the old target's owned files, preserving anything hand-edited).devexecs the installed generator's dev server in the foreground. Errors naminginstallif nothing is installed; errors by name — never silently substituting VitePress — if the installed target has no dev backend.buildruns the installed generator's static build.publishderives fresh from.forge/, resolves the adapter, applies the ownership rules, writes the site, and emits/llms.txtwhendocsite.llms_txtis true (the default).
detect, plan, render, and derive were removed
No aliases, no deprecation window. Running one names its replacement: detect → install --dry-run, render/derive → publish, plan → no direct replacement (its bounded staleness work list had no other caller once publish always derives the whole site fresh every run).
Ownership: forge owns files, not directories
publish tracks what it wrote in .forge/docsite/owned.json — a completely separate manifest from install's own .forge/.docsite-install.json; the two families never touch each other's files. A page you hand-edit after publish wrote it is detected and skipped on the next run rather than overwritten; a page that exists on disk but forge never wrote is invisible to it and stays untouched. publish always derives the whole site, so pruning — deleting a page forge owns that is no longer produced — is unconditional; there is no partial or incremental mode to opt out of it.
Configuration
target, out, pattern, sections, scaffold, llms_txt, auto_on_archive, and exclude are all set under docsite: in .forge/config.yaml and apply to publish only — see Configuration. install/dev/build read no configuration at all: which target is installed lives entirely in .forge/.docsite-install.json. With no docsite: configuration, publish still needs zero setup for an existing public site: it resolves the generator and output directory from files already on disk.
Next steps
- Spec-Viewer Dashboard — the internal, operational view
docsite publishdeliberately does not replace. - Configuration — every
docsite:key (publish-only). - Command Reference — the full
docsitecommand table. - The forge CLI — the full
docsitesynopsis.