AGENTS.md@apps/docs · git:20261012.5769a7b · 2026-10-12 · sha256 86aa5e41f5348c5d
AGENTS.md@apps/docs git:20261012.5769a7bA
Immutable. This exact content never changes and is served at /api/v1/blob/86aa5e41f5348c5d.
# Agent Instructions — `apps/docs` The documentation site. Read together with the [root `AGENTS.md`](../../AGENTS.md) and [`apps/AGENTS.md`](../AGENTS.md). Fumadocs on Next.js, laid out as Fumadocs' Next.js template (`create-fumadocs-app`) lays it out: `app/docs` serves `content/docs`, `lib/source.ts` defines the collection with Fumadocs MDX's macro and loads it, and the search, `llms.txt`, Markdown, Open Graph and MCP routes are Fumadocs' own recipes. The look is Fumadocs' Spacious layout, the one fumadocs.dev uses, without a theme of our own. Reach for a Fumadocs recipe before writing something of our own. ## Everything under `/docs` The hosted cloud routes only `/docs` and `/docs/(.*)` to this app; every other path belongs to the server (repo-root [`vercel.json`](../../vercel.json), [`apps/cloud/README.md`](../cloud/README.md)). So the template's root routes live under `/docs` here: | Route | Template | | --- | --- | | `/docs/api/search` | `/api/search` | | `/docs/api/mcp` | `/api/mcp` (`fumadocs-core/mcp`) | | `/docs/llms.txt`, `/docs/llms-full.txt` | `/llms.txt`, `/llms-full.txt` | | `/docs/og/<page>/image.png` | `/og/docs/<page>/image.png` | | `/docs/<page>.md`, the overview `/docs/index.md` | the same, through `proxy.ts` | - A new route goes under `app/docs/`, never at the app's root. `app/llms.mdx/` is the one exception: only `proxy.ts` reaches it. - A route under `app/docs/` that is not a page goes into the `matcher` of `proxy.ts` as an exclusion, or an agent asking for Markdown gets a 404. - Scripts and styles load from `/docs/_next/` (`assetPrefix`). Do not switch to `basePath`: the URLs in `llms.txt`, the Markdown and the MCP answers would lose their `/docs`. - A link in the content is the page's full path: `/docs/cli`, not `/cli`. ## Content - A page's URL is its path under `content/docs/`. The API reference's own pages are in `content/docs/reference/api/`; a page per operation comes from the OpenAPI document (`lib/source.ts`). - `moon run docs:generate` bundles `api/openapi` into `.generated/openapi.mjs`, which `lib/openapi.ts` imports. The content needs no generation step. - A page's Markdown (`/docs/cli.md`, or `/docs/cli` with `Accept: text/markdown`) is its processed Markdown; an operation's is the operation with every schema it references (`docsLlms` in `lib/source.ts`). `llms-full.txt` leaves the operations out. ## Checks `moon run docs:typecheck docs:lint docs:build`, and `moon run docs:start` to look at the build on port 3003. On Vercel the build runs `pnpm run build`, never moon: moon cannot archive the symlinks Vercel's Next.js adapter writes into `.next/output`. ## Tests `tests/` is the site's contract suite (Playwright, `playwright.config.mts`), written against a URL rather than the code. `moon run docs:e2e` runs it against the local build on port 3003; `DOCS_BASE_URL=https://cloud-….vercel.app moon run docs:e2e-deployment` against a deployment of the hosted cloud, with `VERCEL_AUTOMATION_BYPASS_SECRET` for its protection, which [`deployment-checks.yml`](../../.github/workflows/deployment-checks.yml) does for every deployment. The specs use paths only, so one spec proves both. - `/docs/llms.txt` is the suite's page list: every page it names is fetched as HTML, at its `.md` URL and through `Accept: text/markdown`, and every site link in the Markdown must resolve. A page needs no test of its own. - The routes that are not pages each have a test in `tests/agents.spec.ts`: search, the MCP server (`initialize`, `tools/list`, `get_page`), the plain-text answers, the Open Graph image. A new route under `app/docs/` gets one there, and goes into the matcher of `proxy.ts` (above). - `tests/pages.spec.ts` also pins the assets to `/docs/_next/` and `llms-full.txt` to the pages without the API operations. - One browser test (`*.browser.spec.ts`, Chromium) proves the site hydrates and navigates; everything else is HTTP through Playwright's request fixture.