White Papers

AI Integration

Expose your content to coding agents and chat models via /llms.txt and Markdown endpoints.

Coding agents are now a primary audience for documentation. Claude, Cursor, and GitHub Copilot all read docs when answering questions about a library — but only if those docs are exposed in a way agents can consume.

The /llms.txt convention

Anthropic, Cloudflare, and a growing list of sites have standardized on a simple pattern: a text endpoint at /llms.txt that lists every page on the site in Markdown, with links to full-text versions.

This site exposes two endpoints:

When to use which

Use /llms.txt for agents that can navigate (they'll fetch individual pages on demand). Use /llms-full.txt when an agent needs to load the whole library into context at once — for a code review on a small codebase, for instance.

How they're built

Both endpoints are static Next.js routes. The directory is one line per page; the full version concatenates the rendered Markdown.

app/llms.txt/route.ts
import { source } from "@/lib/source";
import { llms } from "fumadocs-core/source";

export const revalidate = false;

export function GET() {
  return new Response(llms(source).index());
}
app/llms-full.txt/route.ts
import { source } from "@/lib/source";
import { getLLMText } from "@/lib/get-llm-text";

export const revalidate = false;

export async function GET() {
  const pages = source.getPages();
  const scanned = await Promise.all(pages.map(getLLMText));
  return new Response(scanned.join("\n\n"), {
    headers: { "Content-Type": "text/plain; charset=utf-8" },
  });
}

revalidate: false makes these endpoints fully static — they're generated at build time and never re-run.

Why static text instead of HTML?

Three reasons:

  1. Token cost. Stripping HTML cuts the size by 60–80% on a typical page. For an agent paying per-token to ingest your docs, that's the difference between a viable read and an abandoned one.
  2. Parser robustness. Markdown has fewer edge cases than HTML. Less ambiguity means fewer parse errors in the agent.
  3. Cache friendliness. Plain text compresses better and serves from edge caches without negotiation headers.

Customizing what agents see

The getLLMText function in lib/get-llm-text.ts decides what goes into /llms-full.txt. The default is title + description + body, but you can:

  • Strip code blocks if your audience is a doc-querying chat and not a code-completion model
  • Add metadata — last-updated date, tags, author — that doesn't appear in the user-facing page
  • Filter pages — exclude internal docs, draft folders, or 404s
lib/get-llm-text.ts
export async function getLLMText(page) {
  const description = page.data.description
    ? `\n> ${page.data.description}\n`
    : "";
  return `# ${page.data.title} (${page.url})${description}`;
}

Privacy

These endpoints make your content trivially scrapable. If any of your docs are sensitive — internal architecture, security postures — make sure they're behind auth and not in the index.

Future: native chat integration

Fumadocs is working on a <AskAI> widget that mounts directly in the sidebar — readers ask questions in plain English and get answers grounded in the site's content. It uses the same /llms-full.txt endpoint as a context source.

Track the Fumadocs AI integrations page for the latest.

How is this guide?

On this page