# CLI
URL: /docs/cli
LLM index: /llms.txt
Description: Scaffold, upgrade, compact agent docs, generate sitemaps and robots.txt, sync search, and run MCP
Related: /docs/configuration, /docs/guides/agent-friendly-docs, /docs/customization/sitemaps, /docs/customization/llms-txt

# CLI

Use this page when the user asks about this topic: Scaffold, upgrade, compact agent docs, generate sitemaps and robots.txt, sync search, and run MCP.
Keep answers grounded in the exact options, routes, commands, and examples documented here.
If the request moves beyond this page, point to the closest related docs instead of inventing config.

The `@farming-labs/docs` CLI has a few main jobs:

- **`init`** — create a new docs app or add docs to an existing app
- **`upgrade`** — bump the docs packages in an existing project
- **`agent compact`** — generate sibling `agent.md` files from resolved docs pages
- **`agents generate`** — write root and static `AGENTS.md` instructions for coding agents
- **`doctor`** — audit local docs readiness and optional hosted agent routes
- **`mcp`** — run the built-in docs MCP server over stdio for local clients and IDE agents
- **`search sync`** — push docs content into an external search index like Typesense or Algolia
- **`sitemap generate`** — write sitemap metadata plus static `sitemap.xml` and `sitemap.md` files
- **`robots generate`** — write or append an agent-friendly `robots.txt` policy

If you only need the common commands, start here. The framework-specific output and generated file lists are further down this page.

## Quick Start

### From scratch

Use `init --template` when you want a brand new project directory with docs already set up.

<Tabs items={["npm", "pnpm", "yarn", "bun"]}>
  <Tab value="npm">
    ```bash title="terminal"
    npx @farming-labs/docs init --template next --name my-docs
    npx @farming-labs/docs init --template tanstack-start --name my-docs
    npx @farming-labs/docs init --template nuxt --name my-docs
    npx @farming-labs/docs init --template sveltekit --name my-docs
    npx @farming-labs/docs init --template astro --name my-docs
    ```
  </Tab>
  <Tab value="pnpm">
    ```bash title="terminal"
    pnpm dlx @farming-labs/docs init --template next --name my-docs
    pnpm dlx @farming-labs/docs init --template tanstack-start --name my-docs
    pnpm dlx @farming-labs/docs init --template nuxt --name my-docs
    pnpm dlx @farming-labs/docs init --template sveltekit --name my-docs
    pnpm dlx @farming-labs/docs init --template astro --name my-docs
    ```
  </Tab>
  <Tab value="yarn">
    ```bash title="terminal"
    yarn dlx @farming-labs/docs init --template next --name my-docs
    yarn dlx @farming-labs/docs init --template tanstack-start --name my-docs
    yarn dlx @farming-labs/docs init --template nuxt --name my-docs
    yarn dlx @farming-labs/docs init --template sveltekit --name my-docs
    yarn dlx @farming-labs/docs init --template astro --name my-docs
    ```
  </Tab>
  <Tab value="bun">
    ```bash title="terminal"
    bunx @farming-labs/docs init --template next --name my-docs
    bunx @farming-labs/docs init --template tanstack-start --name my-docs
    bunx @farming-labs/docs init --template nuxt --name my-docs
    bunx @farming-labs/docs init --template sveltekit --name my-docs
    bunx @farming-labs/docs init --template astro --name my-docs
    ```
  </Tab>
</Tabs>

This creates a new folder, clones the example template, installs dependencies, and leaves you with a ready-to-run docs app.

### Existing project

Use plain `init` inside an app you already have.

<Tabs items={["npm", "pnpm", "yarn", "bun"]}>
  <Tab value="npm">
    ```bash title="terminal"
    npx @farming-labs/docs init
    ```
  </Tab>
  <Tab value="pnpm">
    ```bash title="terminal"
    pnpm dlx @farming-labs/docs init
    ```
  </Tab>
  <Tab value="yarn">
    ```bash title="terminal"
    yarn dlx @farming-labs/docs init
    ```
  </Tab>
  <Tab value="bun">
    ```bash title="terminal"
    bunx @farming-labs/docs init
    ```
  </Tab>
</Tabs>

Run that from your app root. The CLI will:

1. detect your framework from `package.json` or ask you to choose
2. ask for a theme
3. ask where docs should live, usually `docs`
4. ask about aliases, global CSS, and optional i18n when supported
5. generate the docs files and install the correct `@farming-labs/*` packages

### Upgrade an existing docs project

Use `upgrade` when docs are already installed and you just want newer package versions.

<Tabs items={["npm", "pnpm", "yarn", "bun"]}>
  <Tab value="npm">
    ```bash title="terminal"
    npx @farming-labs/docs upgrade
    ```
  </Tab>
  <Tab value="pnpm">
    ```bash title="terminal"
    pnpm dlx @farming-labs/docs upgrade
    ```
  </Tab>
  <Tab value="yarn">
    ```bash title="terminal"
    yarn dlx @farming-labs/docs upgrade
    ```
  </Tab>
  <Tab value="bun">
    ```bash title="terminal"
    bunx @farming-labs/docs upgrade
    ```
  </Tab>
</Tabs>

By default, the CLI detects your framework and package manager from the current project. If detection is ambiguous, pass `--framework`.

### Run the built-in MCP server locally

Use `mcp` when you want to expose the current docs project to a local MCP client over stdio.

```bash title="terminal"
pnpx @farming-labs/docs mcp
```

If your config lives outside the project root default:

```bash title="terminal"
pnpm exec docs mcp --config src/lib/docs.config.ts
```

To test the HTTP MCP route in this repo instead of stdio, start the Next example:

```bash title="terminal"
pnpm --dir examples/next dev
```

Then point your MCP client or inspector at:

```txt title="~"
http://127.0.0.1:3000/mcp
http://127.0.0.1:3000/.well-known/mcp
```

### Sync an external search index

Use `search sync` when you want to pre-index docs into a hosted search backend instead of waiting
for the first request to trigger sync.

```bash title="terminal"
pnpm dlx @farming-labs/docs search sync --typesense
```

The command reads `.env` and `.env.local` from the current project, scans the docs content based on
`entry` / `contentDir`, and uploads search documents to the selected provider.

Typesense example:

```bash title="terminal"
pnpm dlx @farming-labs/docs search sync --typesense
```

Required env:

```bash title="terminal"
TYPESENSE_URL=https://your-cluster.a1.typesense.net
TYPESENSE_API_KEY=your-admin-capable-key
```

Optional:

```bash title="terminal"
TYPESENSE_COLLECTION=docs
TYPESENSE_MODE=hybrid
TYPESENSE_OLLAMA_MODEL=embeddinggemma
TYPESENSE_OLLAMA_BASE_URL=http://127.0.0.1:11434
```

Algolia example:

```bash title="terminal"
pnpm dlx @farming-labs/docs search sync --algolia
```

Required env:

```bash title="terminal"
ALGOLIA_APP_ID=your-app-id
ALGOLIA_ADMIN_API_KEY=your-admin-key
ALGOLIA_SEARCH_API_KEY=your-search-key
```

### Generate sitemaps

Use `sitemap generate` when you want static `sitemap.xml` and `sitemap.md` files, or when a
server-rendered deployment needs a generated manifest with reliable `lastmod` dates.

```bash title="terminal"
pnpm exec docs sitemap generate
```

By default the command writes:

- `.farming-labs/sitemap-manifest.json`
- `public/sitemap.xml`
- `public/sitemap.md`
- `public/.well-known/sitemap.md`

SvelteKit writes the public files under `static/` instead of `public/`. Use `--config` when your
config lives outside the project root:

```bash title="terminal"
pnpm exec docs sitemap generate --config src/lib/docs.config.ts
```

Useful flags:

| Flag | Description |
| ---- | ----------- |
| `--config <path>` | Use a custom docs config path. |
| `--manifest-only` | Write only `.farming-labs/sitemap-manifest.json`. Useful for server-rendered apps that serve sitemap routes through the runtime. |
| `--public` | Explicitly write public sitemap files. This is already the default unless `--manifest-only` is set. |
| `--check` | Fail if the generated manifest or public sitemap files are stale. |

The generator resolves `lastmod` from each page source file's last git commit date, then falls back
to filesystem modified time. See [Sitemaps](/docs/customization/sitemaps) for route config, static
export setup, and output examples.

### Generate robots.txt

Use `robots generate` when you want a static `robots.txt` file that explicitly allows docs,
markdown, `llms.txt`, sitemap, `AGENTS.md`, skill, MCP, and agent discovery routes.

```bash title="terminal"
pnpm exec docs robots generate
```

By default the command resolves the framework public directory and writes:

- `public/robots.txt` for Next.js, TanStack Start, Astro, and Nuxt projects
- `static/robots.txt` for SvelteKit projects

If the target file already exists, the command keeps it untouched. Use `--append` to add or update
the generated `@farming-labs/docs` block inside an existing policy, or `--force` to replace the
file:

```bash title="terminal"
pnpm exec docs robots generate --append
pnpm exec docs robots generate --force
pnpm exec docs robots generate --path public/robots.txt --append
```

Useful flags:

| Flag | Description |
| ---- | ----------- |
| `--path <path>` | Write to a specific robots.txt path. Positional paths work too. |
| `--append` | Add or update the generated block inside an existing robots.txt. |
| `--force` | Replace the target robots.txt with the generated policy. |
| `--check` | Fail if the generated output would change. |
| `--config <path>` | Use a custom docs config path. |

Configure defaults with `robots` in `docs.config.ts`, then run the command during release prep or
static export builds when you want the policy committed.

### Compact page-level agent docs

For commands, config, and how generated `agent.md` files affect `.md` routes, docs API markdown
output, and MCP, see [Agent compact](#agent-compact) below.

## Agent compact

Use `agent compact` when you want shorter page-level machine docs without hand-writing every
`agent.md`.

What it does:

- resolves the same machine-readable page the runtime already uses: `agent.md`, then `Agent`
  blocks, then normal page markdown
- compresses that document with the Token Company API
- creates missing sibling `agent.md` files and overwrites existing ones
- makes the written `agent.md` the new source for `.md` routes, docs API markdown output, and MCP
  `read_page()`

Common forms:

```bash title="terminal"
pnpm exec docs agent compact installation configuration
pnpm exec docs agent compact /docs/installation
pnpm exec docs agent compact /docs/installation.md
pnpm exec docs agent compact https://docs.example.com/docs/installation
pnpm exec docs agent compact . --dry-run
pnpm exec docs agent compact --page installation --page configuration
pnpm exec docs agent compact --all
pnpm exec docs agent compact --changed
pnpm exec docs agent compact --stale
pnpm exec docs agent compact --stale --include-missing
```

Selection notes:

- positional page arguments are the preferred UX; `--page` is an optional repeatable alias
- page identifiers can be a slug, docs path, `.md` path, full docs URL, or `.` for the root docs
  page
- `--all` compacts every folder-based docs page under the configured `contentDir`
- `--changed` compacts only docs pages changed in the current git working tree, including staged,
  unstaged, and untracked docs changes plus handwritten `agent.md` sources
- `--stale` only refreshes generated `agent.md` files whose source content or compaction settings
  drifted
- `--include-missing` only works with `--stale`, and creates missing `agent.md` files for explicit
  pages or pages that define `agent.tokenBudget`
- only folder-based pages can be written automatically, because the command needs a sibling
  `agent.md` target

Recommended config defaults:

```ts title="docs.config.ts"
export default defineDocs({
  entry: "docs",
  agent: {
    compact: {
      apiKeyEnv: "TOKEN_COMPANY_API_KEY",
      model: "bear-1.2",
      aggressiveness: 0.3,
      protectJson: true,
    },
  },
});
```

If you prefer to reference the env var directly in `docs.config.tsx`, that works too:

```tsx title="docs.config.tsx"
export default defineDocs({
  entry: "docs",
  agent: {
    compact: {
      apiKey: process.env.TOKEN_COMPANY_API_KEY,
    },
  },
});
```

The command loads `.env` and `.env.local` from the current project before it resolves the key, so
the default `TOKEN_COMPANY_API_KEY` env var works without exporting it manually.

Per-page budget overrides live in frontmatter:

```md title="app/docs/installation/page.mdx"
---
title: "Installation"
description: "Install the framework"
agent:
  tokenBudget: 777
---
```

That `agent.tokenBudget` value becomes the compact output target for just that page. It overrides
global `agent.compact.maxOutputTokens` defaults and CLI `--max-output-tokens` values for the same
page. If the page already has a sibling `agent.md`, the command compacts that file. If it does not,
the command compacts the generated machine-readable page output first and then writes the resulting
`agent.md`.

If a global `minOutputTokens` would be higher than the page budget, the CLI clamps it down to the
same page budget before calling the compression API.

Generated `agent.md` files include hidden provenance metadata so the CLI can tell the difference
between:

- **fresh** generated files
- **stale** generated files whose page content or compact settings changed
- **modified** generated files that were edited by hand after generation
- **unknown** handwritten `agent.md` files that do not carry generated provenance
- **missing** files for pages that still use the fallback machine-readable page output

`docs doctor --agent` reports those states, and `docs agent compact --stale` only refreshes the
generated files that are actually stale. Handwritten `agent.md` files still count as explicit
machine context; the doctor reports them as `unknown` freshness instead of treating them as stale.

Useful checks:

```bash title="terminal"
pnpm exec docs agent compact installation --dry-run
pnpm exec docs agent compact --changed
pnpm exec docs agent compact installation
curl "http://127.0.0.1:3000/docs/installation.md"
```

See [Configuration](/docs/configuration) for `agent.compact`, and [Token Efficiency](/docs/token-efficiency)
for when you should use compaction instead of writing `agent.md` by hand.

## Agents Generate

Generate committed `AGENTS.md` files for coding agents and static exports:

```bash title="terminal"
pnpm exec docs agents generate
pnpm exec docs agents generate --check
pnpm exec docs agents generate --force
pnpm exec docs agents generate --path AGENTS.md
```

By default the command writes a managed root `AGENTS.md` plus public copies at `/AGENTS.md`,
`/.well-known/AGENTS.md`, `/AGENT.md`, and `/.well-known/AGENT.md` (`static/` instead of `public/`
for SvelteKit). If a hand-written root `AGENTS.md` or `AGENT.md` already exists, the command keeps
it and uses that content for missing static aliases unless `--force` is passed.

## Doctor

Use `docs doctor --agent` when you want a quick health check for the machine-facing side of the
docs site.

Use `docs doctor --site` when you want a reader-facing audit of navigation, descriptions,
structure, trust signals, feedback, and reading-time cues.

This command does not generate files. It inspects the current project and scores how ready the docs
are for agents, IDEs, and GEO-style crawlers.

What it checks:

- docs config resolution
- docs content discovery
- framework docs API route wiring
- public agent route wiring
- agent discovery spec
- `llms.txt`
- `sitemap.xml` and `sitemap.md`
- `robots.txt`
- `AGENTS.md`
- `skill.md`
- MCP
- search
- agent feedback, which is enabled by default and can be explicitly opted out
- page metadata that feeds markdown output and JSON-LD structured data
- explicit agent-friendly pages
- generated `agent.md` freshness and `agent.compact` defaults

Common forms:

```bash title="terminal"
pnpm exec docs doctor
pnpm exec docs doctor --agent
pnpm exec docs doctor --site
pnpm exec docs doctor --agent --json
pnpm exec docs doctor agent
pnpm exec docs doctor site
pnpm exec docs doctor --agent --config docs.config.tsx
pnpm exec docs doctor --agent --url https://docs.example.com
pnpm exec docs doctor --agent --url https://docs.example.com --json
```

Expected output:

```txt
@farming-labs/docs doctor — agent

Score: 100% (Agent-optimized)
Framework: nextjs • Entry: docs • Content: app/docs
Explicit agent-friendly pages: 37/37 pages (100%)

PASS Docs API route (10/10)
  Found docs API route at app/api/docs/route.ts.
PASS Agent discovery spec (5/5)
  Expected discovery endpoints are available through /.well-known/agent.json, /.well-known/agent, and /api/docs?agent=spec.
PASS Robots agent policy (5/5)
  public/robots.txt advertises agent-readable routes and common AI crawler policy.
PASS Page metadata (5/5)
  37/37 pages include descriptions and 8/37 pages include related links (100% described, 22% related).
PASS Explicit page optimization (10/10)
  37/37 pages define explicit machine-only context (2 agent.md, 35 Agent blocks, 100% of pages).
PASS Agent compaction freshness (5/5)
  0 fresh, 0 stale, 0 modified, 2 unknown, 0 token-budget missing, and 35 other missing pages across compactable docs pages. agent.compact defaults are configured.
```

_Sample abbreviated for brevity. Full runs can also include a `Next steps` section with the most
useful follow-up improvements._

Reader-facing runs use the same overall shape, but print `doctor — site` and score:

- docs config resolution
- docs content discovery
- navigation coverage
- page descriptions
- page structure
- search
- trust signals
- reader feedback
- reading-time cues

When you need structured output instead of terminal text, add `--json`:

```bash title="terminal"
pnpm exec docs doctor --agent --json
pnpm exec docs doctor --site --json
```

Sample shape:

```json title="~"
{
  "mode": "agent",
  "score": 87,
  "maxScore": 100,
  "grade": "Agent-ready",
  "framework": "nextjs",
  "entry": "docs",
  "contentDir": "app/docs",
  "coverage": {
    "explicitPages": 10,
    "totalPages": 41,
    "explicitCoverage": 24
  },
  "checks": [
    {
      "id": "api-route",
      "title": "Docs API route",
      "status": "pass",
      "score": 10,
      "maxScore": 10
    }
  ],
  "recommendations": [
    "Add page-level Agent blocks or agent.md files for workflows where the rendered docs need machine-only hints."
  ]
}
```

The JSON report itself is written to stdout. Separate loader notices, such as config fallback
warnings, are outside the JSON payload.

### Hosted agent checks

Add `--url` when you want the doctor to verify a deployed docs site in addition to the local
project files:

```bash title="terminal"
pnpm exec docs doctor --agent --url https://docs.example.com
```

Without `--url`, the command only inspects the repository: config, content, route files, metadata,
generated sitemap state, and local agent-readiness signals. With `--url`, it also sends real
requests to the hosted site and adds hosted checks to the report.

The hosted pass probes:

- `/.well-known/agent.json`
- `/llms.txt`
- `/llms-full.txt`
- sitemap routes from the discovery spec, usually `/sitemap.xml`, `/sitemap.md`, and `/.well-known/sitemap.md`
- the robots route from the discovery spec, usually `/robots.txt`
- `/AGENTS.md`
- `/.well-known/AGENTS.md`
- `/skill.md`
- `/.well-known/skill.md`
- one representative page markdown route, such as `/docs.md`
- the representative markdown route's canonical `Link` response header
- sampled docs page HTML for `application/ld+json` structured data
- sampled docs page HTML for `<link rel="alternate" type="text/markdown">`
- `/mcp`
- `/.well-known/mcp`
- `https://mcp.<your-domain>/mcp`
- `https://mcp.<your-domain>/`

For MCP, the doctor performs a Streamable HTTP `initialize` request, reuses `mcp-session-id` when
the server returns one, sends `tools/list`, and expects the built-in docs tools:

- `list_pages`
- `get_navigation`
- `search_docs`
- `read_page`

Hosted checks add extra weighted checks, but the top-level score stays normalized to `100%`. The
JSON report also includes the normalized `url` field and hosted check IDs such as
`hosted-agent-discovery`, `hosted-llms`, `hosted-sitemap`, `hosted-robots`, `hosted-skill`,
`hosted-markdown`, `hosted-markdown-canonical`, `hosted-structured-data`,
`hosted-markdown-alternate`, and `hosted-mcp`.

Use this form after deploying, in preview-deployment CI, or any time a site looks healthy locally
but an agent cannot discover the public routes. A hosted failure usually means the deployment is
missing a rewrite, middleware forwarder, or public route, not that the MDX page content itself is
wrong.

How to read it:

- the **score** is a quick summary, not the only thing that matters
- **PASS / WARN / FAIL** lines tell you where the machine-facing surface is strong or thin
- **Explicit agent-friendly pages** means pages that define extra machine-only context through
  `agent.md` or `Agent` blocks
- the **Next steps** section points at the most useful improvements to make next

When to use it:

- before saying a docs site is agent-ready or agent-optimized
- before calling the human docs experience polished or reader-ready
- after changing `docs.config`, route wiring, `.well-known` endpoints, or MCP
- before opening a PR for docs infrastructure work
- in CI if you want a quick quality gate for the agent or human-facing surface
- when another agent, script, or dashboard needs structured results instead of terminal formatting

How essential it is:

- not required to run the framework
- very useful when you care about agent discovery, LLM consumption, MCP, or GEO
- best thought of as a readiness audit for the machine-facing docs layer

## Init

### `init` without `--template`

When you run `init` **without** `--template`, the CLI asks whether you're working with an **existing project** or starting **from scratch**.

| Choice | Best for | What happens |
| ------ | -------- | ------------ |
| `Existing project` | You already have a Next.js, TanStack Start, Nuxt, SvelteKit, or Astro app | The CLI adds docs to the current app |
| `Fresh project` | You want a new docs starter | The CLI creates a new folder from the selected example template |

### From scratch

If you select **Fresh project**, the CLI asks for:

1. **Framework** — Next.js, TanStack Start, Nuxt, SvelteKit, or Astro
2. **Project name** — default is `my-docs`
3. **Package manager** — used for install and the suggested dev command

You can skip those prompts entirely with `--template` and `--name`.

<Tabs items={["npm", "pnpm", "yarn", "bun"]}>
  <Tab value="npm">
    ```bash title="terminal"
    npx @farming-labs/docs init --template next --name my-docs
    ```
  </Tab>
  <Tab value="pnpm">
    ```bash title="terminal"
    pnpm dlx @farming-labs/docs init --template next --name my-docs
    ```
  </Tab>
  <Tab value="yarn">
    ```bash title="terminal"
    yarn dlx @farming-labs/docs init --template next --name my-docs
    ```
  </Tab>
  <Tab value="bun">
    ```bash title="terminal"
    bunx @farming-labs/docs init --template next --name my-docs
    ```
  </Tab>
</Tabs>

Replace `next` with `tanstack-start`, `nuxt`, `sveltekit`, or `astro`.

### Existing project

If you select **Existing project**, the CLI stays in the current folder and wires docs into the app you already have.

1. **Framework** — Auto-detected from `package.json`, or you pick one if detection fails.
2. **Theme** — One of the built-in themes or **Create your own theme** (you’ll be asked for a theme name; it creates `themes/<name>.ts` and `themes/<name>.css`).
3. **Path aliases** — Whether to use `@/`, `$lib/`, or `~/` for imports (framework-dependent).
4. **Entry path** — Where docs live (e.g. `docs`). Press **Enter** to use the default.
5. **Optional API reference** — Whether to scaffold API reference support. If you enable it, the CLI pre-fills the detected API route root (usually `api`) and lets you edit it before writing `apiReference.routeRoot`.
6. **Optional i18n** — Whether to scaffold internationalized docs, which locales to generate, any extra locale codes to add, and which locale should be the default.
7. **Global CSS** — Which file to use (auto-detected if there’s only one, otherwise you pick or type the path; Enter uses the default).
8. The CLI generates config, layout, and sample pages, then detects the package manager from a lockfile when possible. If no lockfile is found, it asks which package manager you want to use before installing dependencies, and can then start the dev server.

Typical flow:

<Tabs items={["npm", "pnpm", "yarn", "bun"]}>
  <Tab value="npm">
    ```bash title="terminal"
    cd my-app
    npx @farming-labs/docs init
    ```
  </Tab>
  <Tab value="pnpm">
    ```bash title="terminal"
    cd my-app
    pnpm dlx @farming-labs/docs init
    ```
  </Tab>
  <Tab value="yarn">
    ```bash title="terminal"
    cd my-app
    yarn dlx @farming-labs/docs init
    ```
  </Tab>
  <Tab value="bun">
    ```bash title="terminal"
    cd my-app
    bunx @farming-labs/docs init
    ```
  </Tab>
</Tabs>

Prompts that show a **placeholder** (e.g. entry path `docs`, project name `my-docs`, theme name `my-theme`) use that value as the default — you can press **Enter** to accept it instead of typing.

### Existing-project flags

Use these to skip the matching prompts during `init`:

| Flag | Description |
| ---- | ----------- |
| `--theme <name>` | Skip the theme prompt |
| `--entry <path>` | Skip the docs entry prompt |
| `--api-reference` | Enable API reference scaffold during `init` |
| `--no-api-reference` | Explicitly skip API reference scaffold |
| `--api-route-root <path>` | Set the detected API route root written to `apiReference.routeRoot` |

Example:

```bash title="terminal"
npx @farming-labs/docs init --theme greentree --entry docs --api-reference --api-route-root internal-api
```

`--api-route-root` is optional. If you omit it, the CLI tries to detect a sensible default from the framework’s route conventions and shows that value as the default in the prompt.

When API reference is enabled through `init`:

- **Next.js** writes the `apiReference` block and `app/api-reference/[[...slug]]/route.ts` (or `src/app/...`).
- **TanStack Start, SvelteKit, Astro, and Nuxt** write the `apiReference` block and also scaffold the minimal `/{path}` handler files so the reference works immediately.

### Optional i18n scaffold

If you enable i18n during `init`, the CLI will:

1. Let you multi-select common locales such as `en`, `fr`, `es`, `de`, `pt`, `ja`, `ko`, `zh`, `ar`, `hi`, and `ru`
2. Let you add custom locale codes such as `pt-BR`
3. Ask which locale should be the default

The generated project gets:

- An `i18n` block in `docs.config.ts` / `src/lib/docs.config.ts`
- Locale content folders like `docs/en`, `docs/fr`, and `docs/zh`
- Framework-specific starter files so routes like `/docs?lang=en` and `/docs?lang=fr` work out of the box

## Upgrade

Upgrade all `@farming-labs/*` docs packages to the latest version, beta channel, or an exact version. Run from your project root; the CLI **auto-detects** your framework from `package.json` and upgrades the right packages for Next.js, TanStack Start, Nuxt, SvelteKit, and Astro.

The CLI also detects your package manager from the lockfile in the current directory (`pnpm-lock.yaml`, `yarn.lock`, `bun.lock`, `bun.lockb`, or `package-lock.json`). If no lockfile is found, it asks which package manager you want to use instead of defaulting to npm.

<Tabs items={["npm", "pnpm", "yarn", "bun"]}>
  <Tab value="npm">
    ```bash title="terminal"
    npx @farming-labs/docs upgrade
    ```
  </Tab>
  <Tab value="pnpm">
    ```bash title="terminal"
    pnpm dlx @farming-labs/docs upgrade
    ```
  </Tab>
  <Tab value="yarn">
    ```bash title="terminal"
    yarn dlx @farming-labs/docs upgrade
    ```
  </Tab>
  <Tab value="bun">
    ```bash title="terminal"
    bunx @farming-labs/docs upgrade
    ```
  </Tab>
</Tabs>

| Framework | Packages upgraded |
| --------- | ------------------------------ |
| Next.js   | `@farming-labs/docs`, `@farming-labs/theme`, `@farming-labs/next` |
| TanStack Start | `@farming-labs/docs`, `@farming-labs/theme`, `@farming-labs/tanstack-start` |
| Nuxt      | `@farming-labs/docs`, `@farming-labs/nuxt`, `@farming-labs/nuxt-theme` |
| SvelteKit | `@farming-labs/docs`, `@farming-labs/svelte`, `@farming-labs/svelte-theme` |
| Astro     | `@farming-labs/docs`, `@farming-labs/astro`, `@farming-labs/astro-theme` |

To specify the framework explicitly (e.g. in a monorepo or when auto-detect fails), use `--framework`:

<Tabs items={["npm", "pnpm", "yarn", "bun"]}>
  <Tab value="npm">
    ```bash title="terminal"
    npx @farming-labs/docs upgrade --framework tanstack-start
    # or
    npx @farming-labs/docs upgrade tanstack-start
    ```
  </Tab>
  <Tab value="pnpm">
    ```bash title="terminal"
    pnpm dlx @farming-labs/docs upgrade --framework tanstack-start
    # or
    pnpm dlx @farming-labs/docs upgrade tanstack-start
    ```
  </Tab>
  <Tab value="yarn">
    ```bash title="terminal"
    yarn dlx @farming-labs/docs upgrade --framework tanstack-start
    # or
    yarn dlx @farming-labs/docs upgrade tanstack-start
    ```
  </Tab>
  <Tab value="bun">
    ```bash title="terminal"
    bunx @farming-labs/docs upgrade --framework tanstack-start
    # or
    bunx @farming-labs/docs upgrade tanstack-start
    ```
  </Tab>
</Tabs>

Valid values: `next`, `tanstack-start`, `nuxt`, `sveltekit`, `astro`.

Use **`--latest`** (default) to install the latest stable release, **`--beta`** to install beta versions, or **`--version <version>`** to install a specific release:

<Tabs items={["npm", "pnpm", "yarn", "bun"]}>
  <Tab value="npm">
    ```bash title="terminal"
    npx @farming-labs/docs upgrade              # latest stable (default)
    npx @farming-labs/docs upgrade --latest     # same
    npx @farming-labs/docs upgrade --beta       # beta versions
    npx @farming-labs/docs upgrade --version 0.1.104
    ```
  </Tab>
  <Tab value="pnpm">
    ```bash title="terminal"
    pnpm dlx @farming-labs/docs upgrade              # latest stable (default)
    pnpm dlx @farming-labs/docs upgrade --latest     # same
    pnpm dlx @farming-labs/docs upgrade --beta       # beta versions
    pnpm dlx @farming-labs/docs upgrade --version 0.1.104
    ```
  </Tab>
  <Tab value="yarn">
    ```bash title="terminal"
    yarn dlx @farming-labs/docs upgrade              # latest stable (default)
    yarn dlx @farming-labs/docs upgrade --latest     # same
    yarn dlx @farming-labs/docs upgrade --beta       # beta versions
    yarn dlx @farming-labs/docs upgrade --version 0.1.104
    ```
  </Tab>
  <Tab value="bun">
    ```bash title="terminal"
    bunx @farming-labs/docs upgrade              # latest stable (default)
    bunx @farming-labs/docs upgrade --latest     # same
    bunx @farming-labs/docs upgrade --beta       # beta versions
    bunx @farming-labs/docs upgrade --version 0.1.104
    ```
  </Tab>
</Tabs>

If you prefer the shorter command form, the CLI also accepts `upgrade@beta` and `upgrade@latest`. For example, `pnpx @farming-labs/docs upgrade@beta` behaves like `pnpx @farming-labs/docs upgrade --beta`.

## Downgrade

Use `downgrade` when you need to move the docs packages back to a lower published version. The CLI auto-detects your framework and package manager the same way `upgrade` does.

Without `--version`, it installs the published version immediately below your current installed `@farming-labs/docs` version:

<Tabs items={["npm", "pnpm", "yarn", "bun"]}>
  <Tab value="npm">
    ```bash title="terminal"
    npx @farming-labs/docs downgrade
    ```
  </Tab>
  <Tab value="pnpm">
    ```bash title="terminal"
    pnpm dlx @farming-labs/docs downgrade
    ```
  </Tab>
  <Tab value="yarn">
    ```bash title="terminal"
    yarn dlx @farming-labs/docs downgrade
    ```
  </Tab>
  <Tab value="bun">
    ```bash title="terminal"
    bunx @farming-labs/docs downgrade
    ```
  </Tab>
</Tabs>

Pass `--version` to choose an exact lower version:

```bash title="terminal"
npx @farming-labs/docs downgrade --version 0.1.103
```

If the requested version is newer than the current installed version, the command stops and points you to `upgrade --version <version>` instead.

## MCP

Run the built-in docs MCP server over stdio from the current project.

```bash title="terminal"
npx @farming-labs/docs mcp
```

The command reads `docs.config.ts[x]` from the current project root by default and reuses the docs graph from your configured `entry` and `contentDir`.

Use `--config` when the config lives somewhere else:

```bash title="terminal"
pnpm exec docs mcp --config src/lib/docs.config.ts
```

The current built-in MCP surface includes:

- `list_pages`
- `get_navigation`
- `search_docs`
- `read_page`

For the HTTP endpoint version, see [MCP Server](/docs/customization/mcp).

## Supported Frameworks

| Framework | Detection | `init` | `upgrade` | `downgrade` |
| --------- | --------- | ------ | --------- | ----------- |
| Next.js | `next` in dependencies | Supported | Supported | Supported |
| TanStack Start | `@tanstack/react-start` in dependencies | Supported | Supported | Supported |
| SvelteKit | `@sveltejs/kit` in dependencies | Supported | Supported | Supported |
| Astro | `astro` in dependencies | Supported | Supported | Supported |
| Nuxt | `nuxt` in dependencies | Supported | Supported | Supported |

## Available Themes

The init CLI offers several built-in themes plus an option to create your own:

| Theme          | Description                                                |
| -------------- | ---------------------------------------------------------- |
| `fumadocs`     | Clean, neutral docs theme (default)                        |
| `darksharp`    | All-black, sharp corners, no rounded edges                 |
| `pixel-border` | Refined dark UI inspired by better-auth.com                |
| `colorful`     | Fumadocs-style neutral theme with description support      |
| `greentree`    | Emerald green accent, Inter font, Mintlify-inspired        |
| `ledger`       | Stripe Docs-inspired product docs shell with navy code panels |
| `command-grid` | Mono-first paper-grid preset inspired by the better-cmdk landing page |
| `concrete`     | Brutalist poster-style theme with offset shadows            |
| `hardline`     | Hard-edge theme with square corners and bold borders        |
| `darkbold`     | Pure monochrome, Geist typography, clean minimalism        |
| `shiny`        | Glossy, modern look with subtle shimmer effects            |
| **Create your own theme** | Scaffolds `themes/<name>.ts` and `themes/<name>.css`; you’re prompted for the theme name (default `my-theme`). See [Creating your own theme](/docs/themes/creating-themes). |

## What it does (Existing project)

When you choose **Existing project**, the CLI does the following (framework-specific files vary):

<Tabs items={["Next.js", "TanStack Start", "SvelteKit", "Astro", "Nuxt"]}>
  <Tab value="Next.js">
    1. **Detects Next.js** via `next` in your `package.json` (or asks you to pick a framework)
    2. **Asks for a theme** — built-in themes or **Create your own theme** (then prompts for theme name; press Enter for default `my-theme`)
    3. **Asks for the entry path** — Default is `docs` (press Enter to accept)
    4. **Asks about path aliases** — Use `@/` alias or relative paths for imports
    5. **Optionally scaffolds i18n** — Generates locale folders like `app/docs/en` and `app/docs/fr`, plus locale-aware wrapper pages
    6. **Generates files:**
       - `docs.config.ts` — Full config with your selected theme
       - `next.config.ts` — Wraps your existing config with `withDocs()`
       - `app/global.css` — Imports Tailwind and theme CSS
       - `app/layout.tsx` — Root layout with RootProvider
       - `app/docs/layout.tsx` — Docs layout
       - `app/docs/page.mdx` — Sample documentation page when i18n is disabled
       - `app/docs/installation/page.mdx` — Sample installation guide when i18n is disabled
       - `app/docs/quickstart/page.mdx` — Sample quickstart guide when i18n is disabled
    7. **Installs dependencies** — `@farming-labs/docs`, `@farming-labs/theme`, `@farming-labs/next`
    8. **Starts the dev server** — Opens your docs at `http://localhost:3000/docs`
  </Tab>
  <Tab value="TanStack Start">
    1. **Detects TanStack Start** via `@tanstack/react-start` in your `package.json` (or asks you to pick a framework)
    2. **Asks for a theme** — built-in themes or **Create your own theme** (then prompts for theme name; press Enter for default `my-theme`)
    3. **Asks about path aliases** — Use `@/` alias or relative paths for imports
    4. **Asks for the entry path** — Default is `docs` (press Enter to accept)
    5. **Skips the built-in i18n scaffold** so the generated TanStack routes stay minimal and working
    6. **Generates files:**
       - `docs.config.ts` — Full config with your selected theme
       - `src/lib/docs.server.ts` — TanStack docs server
       - `src/lib/docs.functions.ts` — Server function wrapper for page loading
       - `src/routes/{entry}/index.tsx` — Docs index route
       - `src/routes/{entry}/$.tsx` — Catch-all docs route
       - `src/routes/api/docs.ts` — Search and AI API route
       - `src/routes/$.ts` — Public `llms.txt`, sitemap, `.well-known`, `.md`, and MCP aliases
       - `src/styles/app.css` — Imports Tailwind and theme CSS
       - `docs/page.mdx` — Sample documentation page
       - `docs/installation/page.mdx` — Sample installation guide
       - `docs/quickstart/page.mdx` — Sample quickstart guide
    7. **Updates existing app files when needed** — Injects `RootProvider` into `src/routes/__root.tsx` and adds `docsMdx()` / Tailwind plugins to `vite.config.ts`
    8. **Installs dependencies** — `@farming-labs/docs`, `@farming-labs/theme`, `@farming-labs/tanstack-start`
    9. **Starts the dev server** — Opens your docs at `http://localhost:5173/docs`

    > In this repo's examples and in other monorepos, keep those `@farming-labs/*` dependencies linked locally while testing unpublished changes. CI and Vercel on Node 22 should consume the built adapter entrypoints, not raw `src/*.ts` files from `node_modules`.
  </Tab>
  <Tab value="SvelteKit">
    1. **Detects SvelteKit** via `@sveltejs/kit` in your `package.json` (or asks you to pick a framework)
    2. **Asks for a theme** — built-in themes or **Create your own theme** (then prompts for theme name; press Enter for default)
    3. **Asks for the entry path** — Default is `docs` (press Enter to accept)
    4. **Asks about path aliases** — Use `$lib/` alias or relative paths for imports
    5. **Optionally scaffolds i18n** — Generates locale folders like `docs/en` and `docs/fr` plus a docs root page for `/docs?lang=...`
    6. **Generates files (does not touch `svelte.config.js`):**
       - `src/lib/docs.config.ts` — Full config with your selected theme
       - `src/lib/docs.server.ts` — Server-side docs loader with `import.meta.glob` for production builds
       - `src/routes/docs/+layout.svelte` — Docs layout component
       - `src/routes/docs/+layout.server.js` — Layout data loader
       - `src/routes/docs/[...slug]/+page.svelte` — Dynamic page component
       - `src/routes/docs/+page.svelte` — Generated when i18n is enabled
       - `src/routes/api/docs/+server.ts` — Search and AI API route
       - `src/hooks.server.ts` — Public `llms.txt`, sitemap, `.well-known`, `.md`, and MCP aliases
       - `src/app.css` — Theme CSS import
       - `docs/page.md` — Sample documentation page
       - `docs/installation/page.md` — Sample installation guide
       - `docs/quickstart/page.md` — Sample quickstart guide
    7. **Installs dependencies** — `@farming-labs/docs`, `@farming-labs/svelte`, `@farming-labs/svelte-theme`
    8. **Starts the dev server** — Opens your docs at `http://localhost:5173/docs`

    > **Production note**: The generated `docs.server.ts` uses `import.meta.glob` to bundle your markdown files at build time. This is required for serverless deployments (Vercel, Netlify, etc.) where the filesystem is not available at runtime.

  </Tab>
  <Tab value="Astro">
    1. **Detects Astro** via `astro` in your `package.json` (or asks you to pick a framework)
    2. **Asks for a theme** — built-in themes or **Create your own theme** (then prompts for theme name; press Enter for default)
    3. **Asks for the entry path** — Default is `docs` (press Enter to accept)
    4. **Optionally scaffolds i18n** — Generates locale folders like `docs/en` and `docs/fr`
    5. **Generates files:**
       - `src/lib/docs.config.ts` — Full config with your selected theme
       - `src/lib/docs.server.ts` — Server-side docs loader with `import.meta.glob` for production builds
       - `src/pages/{entry}/index.astro` — Docs index page
       - `src/pages/{entry}/[...slug].astro` — Dynamic page component
       - `src/pages/api/{entry}.ts` — API route for search and AI
       - `src/middleware.ts` — Public `llms.txt`, sitemap, `.well-known`, `.md`, and MCP aliases
       - `astro.config.mjs` — Astro config with SSR enabled
       - `docs/page.md` — Sample documentation page
       - `docs/installation/page.md` — Sample installation guide
       - `docs/quickstart/page.md` — Sample quickstart guide
    6. **Installs dependencies** — `@farming-labs/docs`, `@farming-labs/astro`, `@farming-labs/astro-theme`
    7. **Starts the dev server** — Opens your docs at `http://localhost:4321/docs`

    > **Production note**: The generated `docs.server.ts` uses `import.meta.glob` to bundle your markdown files at build time. This is required for serverless deployments (Vercel, Netlify, etc.) where the filesystem is not available at runtime.

  </Tab>
  <Tab value="Nuxt">
    1. **Detects Nuxt** via `nuxt` in your `package.json` (or asks you to pick a framework)
    2. **Asks for a theme** — built-in themes or **Create your own theme** (then prompts for theme name; press Enter for default)
    3. **Asks for the entry path** — Default is `docs` (press Enter to accept)
    4. **Optionally scaffolds i18n** — Generates locale folders like `docs/en` and `docs/fr`
    5. **Generates files:**
       - `docs.config.ts` — Full config with your selected theme
       - `nuxt.config.ts` — Nuxt config with theme CSS and server assets
       - `server/api/docs.ts` — docs data, search, AI, and page loading
       - `server/middleware/docs-public.ts` — public `llms.txt`, sitemap, `.well-known`, `.md`, and MCP aliases
       - `pages/docs/[[...slug]].vue` — Catch-all page component that handles the docs index and nested docs routes
       - `docs/page.md` — Sample documentation page
       - `docs/installation/page.md` — Sample installation guide
       - `docs/quickstart/page.md` — Sample quickstart guide
    6. **Installs dependencies** — `@farming-labs/docs`, `@farming-labs/nuxt`, `@farming-labs/nuxt-theme`
    7. **Starts the dev server** — Opens your docs at `http://localhost:3000/docs`
  </Tab>
</Tabs>

## Example Output

<Tabs items={["Next.js", "TanStack Start", "SvelteKit", "Astro", "Nuxt"]}>
  <Tab value="Next.js">
    ```text title="next-js-project-structure.txt"
    $ npx @farming-labs/docs init

      ┌ @farming-labs/docs
      │
      ◆ Are you adding docs to an existing project or starting fresh?
      │ ● Existing project — Add docs to the current app in this directory
      │ ○ Fresh project — Bootstrap a new app from a template
      │
      ◆ Detected framework: Next.js
      │
      ◆ Which theme would you like to use?
      │ ● fumadocs (default)
      │ ○ darksharp
      │ ○ pixel-border
      │ ○ colorful
      │ ○ greentree
      │ ○ concrete
      │ ○ command-grid
      │ ○ hardline
      │ ○ darkbold
      │ ○ shiny
      │ ○ Create your own theme
      │
      ◆ Where should your docs live?
      │ docs  (press Enter for default)
      │
      ◆ Scaffold i18n support?
      │ ● Yes
      │ ○ No
      │
      ◆ Which locales should we scaffold?
      │ ◻ en
      │ ◼ fr
      │ ◼ de
      │
      ◆ Any additional locale codes? (comma-separated, optional)
      │ pt-BR
      │
      ◆ Which locale should be the default?
      │ ● fr
      │ ○ de
      │ ○ pt-BR
      │
      ◆ Use path aliases for imports?
      │ ● Yes (@/ alias)
      │ ○ No (relative paths)
      │
      ◇ Generated docs.config.ts
      ◇ Generated next.config.ts
      ◇ Generated app/global.css
      ◇ Generated app/components/locale-doc-page.tsx
      ◇ Generated app/docs/page.mdx
      ◇ Generated app/docs/installation/page.mdx
      ◇ Generated app/docs/quickstart/page.mdx
      ◇ Generated app/docs/fr/page.mdx
      ◇ Generated app/docs/fr/installation/page.mdx
      ◇ Generated app/docs/fr/quickstart/page.mdx
      ◇ Generated app/docs/de/page.mdx
      ◇ Generated app/docs/de/installation/page.mdx
      ◇ Generated app/docs/de/quickstart/page.mdx
      ◇ Generated app/docs/pt-BR/page.mdx
      ◇ Generated app/docs/pt-BR/installation/page.mdx
      ◇ Generated app/docs/pt-BR/quickstart/page.mdx
      │
      ◇ Installing dependencies...
      ◇ Starting dev server...
      │
      └ Done! Open http://localhost:3000/docs
    ```

  </Tab>
  <Tab value="TanStack Start">
    ```text title="tanstack-start-project-structure.txt"
    $ npx @farming-labs/docs init

      ┌ @farming-labs/docs
      │
      ◆ Are you adding docs to an existing project or starting fresh?
      │ ● Existing project
      │ ○ Fresh project
      │
      ◆ Detected framework: TanStack Start
      │
      ◆ Which theme would you like to use?
      │ ● fumadocs (default)
      │ ○ darksharp
      │ ○ pixel-border
      │ ○ colorful
      │ ○ greentree
      │ ○ concrete
      │ ○ command-grid
      │ ○ hardline
      │ ○ darkbold
      │ ○ shiny
      │ ○ Create your own theme
      │
      ◆ Use path aliases for imports?
      │ ● Yes (@/ alias)
      │ ○ No (relative paths)
      │
      ◆ Where should your docs live?
      │ docs  (press Enter for default)
      │
      ℹ Skipping i18n scaffold for TanStack Start. Configure localized routes manually if needed.
      │
      ◇ Generated docs.config.ts
      ◇ Generated src/lib/docs.server.ts
      ◇ Generated src/lib/docs.functions.ts
      ◇ Generated src/routes/docs/index.tsx
      ◇ Generated src/routes/docs/$.tsx
      ◇ Generated src/routes/api/docs.ts
      ◇ Updated src/routes/__root.tsx
      ◇ Updated vite.config.ts
      ◇ Updated src/styles/app.css
      │
      ◇ Installing dependencies...
      ◇ Starting dev server...
      │
      └ Done! Open http://localhost:5173/docs
    ```

  </Tab>
  <Tab value="SvelteKit">
    ```text title="sveltekit-project-structure.txt"
    $ npx @farming-labs/docs init

      ┌ @farming-labs/docs
      │
      ◆ Are you adding docs to an existing project or starting fresh?
      │ ● Existing project
      │ ○ Fresh project
      │
      ◆ Detected framework: SvelteKit
      │
      ◆ Which theme would you like to use?
      │ ● fumadocs (default)
      │ ○ darksharp
      │ ○ pixel-border
      │ ○ colorful
      │ ○ darkbold
      │ ○ shiny
      │ ○ greentree
      │ ○ concrete
      │ ○ command-grid
      │ ○ hardline
      │
      ◆ Entry path for docs:
      │ docs
      │
      ◆ Scaffold i18n support?
      │ ● Yes
      │ ○ No
      │
      ◆ Which locales should we scaffold?
      │ ◼ en
      │ ◼ fr
      │ ◻ de
      │
      ◆ Any additional locale codes? (comma-separated, optional)
      │
      ◆ Which locale should be the default?
      │ ● en
      │ ○ fr
      │
      ◆ Use path aliases for imports?
      │ ● Yes ($lib/ alias)
      │ ○ No (relative paths)
      │
      ◇ Generated src/lib/docs.config.ts
      ◇ Generated src/lib/docs.server.ts
      ◇ Generated src/routes/docs/+layout.svelte
      ◇ Generated src/routes/docs/+layout.server.js
      ◇ Generated src/routes/docs/[...slug]/+page.svelte
      ◇ Generated src/routes/api/docs/+server.ts
      ◇ Generated src/hooks.server.ts
      ◇ Generated docs/page.md
      ◇ Generated docs/installation/page.md
      ◇ Generated docs/quickstart/page.md
      ◇ Generated docs/en/page.md
      ◇ Generated docs/en/installation/page.md
      ◇ Generated docs/en/quickstart/page.md
      ◇ Generated docs/fr/page.md
      ◇ Generated docs/fr/installation/page.md
      ◇ Generated docs/fr/quickstart/page.md
      │
      ◇ Installing dependencies...
      ◇ Starting dev server...
      │
      └ Done! Open http://localhost:5173/docs
    ```

  </Tab>
  <Tab value="Astro">
    ```text title="astro-project-structure.txt"
    $ npx @farming-labs/docs init

      ┌ @farming-labs/docs
      │
      ◆ Are you adding docs to an existing project or starting fresh?
      │ ● Existing project
      │ ○ Fresh project
      │
      ◆ Detected framework: Astro
      │
      ◆ Which theme would you like to use?
      │ ● fumadocs (default)
      │ ○ darksharp
      │ ○ pixel-border
      │ ○ colorful
      │ ○ darkbold
      │ ○ shiny
      │ ○ greentree
      │ ○ concrete
      │ ○ command-grid
      │ ○ hardline
      │
      ◆ Entry path for docs:
      │ docs
      │
      ◆ Scaffold i18n support?
      │ ● Yes
      │ ○ No
      │
      ◆ Which locales should we scaffold?
      │ ◼ en
      │ ◼ ja
      │ ◻ fr
      │
      ◆ Any additional locale codes? (comma-separated, optional)
      │ zh-CN
      │
      ◆ Which locale should be the default?
      │ ● en
      │ ○ ja
      │ ○ zh-CN
      │
      ◇ Generated src/lib/docs.config.ts
      ◇ Generated src/lib/docs.server.ts
      ◇ Generated src/pages/docs/index.astro
      ◇ Generated src/pages/docs/[...slug].astro
      ◇ Generated src/pages/api/docs.ts
      ◇ Generated src/middleware.ts
      ◇ Generated astro.config.mjs
      ◇ Generated docs/page.md
      ◇ Generated docs/installation/page.md
      ◇ Generated docs/quickstart/page.md
      ◇ Generated docs/en/page.md
      ◇ Generated docs/en/installation/page.md
      ◇ Generated docs/en/quickstart/page.md
      ◇ Generated docs/ja/page.md
      ◇ Generated docs/ja/installation/page.md
      ◇ Generated docs/ja/quickstart/page.md
      ◇ Generated docs/zh-CN/page.md
      ◇ Generated docs/zh-CN/installation/page.md
      ◇ Generated docs/zh-CN/quickstart/page.md
      │
      ◇ Installing dependencies...
      ◇ Starting dev server...
      │
      └ Done! Open http://localhost:4321/docs
    ```

  </Tab>
  <Tab value="Nuxt">
    ```text title="nuxt-project-structure.txt"
    $ npx @farming-labs/docs init

      ┌ @farming-labs/docs
      │
      ◆ Are you adding docs to an existing project or starting fresh?
      │ ● Existing project
      │ ○ Fresh project
      │
      ◆ Detected framework: Nuxt
      │
      ◆ Which theme would you like to use?
      │ ● fumadocs (default)
      │ ○ darksharp
      │ ○ pixel-border
      │ ○ colorful
      │ ○ darkbold
      │ ○ shiny
      │ ○ greentree
      │ ○ concrete
      │ ○ command-grid
      │ ○ hardline
      │
      ◆ Entry path for docs:
      │ docs
      │
      ◆ Scaffold i18n support?
      │ ● Yes
      │ ○ No
      │
      ◆ Which locales should we scaffold?
      │ ◼ en
      │ ◼ es
      │ ◻ fr
      │
      ◆ Any additional locale codes? (comma-separated, optional)
      │
      ◆ Which locale should be the default?
      │ ● en
      │ ○ es
      │
      ◇ Generated docs.config.ts
      ◇ Generated nuxt.config.ts
      ◇ Generated server/api/docs.ts
      ◇ Generated server/middleware/docs-public.ts
      ◇ Generated pages/docs/[...slug].vue
      ◇ Generated docs/page.md
      ◇ Generated docs/installation/page.md
      ◇ Generated docs/quickstart/page.md
      ◇ Generated docs/en/page.md
      ◇ Generated docs/en/installation/page.md
      ◇ Generated docs/en/quickstart/page.md
      ◇ Generated docs/es/page.md
      ◇ Generated docs/es/installation/page.md
      ◇ Generated docs/es/quickstart/page.md
      │
      ◇ Installing dependencies...
      ◇ Starting dev server...
      │
      └ Done! Open http://localhost:3000/docs
    ```

  </Tab>
</Tabs>

## Flags

| Flag                    | Description                                                                 |
| ----------------------- | --------------------------------------------------------------------------- |
| `--template <name>`     | Bootstrap a project: `next`, `tanstack-start`, `nuxt`, `sveltekit`, or `astro`. Use with `--name`. |
| `--name <project>`      | Project folder name when using `--template`; prompt if omitted (e.g. `my-docs`) |
| `--theme <name>`        | Skip theme prompt: `fumadocs`, `darksharp`, `pixel-border`, `colorful`, `darkbold`, `shiny`, `ledger`, `greentree`, `concrete`, `command-grid`, `hardline` |
| `--entry <path>`        | Skip entry path prompt (e.g. `--entry docs`)                                |

**Starting from scratch?** Use `--template` with `--name <project>`. The CLI bootstraps a project with the given name, installs dependencies, and then you run `cd <project> && pnpm run dev` to start.

## Manual Code

Here is every file the CLI generates, ready to copy-paste if you prefer manual setup.

<Callout type="info" title="Theme CSS in global styles">
  For each framework, add your **theme's CSS** to the global stylesheet (or config) shown below. The import must match the theme you use in `docs.config` (e.g. `default`, `greentree`, `darksharp`). Without it, docs pages will lack the correct styling.
</Callout>

<Callout type="info" title="Rename to docs.config.ts when using JSX">
  If your config includes JSX or React nodes, rename `docs.config.ts` to `docs.config.ts`.
  This applies when you add things like a custom `nav.title`, React icons, or React-based components directly in the config file.
</Callout>

<Tabs items={["Next.js", "TanStack Start", "SvelteKit", "Astro", "Nuxt"]}>
  <Tab value="Next.js">
    **`docs.config.ts`**

    ```tsx title="docs.config.ts"
    import { defineDocs } from "@farming-labs/docs";
    import { fumadocs } from "@farming-labs/theme";

    export default defineDocs({
      entry: "docs",
      theme: fumadocs(),
      nav: { title: "My Docs" },
      breadcrumb: { enabled: true },
      metadata: {
        titleTemplate: "%s – Docs",
        description: "My documentation site",
      },
    });
    ```

    **`next.config.ts`**

    ```ts title="next.config.ts"
    import { withDocs } from "@farming-labs/next/config";
    export default withDocs({});
    ```

    **`app/global.css`** — add your theme's CSS here so docs styling applies.

    ```css title="app/global.css"
    @import "tailwindcss";
    @import "@farming-labs/theme/default/css";
    ```

    **`app/layout.tsx`**

    ```tsx title="app/layout.tsx"
    import { RootProvider } from "@farming-labs/theme";
    import "./global.css";

    export default function RootLayout({
      children,
    }: {
      children: React.ReactNode;
    }) {
      return (
        <html lang="en" suppressHydrationWarning>
          <body>
            <RootProvider>{children}</RootProvider>
          </body>
        </html>
      );
    }
    ```

    **`app/docs/layout.tsx`**

    ```tsx title="app/docs/layout.tsx"
    import { createDocsLayout } from "@farming-labs/theme";
    import config from "@/docs.config";

    const { DocsLayout } = createDocsLayout(config);

    export default function Layout({
      children,
    }: {
      children: React.ReactNode;
    }) {
      return <DocsLayout>{children}</DocsLayout>;
    }
    ```

    **`app/docs/page.mdx`** (sample page)

    ```mdx title="app/docs/page.mdx"
    ---
    title: "Introduction"
    description: "Welcome to the docs"
    icon: "book"
    ---

    # Welcome

    This is your documentation home page.
    ```

    > If you chose `darksharp` or `pixel-border`, the CSS import line will differ:
    > - Darksharp: `@import "@farming-labs/theme/darksharp/css";`
    > - Pixel Border: `@import "@farming-labs/theme/pixel-border/css";`

  </Tab>
  <Tab value="TanStack Start">
    **`docs.config.ts`**

    ```tsx title="docs.config.ts"
    import { defineDocs } from "@farming-labs/docs";
    import { fumadocs } from "@farming-labs/theme";

    export default defineDocs({
      entry: "docs",
      contentDir: "docs",
      theme: fumadocs(),
      nav: {
        title: "My Docs",
        url: "/docs",
      },
      breadcrumb: { enabled: true },
      metadata: {
        titleTemplate: "%s – Docs",
        description: "My documentation site",
      },
    });
    ```

    **`vite.config.ts`**

    ```ts title="vite.config.ts"
    import { defineConfig } from "vite";
    import tailwindcss from "@tailwindcss/vite";
    import tsconfigPaths from "vite-tsconfig-paths";
    import { tanstackStart } from "@tanstack/react-start/plugin/vite";
    import { docsMdx } from "@farming-labs/tanstack-start/vite";

    export default defineConfig({
      plugins: [tailwindcss(), docsMdx(), tsconfigPaths({ ignoreConfigErrors: true }), tanstackStart()],
    });
    ```

    **`src/styles/app.css`** — add your theme's CSS here so docs styling applies.

    ```css title="src/styles/app.css"
    @import "tailwindcss";
    @import "@farming-labs/theme/default/css";
    ```

    **`src/routes/__root.tsx`**

    ```tsx title="src/routes/__root.tsx"
    import appCss from "@/styles/app.css?url";
    import { createRootRoute, HeadContent, Outlet, Scripts } from "@tanstack/react-router";
    import { RootProvider } from "@farming-labs/theme/tanstack";

    export const Route = createRootRoute({
      head: () => ({
        links: [{ rel: "stylesheet", href: appCss }],
      }),
      component: RootComponent,
    });

    function RootComponent() {
      return (
        <html lang="en" suppressHydrationWarning>
          <head>
            <HeadContent />
          </head>
          <body>
            <RootProvider>
              <Outlet />
            </RootProvider>
            <Scripts />
          </body>
        </html>
      );
    }
    ```

    **`src/lib/docs.server.ts`**

    ```ts title="src/lib/docs.server.ts"
    import { createDocsServer } from "@farming-labs/tanstack-start/server";
    import docsConfig from "../../docs.config";

    export const docsServer = createDocsServer({
      ...docsConfig,
      rootDir: process.cwd(),
    });
    ```

    **`src/routes/docs/index.tsx`**

    ```tsx title="src/routes/docs/index.tsx"
    import { createFileRoute } from "@tanstack/react-router";
    import { TanstackDocsPage } from "@farming-labs/tanstack-start/react";
    import { loadDocPage } from "@/lib/docs.functions";
    import docsConfig from "../../../docs.config";

    export const Route = createFileRoute("/docs/")({
      loader: () => loadDocPage({ data: { pathname: "/docs" } }),
      component: () => <TanstackDocsPage config={docsConfig} data={Route.useLoaderData()} />,
    });
    ```

    > TanStack Start uses the same `@farming-labs/theme` theme package as Next.js. Keep the theme name in `docs.config.ts` and `src/styles/app.css` aligned.

  </Tab>
  <Tab value="SvelteKit">
    **`src/lib/docs.config.ts`**

    ```ts title="src/lib/docs.config.ts"
    import { defineDocs } from "@farming-labs/docs";
    import { fumadocs } from "@farming-labs/svelte-theme";

    export default defineDocs({
      entry: "docs",
      contentDir: "docs",
      theme: fumadocs(),
      nav: {
        title: "My Docs",
        url: "/docs",
      },
      breadcrumb: { enabled: true },
      metadata: {
        titleTemplate: "%s – Docs",
        description: "My documentation site",
      },
    });
    ```

    **`src/lib/docs.server.ts`**

    ```ts title="src/lib/docs.server.ts"
    import { createDocsServer } from "@farming-labs/svelte/server";
    import config from "./docs.config";

    // preloading for production
    const contentFiles = import.meta.glob(
      ["/docs/**/*.{md,mdx,svx}", "/AGENTS.md", "/AGENT.md", "/skill.md", "/.farming-labs/sitemap-manifest.json"],
      {
        query: "?raw",
        import: "default",
        eager: true,
      },
    ) as Record<string, string>;

    export const { load, GET, POST } = createDocsServer({
      ...config,
      _preloadedContent: contentFiles,
    });
    ```

    **`src/routes/docs/+layout.svelte`**

    ```svelte title="src/routes/docs/+layout.svelte"
    <script>
      import { DocsLayout } from "@farming-labs/svelte-theme";
      import config from "../../lib/docs.config";

      let { data, children } = $props();
    </script>

    <DocsLayout tree={data.tree} {config}>
      {@render children()}
    </DocsLayout>
    ```

    **`src/routes/docs/+layout.server.js`**

    ```js title="src/routes/docs/+layout.server.js"
    export { load } from "../../lib/docs.server";
    ```

    **`src/routes/docs/[...slug]/+page.svelte`**

    ```svelte title="src/routes/docs/[...slug]/+page.svelte"
    <script>
      import { DocsContent } from "@farming-labs/svelte-theme";
      import config from "../../../lib/docs.config";

      let { data } = $props();
    </script>

    <DocsContent {data} {config} />
    ```

    **`src/routes/api/docs/+server.js`** (search & AI)

    ```js title="src/routes/api/docs/+server.js"
    export { GET, POST } from "../../../lib/docs.server";
    ```

    **`src/app.css`** — add your theme's CSS here so docs styling applies.

    ```css title="src/app.css"
    @import "@farming-labs/svelte-theme/fumadocs/css";
    ```

    **`docs/page.md`** (sample page)

    ```md title="docs/page.md"
    ---
    title: "Introduction"
    description: "Welcome to the docs"
    icon: "book"
    ---

    # Welcome

    This is your documentation home page.
    ```

    > If you chose `darksharp` or `pixel-border`, swap the theme factory and CSS:
    > - Darksharp: `import { darksharp } from "@farming-labs/svelte-theme"` + `@import "@farming-labs/svelte-theme/darksharp/css";`
    > - Pixel Border: `import { pixelBorder } from "@farming-labs/svelte-theme"` + `@import "@farming-labs/svelte-theme/pixel-border/css";`

  </Tab>
  <Tab value="Astro">
    **`src/lib/docs.config.ts`**

    ```ts title="src/lib/docs.config.ts"
    import { defineDocs } from "@farming-labs/docs";
    import { fumadocs } from "@farming-labs/astro-theme";

    export default defineDocs({
      entry: "docs",
      contentDir: "docs",
      theme: fumadocs(),
      nav: {
        title: "My Docs",
        url: "/docs",
      },
      breadcrumb: { enabled: true },
      metadata: {
        titleTemplate: "%s – Docs",
        description: "My documentation site",
      },
    });
    ```

    **`src/lib/docs.server.ts`**

    ```ts title="src/lib/docs.server.ts"
    import { createDocsServer } from "@farming-labs/astro/server";
    import config from "./docs.config";

    const contentFiles = import.meta.glob(
      ["/docs/**/*.{md,mdx}", "/AGENTS.md", "/AGENT.md", "/skill.md", "/.farming-labs/sitemap-manifest.json"],
      {
        query: "?raw",
        import: "default",
        eager: true,
      },
    ) as Record<string, string>;

    export const { load, GET, POST } = createDocsServer({
      ...config,
      _preloadedContent: contentFiles,
    });
    ```

    **`src/pages/docs/index.astro`** and **`src/pages/docs/[...slug].astro`** — import your theme's CSS in each (e.g. `@farming-labs/astro-theme/css` for default; use `greentree/css` etc. for other themes).

    ```astro title="src/pages/docs/[...slug].astro"
    ---
    import DocsLayout from "@farming-labs/astro-theme/src/components/DocsLayout.astro";
    import DocsContent from "@farming-labs/astro-theme/src/components/DocsContent.astro";
    import config from "../../lib/docs.config";
    import { load } from "../../lib/docs.server";
    import "@farming-labs/astro-theme/css";

    const data = await load(Astro.url.pathname);
    ---

    <html lang="en">
      <head><title>{data.title} – Docs</title></head>
      <body>
        <DocsLayout tree={data.tree} config={config}>
          <DocsContent data={data} config={config} />
        </DocsLayout>
      </body>
    </html>
    ```

    **`src/pages/api/docs.ts`** (search & AI)

    ```ts title="src/pages/api/docs.ts"
    import type { APIRoute } from "astro";
    import { GET as docsGET, POST as docsPOST } from "../../lib/docs.server";

    export const GET: APIRoute = async ({ request }) => docsGET({ request });
    export const POST: APIRoute = async ({ request }) => docsPOST({ request });
    ```

    **`astro.config.mjs`**

    ```js title="astro.config.mjs"
    import { defineConfig } from "astro/config";
    export default defineConfig({ output: "server" });
    ```

    **`docs/page.md`** (sample page)

    ```md title="docs/page.md"
    ---
    title: "Introduction"
    description: "Welcome to the docs"
    icon: "book"
    ---

    # Welcome

    This is your documentation home page.
    ```

    > If you chose `darksharp` or `pixel-border`, swap the theme factory and CSS:
    > - Darksharp: `import { darksharp } from "@farming-labs/astro-theme"` + `@farming-labs/astro-theme/darksharp/css`
    > - Pixel Border: `import { pixelBorder } from "@farming-labs/astro-theme"` + `@farming-labs/astro-theme/pixel-border/css`

  </Tab>
  <Tab value="Nuxt">
    **`docs.config.ts`**

    ```ts title="docs.config.ts"
    import { defineDocs } from "@farming-labs/docs";
    import { fumadocs } from "@farming-labs/nuxt-theme/fumadocs";

    export default defineDocs({
      entry: "docs",
      contentDir: "docs",
      theme: fumadocs(),
      nav: {
        title: "My Docs",
        url: "/docs",
      },
      breadcrumb: { enabled: true },
      metadata: {
        titleTemplate: "%s – Docs",
        description: "My documentation site",
      },
    });
    ```

    **`nuxt.config.ts`** — add your theme's CSS in the `css` array so docs styling applies.

    ```ts title="nuxt.config.ts"
    export default defineNuxtConfig({
      css: ["@farming-labs/nuxt-theme/fumadocs/css"],
      nitro: {
        serverAssets: [{ baseName: "docs", dir: "../docs" }],
      },
    });
    ```

    **`server/api/docs.ts`** (search, AI, and page loading) and **`server/middleware/docs-public.ts`** (public agent/GEO aliases)

    **`pages/docs/[...slug].vue`**

    ```vue title="pages/docs/[...slug].vue"
    <script setup lang="ts">
    import { DocsLayout, DocsContent } from "@farming-labs/nuxt-theme";
    import config from "~/docs.config";
    const route = useRoute();
    const pathname = computed(() => route.path);
    const { data } = await useFetch("/api/docs", {
      query: { pathname }, watch: [pathname],
    });
    </script>
    <template>
      <DocsLayout :tree="data.tree" :config="config">
        <DocsContent :data="data" :config="config" />
      </DocsLayout>
    </template>
    ```

    **`docs/page.md`** (sample page)

    ```md title="docs/page.md"
    ---
    title: "Introduction"
    description: "Welcome to the docs"
    icon: "book"
    ---

    # Welcome

    This is your documentation home page.
    ```

    > If you chose `darksharp` or `pixel-border`, swap the theme factory and CSS:
    > - Darksharp: `import { darksharp } from "@farming-labs/nuxt-theme"` + `@farming-labs/nuxt-theme/darksharp/css`
    > - Pixel Border: `import { pixelBorder } from "@farming-labs/nuxt-theme"` + `@farming-labs/nuxt-theme/pixel-border/css`

  </Tab>
</Tabs>

## Project Structure

After running `init`, your project will look like this:

<Tabs items={["Next.js", "TanStack Start", "SvelteKit", "Astro", "Nuxt"]}>
  <Tab value="Next.js">
```text
my-app/
├── docs.config.ts        # Docs configuration
├── next.config.ts        # Next.js config with withDocs()
├── app/
│   ├── global.css        # Theme CSS import
│   ├── layout.tsx        # Root layout
│   └── docs/
│       ├── layout.tsx    # Docs layout
│       ├── page.mdx      # /docs
│       ├── installation/
│       │   └── page.mdx  # /docs/installation
│       └── quickstart/
│           └── page.mdx  # /docs/quickstart
└── package.json
```
  </Tab>
  <Tab value="TanStack Start">
```text title="tanstack-start-project-structure.txt"
my-app/
├── docs.config.ts             # Docs configuration
├── docs/                      # Markdown content
│   ├── page.mdx               # /docs
│   ├── installation/
│   │   └── page.mdx           # /docs/installation
│   └── quickstart/
│       └── page.mdx           # /docs/quickstart
├── src/
│   ├── lib/
│   │   ├── docs.functions.ts  # Server function wrapper
│   │   └── docs.server.ts     # Docs server
│   ├── routes/
│   │   ├── __root.tsx         # Root layout with RootProvider
│   │   ├── $.ts               # Public docs aliases
│   │   ├── api/
│   │   │   └── docs.ts        # Search & AI API route
│   │   └── docs/
│   │       ├── $.tsx          # Dynamic page
│   │       └── index.tsx      # /docs
│   └── styles/
│       └── app.css            # Theme CSS import
├── vite.config.ts             # docsMdx() + TanStack Start plugin
└── package.json
```
  </Tab>
  <Tab value="SvelteKit">
```text title="sveltekit-project-structure.txt"
my-app/
├── docs/                     # Markdown content
│   ├── page.md               # /docs
│   ├── installation/
│   │   └── page.md           # /docs/installation
│   └── quickstart/
│       └── page.md           # /docs/quickstart
├── src/
│   ├── app.css               # Theme CSS import
│   ├── hooks.server.ts       # Public docs aliases
│   ├── lib/
│   │   ├── docs.config.ts    # Docs configuration
│   │   └── docs.server.ts    # Server loader + content bundling
│   └── routes/
│       ├── api/
│       │   └── docs/
│       │       └── +server.ts      # Search & AI API route
│       └── docs/
│           ├── +layout.svelte      # Docs layout
│           ├── +layout.server.js   # Layout data loader
│           └── [...slug]/
│               └── +page.svelte    # Dynamic page
└── package.json
```
  </Tab>
  <Tab value="Astro">
```text title="astro-project-structure.txt"
my-app/
├── astro.config.mjs          # Astro config with SSR
├── docs/                     # Markdown content
│   ├── page.md               # /docs
│   ├── installation/
│   │   └── page.md           # /docs/installation
│   └── quickstart/
│       └── page.md           # /docs/quickstart
├── src/
│   ├── lib/
│   │   ├── docs.config.ts    # Docs configuration
│   │   └── docs.server.ts    # Server loader + content bundling
│   ├── middleware.ts         # Public docs aliases
│   └── pages/
│       ├── api/
│       │   └── docs.ts       # Search & AI API route
│       └── docs/
│           ├── index.astro   # /docs
│           └── [...slug].astro  # /docs/*
└── package.json
```
  </Tab>
  <Tab value="Nuxt">
```text title="nuxt-project-structure.txt"
my-app/
├── docs.config.ts            # Docs configuration
├── nuxt.config.ts            # Nuxt config with theme CSS
├── docs/                     # Markdown content
│   ├── page.md               # /docs
│   ├── installation/
│   │   └── page.md           # /docs/installation
│   └── quickstart/
│       └── page.md           # /docs/quickstart
├── server/
│   ├── api/
│   │   └── docs.ts           # Search & AI API route
│   └── middleware/
│       └── docs-public.ts    # Public docs aliases
├── pages/
│   └── docs/
│       └── [...slug].vue     # Dynamic page
└── package.json
```
  </Tab>
</Tabs>