CLI
The @farming-labs/docs CLI has a few main jobs:
init— create a new docs app or add docs to an existing appupgrade— bump the docs packages in an existing projectagent compact— generate siblingagent.mdfiles from resolved docs pagesagents generate— write root and staticAGENTS.mdinstructions for coding agentsdoctor— audit local docs readiness and optional hosted agent routesmcp— run the built-in docs MCP server over stdio for local clients and IDE agentssearch sync— push docs content into an external search index like Typesense or Algoliasitemap generate— write sitemap metadata plus staticsitemap.xmlandsitemap.mdfilesrobots generate— write or append an agent-friendlyrobots.txtpolicy
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.
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-docspnpm 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-docsyarn 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-docsbunx @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-docsThis 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.
npx @farming-labs/docs initpnpm dlx @farming-labs/docs inityarn dlx @farming-labs/docs initbunx @farming-labs/docs initRun that from your app root. The CLI will:
- detect your framework from
package.jsonor ask you to choose - ask for a theme
- ask where docs should live, usually
docs - ask about aliases, global CSS, and optional i18n when supported
- 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.
npx @farming-labs/docs upgradepnpm dlx @farming-labs/docs upgradeyarn dlx @farming-labs/docs upgradebunx @farming-labs/docs upgradeBy 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.
pnpx @farming-labs/docs mcpIf your config lives outside the project root default:
pnpm exec docs mcp --config src/lib/docs.config.tsTo test the HTTP MCP route in this repo instead of stdio, start the Next example:
pnpm --dir examples/next devThen point your MCP client or inspector at:
http://127.0.0.1:3000/mcp
http://127.0.0.1:3000/.well-known/mcpSync 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.
pnpm dlx @farming-labs/docs search sync --typesenseThe 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:
pnpm dlx @farming-labs/docs search sync --typesenseRequired env:
TYPESENSE_URL=https://your-cluster.a1.typesense.net
TYPESENSE_API_KEY=your-admin-capable-keyOptional:
TYPESENSE_COLLECTION=docs
TYPESENSE_MODE=hybrid
TYPESENSE_OLLAMA_MODEL=embeddinggemma
TYPESENSE_OLLAMA_BASE_URL=http://127.0.0.1:11434Algolia example:
pnpm dlx @farming-labs/docs search sync --algoliaRequired env:
ALGOLIA_APP_ID=your-app-id
ALGOLIA_ADMIN_API_KEY=your-admin-key
ALGOLIA_SEARCH_API_KEY=your-search-keyGenerate 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.
pnpm exec docs sitemap generateBy default the command writes:
.farming-labs/sitemap-manifest.jsonpublic/sitemap.xmlpublic/sitemap.mdpublic/.well-known/sitemap.md
SvelteKit writes the public files under static/ instead of public/. Use --config when your
config lives outside the project root:
pnpm exec docs sitemap generate --config src/lib/docs.config.tsUseful 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 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.
pnpm exec docs robots generateBy default the command resolves the framework public directory and writes:
public/robots.txtfor Next.js, TanStack Start, Astro, and Nuxt projectsstatic/robots.txtfor 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:
pnpm exec docs robots generate --append
pnpm exec docs robots generate --force
pnpm exec docs robots generate --path public/robots.txt --appendUseful 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 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, thenAgentblocks, then normal page markdown - compresses that document with the Token Company API
- creates missing sibling
agent.mdfiles and overwrites existing ones - makes the written
agent.mdthe new source for.mdroutes, docs API markdown output, and MCPread_page()
Common forms:
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-missingSelection notes:
- positional page arguments are the preferred UX;
--pageis an optional repeatable alias - page identifiers can be a slug, docs path,
.mdpath, full docs URL, or.for the root docs page --allcompacts every folder-based docs page under the configuredcontentDir--changedcompacts only docs pages changed in the current git working tree, including staged, unstaged, and untracked docs changes plus handwrittenagent.mdsources--staleonly refreshes generatedagent.mdfiles whose source content or compaction settings drifted--include-missingonly works with--stale, and creates missingagent.mdfiles for explicit pages or pages that defineagent.tokenBudget- only folder-based pages can be written automatically, because the command needs a sibling
agent.mdtarget
Recommended config defaults:
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:
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:
---
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.mdfiles 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:
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 for agent.compact, and 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:
pnpm exec docs agents generate
pnpm exec docs agents generate --check
pnpm exec docs agents generate --force
pnpm exec docs agents generate --path AGENTS.mdBy 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.txtsitemap.xmlandsitemap.mdrobots.txtAGENTS.mdskill.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.mdfreshness andagent.compactdefaults
Common forms:
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 --jsonExpected output:
@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:
pnpm exec docs doctor --agent --json
pnpm exec docs doctor --site --jsonSample shape:
{
"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:
pnpm exec docs doctor --agent --url https://docs.example.comWithout --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
Linkresponse header - sampled docs page HTML for
application/ld+jsonstructured data - sampled docs page HTML for
<link rel="alternate" type="text/markdown"> /mcp/.well-known/mcphttps://mcp.<your-domain>/mcphttps://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_pagesget_navigationsearch_docsread_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.mdorAgentblocks - 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-knownendpoints, 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:
- Framework — Next.js, TanStack Start, Nuxt, SvelteKit, or Astro
- Project name — default is
my-docs - Package manager — used for install and the suggested dev command
You can skip those prompts entirely with --template and --name.
npx @farming-labs/docs init --template next --name my-docspnpm dlx @farming-labs/docs init --template next --name my-docsyarn dlx @farming-labs/docs init --template next --name my-docsbunx @farming-labs/docs init --template next --name my-docsReplace 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.
- Framework — Auto-detected from
package.json, or you pick one if detection fails. - Theme — One of the built-in themes or Create your own theme (you’ll be asked for a theme name; it creates
themes/<name>.tsandthemes/<name>.css). - Path aliases — Whether to use
@/,$lib/, or~/for imports (framework-dependent). - Entry path — Where docs live (e.g.
docs). Press Enter to use the default. - 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 writingapiReference.routeRoot. - Optional i18n — Whether to scaffold internationalized docs, which locales to generate, any extra locale codes to add, and which locale should be the default.
- Global CSS — Which file to use (auto-detected if there’s only one, otherwise you pick or type the path; Enter uses the default).
- 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:
cd my-app
npx @farming-labs/docs initcd my-app
pnpm dlx @farming-labs/docs initcd my-app
yarn dlx @farming-labs/docs initcd my-app
bunx @farming-labs/docs initPrompts 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:
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
apiReferenceblock andapp/api-reference/[[...slug]]/route.ts(orsrc/app/...). - TanStack Start, SvelteKit, Astro, and Nuxt write the
apiReferenceblock 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:
- Let you multi-select common locales such as
en,fr,es,de,pt,ja,ko,zh,ar,hi, andru - Let you add custom locale codes such as
pt-BR - Ask which locale should be the default
The generated project gets:
- An
i18nblock indocs.config.ts/src/lib/docs.config.ts - Locale content folders like
docs/en,docs/fr, anddocs/zh - Framework-specific starter files so routes like
/docs?lang=enand/docs?lang=frwork 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.
npx @farming-labs/docs upgradepnpm dlx @farming-labs/docs upgradeyarn dlx @farming-labs/docs upgradebunx @farming-labs/docs upgrade| 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:
npx @farming-labs/docs upgrade --framework tanstack-start
# or
npx @farming-labs/docs upgrade tanstack-startpnpm dlx @farming-labs/docs upgrade --framework tanstack-start
# or
pnpm dlx @farming-labs/docs upgrade tanstack-startyarn dlx @farming-labs/docs upgrade --framework tanstack-start
# or
yarn dlx @farming-labs/docs upgrade tanstack-startbunx @farming-labs/docs upgrade --framework tanstack-start
# or
bunx @farming-labs/docs upgrade tanstack-startValid 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:
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.104pnpm 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.104yarn 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.104bunx @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.104If 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:
npx @farming-labs/docs downgradepnpm dlx @farming-labs/docs downgradeyarn dlx @farming-labs/docs downgradebunx @farming-labs/docs downgradePass --version to choose an exact lower version:
npx @farming-labs/docs downgrade --version 0.1.103If 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.
npx @farming-labs/docs mcpThe 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:
pnpm exec docs mcp --config src/lib/docs.config.tsThe current built-in MCP surface includes:
list_pagesget_navigationsearch_docsread_page
For the HTTP endpoint version, see MCP Server.
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. |
What it does (Existing project)
When you choose Existing project, the CLI does the following (framework-specific files vary):
- Detects Next.js via
nextin yourpackage.json(or asks you to pick a framework) - Asks for a theme — built-in themes or Create your own theme (then prompts for theme name; press Enter for default
my-theme) - Asks for the entry path — Default is
docs(press Enter to accept) - Asks about path aliases — Use
@/alias or relative paths for imports - Optionally scaffolds i18n — Generates locale folders like
app/docs/enandapp/docs/fr, plus locale-aware wrapper pages - Generates files:
docs.config.ts— Full config with your selected themenext.config.ts— Wraps your existing config withwithDocs()app/global.css— Imports Tailwind and theme CSSapp/layout.tsx— Root layout with RootProviderapp/docs/layout.tsx— Docs layoutapp/docs/page.mdx— Sample documentation page when i18n is disabledapp/docs/installation/page.mdx— Sample installation guide when i18n is disabledapp/docs/quickstart/page.mdx— Sample quickstart guide when i18n is disabled
- Installs dependencies —
@farming-labs/docs,@farming-labs/theme,@farming-labs/next - Starts the dev server — Opens your docs at
http://localhost:3000/docs
- Detects TanStack Start via
@tanstack/react-startin yourpackage.json(or asks you to pick a framework) - Asks for a theme — built-in themes or Create your own theme (then prompts for theme name; press Enter for default
my-theme) - Asks about path aliases — Use
@/alias or relative paths for imports - Asks for the entry path — Default is
docs(press Enter to accept) - Skips the built-in i18n scaffold so the generated TanStack routes stay minimal and working
- Generates files:
docs.config.ts— Full config with your selected themesrc/lib/docs.server.ts— TanStack docs serversrc/lib/docs.functions.ts— Server function wrapper for page loadingsrc/routes/{entry}/index.tsx— Docs index routesrc/routes/{entry}/$.tsx— Catch-all docs routesrc/routes/api/docs.ts— Search and AI API routesrc/routes/$.ts— Publicllms.txt, sitemap,.well-known,.md, and MCP aliasessrc/styles/app.css— Imports Tailwind and theme CSSdocs/page.mdx— Sample documentation pagedocs/installation/page.mdx— Sample installation guidedocs/quickstart/page.mdx— Sample quickstart guide
- Updates existing app files when needed — Injects
RootProviderintosrc/routes/__root.tsxand addsdocsMdx()/ Tailwind plugins tovite.config.ts - Installs dependencies —
@farming-labs/docs,@farming-labs/theme,@farming-labs/tanstack-start - 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 rawsrc/*.tsfiles fromnode_modules.
- Detects SvelteKit via
@sveltejs/kitin yourpackage.json(or asks you to pick a framework) - Asks for a theme — built-in themes or Create your own theme (then prompts for theme name; press Enter for default)
- Asks for the entry path — Default is
docs(press Enter to accept) - Asks about path aliases — Use
$lib/alias or relative paths for imports - Optionally scaffolds i18n — Generates locale folders like
docs/enanddocs/frplus a docs root page for/docs?lang=... - Generates files (does not touch
svelte.config.js):src/lib/docs.config.ts— Full config with your selected themesrc/lib/docs.server.ts— Server-side docs loader withimport.meta.globfor production buildssrc/routes/docs/+layout.svelte— Docs layout componentsrc/routes/docs/+layout.server.js— Layout data loadersrc/routes/docs/[...slug]/+page.svelte— Dynamic page componentsrc/routes/docs/+page.svelte— Generated when i18n is enabledsrc/routes/api/docs/+server.ts— Search and AI API routesrc/hooks.server.ts— Publicllms.txt, sitemap,.well-known,.md, and MCP aliasessrc/app.css— Theme CSS importdocs/page.md— Sample documentation pagedocs/installation/page.md— Sample installation guidedocs/quickstart/page.md— Sample quickstart guide
- Installs dependencies —
@farming-labs/docs,@farming-labs/svelte,@farming-labs/svelte-theme - Starts the dev server — Opens your docs at
http://localhost:5173/docs
Production note: The generated
docs.server.tsusesimport.meta.globto bundle your markdown files at build time. This is required for serverless deployments (Vercel, Netlify, etc.) where the filesystem is not available at runtime.
- Detects Astro via
astroin yourpackage.json(or asks you to pick a framework) - Asks for a theme — built-in themes or Create your own theme (then prompts for theme name; press Enter for default)
- Asks for the entry path — Default is
docs(press Enter to accept) - Optionally scaffolds i18n — Generates locale folders like
docs/enanddocs/fr - Generates files:
src/lib/docs.config.ts— Full config with your selected themesrc/lib/docs.server.ts— Server-side docs loader withimport.meta.globfor production buildssrc/pages/{entry}/index.astro— Docs index pagesrc/pages/{entry}/[...slug].astro— Dynamic page componentsrc/pages/api/{entry}.ts— API route for search and AIsrc/middleware.ts— Publicllms.txt, sitemap,.well-known,.md, and MCP aliasesastro.config.mjs— Astro config with SSR enableddocs/page.md— Sample documentation pagedocs/installation/page.md— Sample installation guidedocs/quickstart/page.md— Sample quickstart guide
- Installs dependencies —
@farming-labs/docs,@farming-labs/astro,@farming-labs/astro-theme - Starts the dev server — Opens your docs at
http://localhost:4321/docs
Production note: The generated
docs.server.tsusesimport.meta.globto bundle your markdown files at build time. This is required for serverless deployments (Vercel, Netlify, etc.) where the filesystem is not available at runtime.
- Detects Nuxt via
nuxtin yourpackage.json(or asks you to pick a framework) - Asks for a theme — built-in themes or Create your own theme (then prompts for theme name; press Enter for default)
- Asks for the entry path — Default is
docs(press Enter to accept) - Optionally scaffolds i18n — Generates locale folders like
docs/enanddocs/fr - Generates files:
docs.config.ts— Full config with your selected themenuxt.config.ts— Nuxt config with theme CSS and server assetsserver/api/docs.ts— docs data, search, AI, and page loadingserver/middleware/docs-public.ts— publicllms.txt, sitemap,.well-known,.md, and MCP aliasespages/docs/[[...slug]].vue— Catch-all page component that handles the docs index and nested docs routesdocs/page.md— Sample documentation pagedocs/installation/page.md— Sample installation guidedocs/quickstart/page.md— Sample quickstart guide
- Installs dependencies —
@farming-labs/docs,@farming-labs/nuxt,@farming-labs/nuxt-theme - Starts the dev server — Opens your docs at
http://localhost:3000/docs
Example Output
$ 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$ 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$ 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$ 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$ 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/docsFlags
| 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.
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.
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.
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
import { withDocs } from "@farming-labs/next/config";
export default withDocs({});app/global.css — add your theme's CSS here so docs styling applies.
@import "tailwindcss";
@import "@farming-labs/theme/default/css";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
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)
---
title: "Introduction"
description: "Welcome to the docs"
icon: "book"
---
# Welcome
This is your documentation home page.If you chose
darksharporpixel-border, the CSS import line will differ:
- Darksharp:
@import "@farming-labs/theme/darksharp/css";- Pixel Border:
@import "@farming-labs/theme/pixel-border/css";
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
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.
@import "tailwindcss";
@import "@farming-labs/theme/default/css";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
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
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/themetheme package as Next.js. Keep the theme name indocs.config.tsandsrc/styles/app.cssaligned.
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
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
<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
export { load } from "../../lib/docs.server";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)
export { GET, POST } from "../../../lib/docs.server";src/app.css — add your theme's CSS here so docs styling applies.
@import "@farming-labs/svelte-theme/fumadocs/css";docs/page.md (sample page)
---
title: "Introduction"
description: "Welcome to the docs"
icon: "book"
---
# Welcome
This is your documentation home page.If you chose
darksharporpixel-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";
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
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).
---
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)
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
import { defineConfig } from "astro/config";
export default defineConfig({ output: "server" });docs/page.md (sample page)
---
title: "Introduction"
description: "Welcome to the docs"
icon: "book"
---
# Welcome
This is your documentation home page.If you chose
darksharporpixel-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
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.
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
<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)
---
title: "Introduction"
description: "Welcome to the docs"
icon: "book"
---
# Welcome
This is your documentation home page.If you chose
darksharporpixel-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
Project Structure
After running init, your project will look like this:
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.jsonmy-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.jsonmy-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.jsonmy-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.jsonmy-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.jsonHow is this guide?