---
title: Connect a docs site
description: >-
  Build a shared docs app from source docs that live with the code they
  document.
group: docs-site
lastModified: '2026-05-11T20:02:32-07:00'
lastAuthor: 'github-actions[bot]'
---
# Connect a docs site

Use this path when you run a docs app that renders docs from one or more source repos. This is the main Leadtype docs-site model: content stays next to the code it documents, while the docs app clones or checks out that content during build and serves the generated artifacts.

Your framework still owns routes, HTML, styling, and deployment. Leadtype owns the source-to-artifact pipeline.

## The flow

```mermaid
`flowchart LR
repo["source repo / docs/*.mdx"]
clone["checkout or clone / .docs-src/c15t"]
lint["leadtype lint"]
generate["leadtype generate"]
public["public/ / llms.txt · llms-full.txt / docs/*.md / search · agent metadata"]
app["docs app / routing + HTML"]
repo --> clone --> lint --> generate --> public --> app`
```

## Fetch the source repo

In CI, check out the docs source before the docs app build. For a public repo, a shallow clone is enough:

```bash
rm -rf .docs-src/c15t
git clone --depth 1 https://github.com/c15t/c15t .docs-src/c15t
```

For private repos, use your CI platform's checkout action or a read-only deploy key. The important part is that Leadtype receives a normal filesystem path whose root contains `docs/`.

## Lint before generate

Run lint against the fetched docs before writing generated output:

```bash
npx leadtype lint .docs-src/c15t/docs \
  --format github \
  --error-unknown \
  --max-warnings 0
```

Lint fails with file and line context for frontmatter, internal links, placeholders, and schema issues. That is easier to debug than a later app build using stale or partial artifacts.

## Generate hosted artifacts

Point `--src` at the fetched repository root and `--out` at the docs app public directory:

```bash
npx leadtype generate \
  --src .docs-src/c15t \
  --out public \
  --base-url https://docs.example.com \
  --json
```

That command writes:

* `public/llms.txt` and `public/llms-full.txt`
* `public/docs/*.md`
* `public/docs/search-index.json` and `public/docs/search-content.json`
* `public/docs/sitemap.xml`, `sitemap.md`, `robots.txt`, and `agent-readability.json`

Use `--json` in CI so automation can record resolved groups, output files, filters, and search index stats.

## Add sibling sources

Some projects keep docs and release notes side by side instead of putting everything under `docs/`:

```text
.docs-src/c15t/
├── docs/
│   ├── quickstart.mdx
│   └── docs.config.ts
└── changelog/
    └── v1.mdx
```

Repeat `--docs-dir` to include those folders in the same generated corpus:

```bash
npx leadtype generate \
  --src .docs-src/c15t \
  --docs-dir docs \
  --docs-dir changelog \
  --out public \
  --base-url https://docs.example.com
```

By default, extra sources are mounted under `/docs/<folder>`, so `changelog/v1.mdx` becomes `public/docs/changelog/v1.md` and `/docs/changelog/v1.md`.

Use `<dir>=<url-prefix>` when the folder should keep its own public route:

```bash
npx leadtype generate \
  --src .docs-src/c15t \
  --docs-dir docs \
  --docs-dir changelog=/changelog \
  --out public \
  --base-url https://docs.example.com
```

That still keeps an internal generated copy at `public/docs/changelog/v1.md` for search and runtime helpers, but it also writes `public/changelog/v1.md` and emits canonical links such as `/changelog/v1` and `/changelog/v1.md` in `llms.txt`, search metadata, sitemap entries, and `agent-readability.json`.

## Wire it into the app build

Make the source checkout, lint, and generation steps run before the framework build:

```json
{
  "scripts": {
    "docs:fetch": "rm -rf .docs-src/c15t && git clone --depth 1 https://github.com/c15t/c15t .docs-src/c15t",
    "docs:lint": "leadtype lint .docs-src/c15t/docs --format github --error-unknown --max-warnings 0",
    "docs:generate": "leadtype generate --src .docs-src/c15t --out public --base-url https://docs.example.com --json",
    "build": "npm run docs:fetch && npm run docs:lint && npm run docs:generate && vite build"
  }
}
```

If the docs source and docs app live in the same repo, skip `docs:fetch` and point `--src` at `.`:

```bash
npx leadtype lint docs --error-unknown
npx leadtype generate --src . --out public --base-url https://docs.example.com
```

## Configure product and groups

The source repo should own `docs/docs.config.ts` so its groups and product metadata version with the docs. `leadtype generate` loads this file automatically from the docs folder:

```ts
import { defineDocsConfig } from "leadtype";

export default defineDocsConfig({
  product: {
    name: "c15t",
    summary: "Consent infrastructure for modern web apps.",
    bullets: ["Framework integrations.", "Consent primitives.", "Audit-friendly docs."],
    bestStartingPoints: [{ urlPath: "/docs" }, { urlPath: "/docs/quickstart" }],
  },
  groups: [
    { slug: "get-started", title: "Get Started" },
    { slug: "guides", title: "Guides" },
    { slug: "reference", title: "Reference" },
  ],
});
```

Pages declare `group:` in frontmatter. The config declares titles, order, and descriptions. Together they drive navigation, `llms.txt`, search metadata, and package `AGENTS.md` sections. If no config exists, the CLI infers groups from frontmatter, but inferred groups have no descriptions or custom order. See [Frontmatter](/docs/authoring/frontmatter).

## Use scripts for custom pipelines

The CLI is the happy path. Use the library APIs directly when you need custom plugin order, filters, or generated JSON paths. Keep conversion first because LLM files, search, and Agent Readability artifacts read the generated markdown.

```ts
import { convertAllMdx } from "leadtype/convert";
import {
  generateAgentReadabilityArtifacts,
  generateLLMFullContextFiles,
  generateLlmsTxt,
  resolveDocsNavigation,
} from "leadtype/llm";
import { defaultRemarkPlugins, remarkInclude } from "leadtype/remark";
import { generateDocsSearchFiles } from "leadtype/search/node";
import docsConfig from "../.docs-src/c15t/docs/docs.config";

const sourceRoot = ".docs-src/c15t";
const mounts = [
  { pathPrefix: "", urlPrefix: "/docs" },
  { pathPrefix: "changelog", urlPrefix: "/changelog" },
];

await convertAllMdx({
  srcDir: `${sourceRoot}/docs`,
  outDir: "public/docs",
  remarkPlugins: [remarkInclude, ...defaultRemarkPlugins],
  enrichFrontmatterFromGit: true,
});

await convertAllMdx({
  srcDir: `${sourceRoot}/changelog`,
  outDir: "public/docs/changelog",
  remarkPlugins: [remarkInclude, ...defaultRemarkPlugins],
  enrichFrontmatterFromGit: true,
});

await generateLlmsTxt({
  srcDir: sourceRoot,
  outDir: "public",
  baseUrl: "https://docs.example.com",
  product: docsConfig.product,
  groups: docsConfig.groups,
  mounts,
});

await generateLLMFullContextFiles({
  outDir: "public",
  baseUrl: "https://docs.example.com",
  product: { name: docsConfig.product.name },
  groups: docsConfig.groups,
  mounts,
});

await generateDocsSearchFiles({
  outDir: "public",
  baseUrl: "https://docs.example.com",
  mounts,
});

const agentReadability = await generateAgentReadabilityArtifacts({
  outDir: "public",
  baseUrl: "https://docs.example.com",
  product: docsConfig.product,
  groups: docsConfig.groups,
  mounts,
});

const navigation = await resolveDocsNavigation({
  srcDir: sourceRoot,
  baseUrl: "https://docs.example.com",
  groups: docsConfig.groups,
  mounts,
});
```

Write `navigation` to a generated JSON file if your sidebar should use the same group tree as `llms.txt`. Write `agentReadability.manifest` if your runtime needs to merge docs pages with marketing, blog, changelog, or product routes. Custom scripts that need plain static markdown at mounted paths should also copy `public/docs/changelog/*.md` to `public/changelog/*.md`; the CLI does that automatically.

## Wire the app runtime

After generation, choose the runtime pieces your site needs:

* Render source MDX as HTML with your own components: [Render MDX and TOC](/docs/build/render-mdx-and-toc).
* Return markdown for agent requests and serve discovery files: [Optimize docs for agents](/docs/build/optimize-docs-for-agents).
* Add local search and optional source-grounded answers: [Add search](/docs/build/add-search).

## Verify

After a clean build, inspect these files:

* `public/docs/index.md` — converted markdown for the source repo home page.
* `public/llms.txt` — hosted routing index with page-level markdown links.
* `public/llms-full.txt` — all generated markdown docs in one fallback file.
* `public/docs/search-index.json` and `public/docs/search-content.json` — non-empty search files.
* `public/docs/agent-readability.json` — manifest for markdown responses, JSON-LD, sitemap, and robots helpers.

Then start your app and check at least one browser HTML page and one markdown response path.
