Every Nimbus site publishes a plain-text copy of itself for agents and other tools. New sites have the routes already.
What every site publishes
| Path | What it is |
|---|---|
/<slug>/index.md |
The page as clean Markdown, with components converted to text. Links to its .mdx source. |
/<slug>/index.mdx |
The page’s authored source, with imports, JSX and directives. Not published for API pages. |
/llms.txt |
An index of the current docs: top-level pages and a link to each section’s index. |
/<section>/llms.txt |
An index for each top-level group and collection, and each folder below it, linked from its parent. |
/llms-full.txt |
Every current page in one Markdown document. Over 25 MiB, it becomes an index of one llms-full.txt per section. |
/<version>/llms.txt |
An index for each older docs version, which the site index leaves out. |
On a versioned site, every Markdown version’s frontmatter has a version: key, so agents can pin a version. Every page’s head also carries JSON-LD structured data. Pages with draft: true or noindex: true are left out of the indexes; see Docs for agents for the full rules.
Add your own frontmatter
Each page’s Markdown version carries title, description, image and, where the page has one, version. To add other fields, declare them in schemaFields and name them in markdownFields:
changelog: defineCollection(
docsCollection({
base: "changelog",
schemaFields: {
date: z.coerce.date(),
tags: z.array(z.string()).default([]),
},
markdownFields: ["date", "tags"],
}),
),The fields follow Nimbus’s own keys, in the order you list them, in both index.md and index.mdx. Values can be strings, numbers, booleans, dates, or arrays of those; a field a page leaves empty is left out.
A date at midnight UTC is written as 2026-07-02, and any other time in full with Z. Write dates without a time, or with an offset (2026-07-02T09:30:00+02:00): a time without an offset is read in the build machine’s timezone.
Add the routes to an older site
A site created before these routes shipped adds five endpoints. The Nimbus integration must already be present in astro.config.ts.
1. Add alternate page versions
Create the clean Markdown version:
import { markdownRoute } from "@cloudflare/nimbus-docs/agent-endpoints";
export const { GET, getStaticPaths } = markdownRoute();Create the MDX source version:
import { markdownSourceRoute } from "@cloudflare/nimbus-docs/agent-endpoints";
export const { GET, getStaticPaths } = markdownSourceRoute();These two routes serve every collection, including docs versions, a blog at /blog, and API references. API pages have a .md version but no .mdx source. Pages in hidden versions have neither. Collections you add later need no new route files. To customize the output for some or all pages, see Override a default.
On a static site these routes build ahead of time. With a rendering policy, a page’s Markdown follows its collection’s rendering mode automatically: a request-rendered collection serves its Markdown and MDX versions on request from these same routes, and prerendered collections keep their static files. Run nimbus-docs check --fix after changing the policy to write each route’s mode into the file.
2. Add the site index
Create the site-wide discovery index:
import { llmsRoute } from "@cloudflare/nimbus-docs/agent-endpoints";
export const { GET } = llmsRoute();3. Add llms-full.txt
Create the file containing all discoverable documentation:
import { llmsFullRoute } from "@cloudflare/nimbus-docs/agent-endpoints";
export const { GET } = llmsFullRoute();This file is optional. Without it, Nimbus doesn’t build llms-full.txt and llms.txt doesn’t link to it.
When the document would be over 25 MiB (Cloudflare’s per-file limit), /llms-full.txt becomes an index of one llms-full.txt per section, such as /reference/llms-full.txt. Nimbus serves those files from a route of its own, beside this one, so there’s nothing to add. Wrapping this route’s GET doesn’t change the section files.
- A section under the limit holds its pages in full, as
llms-full.txtdoes. The index gives its size. - A section over the limit is itself an index: it links its sub-folders’ files, marked “split further” where they’re split again, and links each of its own pages’ Markdown. A folder over the limit with no sub-folders is a list of links to its pages, marked “links to its pages”.
- Pages at the top of the site are linked from
/llms-full.txt, not included in it.
The build log lists the files it wrote. On Cloudflare (the adapter, or a wrangler file), the build warns about any agent file over 25 MiB, including a single page’s Markdown, because that file would fail the deploy.
4. Add section indexes
Create the route for paths such as /writing/llms.txt and /reference/functions/llms.txt:
import { llmsSectionRoute } from "@cloudflare/nimbus-docs/agent-endpoints";
export const { GET, getStaticPaths } = llmsSectionRoute();Each section index lists the pages in its folder, then links each sub-folder’s llms.txt under “Sections”, so an agent descends one level at a time. A folder with only an index.mdx is a page of its parent.
A section is named by its index page’s sidebar.group.label, then its title, then the folder name.
Each GET returns 404 for an unknown section. Rendered on request, it returns a 500 without details when an index can’t be read, and logs the error. To change what a route serves, see Override a default.
The llms.txt endpoints follow the rendering policy too: the site index and llms-full.txt use rendering.default, and a section index uses its collection’s mode.
The build warns when a prerendered collection’s Markdown or llms.txt has no route, and names the route to add.
Verify
Run a production build, then start Astro’s production preview:
pnpm build
pnpm previewIn another terminal, replace guides/install and writing with routes that exist in the project. If Astro has a deployment base, prefix each path with it:
curl --fail http://localhost:4321/guides/install/index.md
curl --fail http://localhost:4321/guides/install/index.mdx
curl --fail http://localhost:4321/llms.txt
curl --fail http://localhost:4321/llms-full.txt
curl --fail http://localhost:4321/writing/llms.txtEach command should return content with a success status. A 404 means the route file is missing, or the collection isn’t a page collection; wrap a custom loader with withNimbusMarkdown().
If a section index is missing, check that the section has discoverable pages and appears in /llms.txt.
Direct rendering
renderEntryAsMarkdown() and getEntryMarkdown() remain available for entry bodies that do not contain <Render>. Passing a body with <Render> throws. Use the endpoints above for alternate authored Markdown versions and llms.txt indexes. getEntryMarkdown() also loads API citation data and is intended for prerendered routes.