# Publish the documentation

`apps/docs` uses Fumadocs to build a separate static documentation site from this repository's
canonical Markdown and explicitly exported cookbook examples. The product and twins catalog
remain in `apps/www`; a World dashboard remains in `apps/console`. Documentation requires no
Mintlify account or documentation subscription. Hosting is an ordinary static-site deployment.

## Author one source

Edit the canonical page under `docs/`, or the cookbook's README and source files. Keep tutorial
file and command fences unchanged when adjusting their presentation. The [documentation
map](../README.md) owns navigation order and groups: Guides, Cookbook, Reference, Concepts and
Contribute are views over that map. Fumadocs owns the shell, search, code presentation, mobile
navigation, page headings and previous/next links.

The build prepares `.content/`, `.generated/` and `public/` under `apps/docs`. These ignored
outputs adapt links and titles; they are never another place to edit a page. Raw canonical
Markdown is served at the corresponding `.md` address. Both renderers use `VOLTER_REPO_URL`:
set it to `none` while the platform repository is private. Source links then serve Markdown;
a configured public repository gets GitHub source links. Links to unexported private files
become text, and published package references point to their npm pages.

Only cookbook directories with `public-files.json` export starter files. The manifest lists
files or identifies a canonical tutorial whose file fences own the runnable example. Larger
application case studies appear only when a public source repository is configured and retain their stated prerequisites; their
checkouts, runtime data and private files are not copied into the documentation export.

Brand tokens, World logos, fonts and font licenses are fetched from `brand.volter.ai` at build
time into the ignored output. A failed fetch fails the build. The site serves those assets
itself, uses no runtime brand request and has no analytics, authentication or World state.

## Build and preview

Use Node 22.3 or newer and the repository's pinned Bun. Install from the repository lockfile
with the normal package-manager cache enabled, outside World execution:

```console
bun install --frozen-lockfile
git lfs pull
```

Build from `apps/docs` inside a task-owned World that allows reads from `brand.volter.ai`:

```console
volter-world run <build-config> --root <task-root> --env-out <new-output-env> --owner docs-build -- env VOLTER_REPO_URL=none bun scripts/build.ts
```

The build writes `apps/docs/out/`, including static HTML, local fonts, client bundles, raw
Markdown, exported examples and the search index. Search runs in the reader's browser; it
requires no search account or running application server. Build does not run repository test
suites, lints or typechecks.

For the preview, from `apps/docs`:

```console
volter-world up world.json --root . --env-out .volter/docs-preview.env --owner docs-preview
volter-world app-url world-docs-preview --root .
```

`world.json` declares the static preview as a World-owned process service. Its endpoint is
registered by the runtime after readiness. Stop it through its owner:

```console
volter-world down world-docs-preview --root .
```

Use a distinct task root and config when another preview already owns this root. The preview
serves the static export that is deployed, rather than a development rendering of the pages.

## Host the export

Serve `apps/docs/out/` at the root of the chosen documentation hostname. Any static host that
serves extensionless HTML paths works. `_redirects` and `_headers` provide Cloudflare Pages
metadata; hosts with different conventions need equivalent rules. There is no required Node
server. Building an export does not publish it.

Keep `/docs/README`, other `/docs/` pages and exported `/cookbook/` pages at their existing
paths. `.html` aliases redirect to the extensionless address; canonical `.md` files remain
available. The host must serve `404.html` with a 404 status for an absent page.

After the documentation hostname is live, set `VOLTER_DOCS_URL` to its origin in the product-site
build. That build links to the separate docs site, redirects its former documentation addresses
and omits its old documentation renderer and documentation search entries. Until cutover, an
unset `VOLTER_DOCS_URL` retains the existing pages so public links continue to work. The docs
and product site have separate deployment lifetimes.

Fumadocs' [static export guide](https://www.fumadocs.dev/docs/deploying/static) owns the framework
configuration; [Next.js static export](https://nextjs.org/docs/app/guides/static-exports) explains
what the host must serve. Domain selection, DNS changes and publication are explicit operator
actions, separate from local authoring and preview.

## Publish Volter's documentation

The public documentation hostname is `https://world-docs.volter.ai`; its Cloudflare Pages
project is `volter-world-docs`, configured in `apps/docs/wrangler.toml`. The product and catalog
use `volter-world-www` at `https://world.volter.ai`. Build the docs as above, then upload the
completed export from `apps/docs` using the repository's locked Wrangler dependency:

```console
bunx wrangler pages deploy out --project-name volter-world-docs --branch main
```

The upload uses the operator's existing Cloudflare authentication. Keep credentials out of
the repository and export. `--branch main` selects production even when the build's checkout
is on a feature branch; omitting it can create a preview deployment instead.

Configure the product build with `VOLTER_DOCS_URL=https://world-docs.volter.ai`,
`VOLTER_SITE_URL=https://world.volter.ai`, `VOLTER_REPO_URL=none` while source is private, and
`VOLTER_HOSTED=off` while the hosted platform is not activated. A static-site deployment does
not deploy or upgrade a platform or any World. The product publisher defaults to `main` and
accepts an explicit `--branch` when publishing a preview.
