> For AI agents: the complete documentation index is available at https://rspress.rs/llms.txt, the full documentation bundle is available at https://rspress.rs/llms-full.txt.

# @rspress/plugin-llms 

[Source Code](https://github.com/web-infra-dev/rspress/tree/main/packages/plugin-llms)

Generate [llms.txt](https://llmstxt.org/) related files for your Rspress site so large language models can better understand your documentation.

:::warning

`@rspress/plugin-llms` uses remark to process MDX source files, so it does not support rendering dynamic content such as React Hooks or custom components.

This plugin is intended only as a fallback when SSG and SSG-MD cannot be enabled because the code is incompatible with SSR. Prefer the [SSG-MD](https://rspress.rs/guide/basic/ssg-md.md) feature when possible.

:::

## Installation


```sh [npm]
npm add @rspress/plugin-llms -D
```

```sh [yarn]
yarn add @rspress/plugin-llms -D
```

```sh [pnpm]
pnpm add @rspress/plugin-llms -D
```

```sh [bun]
bun add @rspress/plugin-llms -D
```

```sh [deno]
deno add npm:@rspress/plugin-llms -D
```

## Usage

### 1. Install the plugin

Add the following configuration:

```ts
// rspress.config.ts
import { defineConfig } from '@rspress/core';
import { pluginLlms } from '@rspress/plugin-llms';

export default defineConfig({
  plugins: [pluginLlms()],
});
```

Then run `rspress build`. During output generation, the plugin also generates `llms.txt`, `llms-full.txt`, and corresponding Markdown files for each route in the output directory, based on the navbar and sidebar.

### 2. UI display

To help readers use your documentation with large language models, add a copy Markdown button at the top of the page, similar to this website.

#### Using themeConfig (Recommended)

The simplest way is to enable `llmsUI` in `themeConfig`. This will automatically add `LlmsCopyButton` and `LlmsViewOptions` components below all H1 headers (or in the outline panel) without requiring custom theme code:

```ts title="rspress.config.ts"
import { defineConfig } from '@rspress/core';
import { pluginLlms } from '@rspress/plugin-llms';

export default defineConfig({
  plugins: [pluginLlms()],
  themeConfig: {
    llmsUI: true,
    // Or with custom options:
    // llmsUI: {
    //   injectLlmsHint: false, // Disable the HTML/Markdown directive hint for LLMs
    //   viewOptions: ['markdownLink', 'chatgpt', 'claude'],
    //   placement: 'outline', // Display in outline panel instead of below H1
    // },
  },
});
```

#### Using custom theme

If you need more control, you can use [custom theme](https://rspress.rs/guide/basic/custom-theme.md) to add a copy Markdown button.

Add a copy button to all pages:

```tsx title="theme/index.tsx"
import { getCustomMDXComponent as basicGetCustomMDXComponent } from '@rspress/core/theme-original';
import {
  LlmsContainer,
  LlmsCopyButton,
  LlmsViewOptions,
} from '@rspress/plugin-llms/runtime';

function getCustomMDXComponent() {
  const { h1: H1, ...mdxComponents } = basicGetCustomMDXComponent();

  const MyH1 = ({ ...props }) => {
    return (
      <>
        <H1 {...props} />
        {/* [!code highlight:5] */}
        <LlmsContainer>
          <LlmsCopyButton />
          {/* Add LlmsViewOptions as needed */}
          <LlmsViewOptions />
        </LlmsContainer>
      </>
    );
  };
  return {
    ...mdxComponents,
    h1: MyH1,
  };
}

export { getCustomMDXComponent };
export * from '@rspress/core/theme-original';
```

Add a copy button to specific pages:

```mdx title="docs/hello-world.mdx"
# Hello world

<LlmsContainer>
  <LlmsCopyButton />
  <LlmsViewOptions /> {/* Add LlmsViewOptions as needed */}
</LlmsContainer>

This is a sample document.
```

## Configuration

This plugin accepts an options object with the following type:

- **Type**:


```ts
interface LlmsTxt {
  name: string;
  onTitleGenerate?: (context: {
    title: string | undefined;
    description: string | undefined;
  }) => string;
  onLineGenerate?: (page: PageIndexInfo) => string;
  onAfterLlmsTxtGenerate?: (llmsTxtContent: string) => string;
}

interface MdFiles {
  mdxToMd?: boolean;
  remarkPlugins?: PluggableList;
}

interface LlmsFullTxt {
  name: string;
}

export interface Options {
  llmsTxt?: false | LlmsTxt;
  mdFiles?: false | MdFiles;
  llmsFullTxt?: false | LlmsFullTxt;
  include?: (context: { page: PageIndexInfo }) => boolean;
  exclude?: (context: { page: PageIndexInfo }) => boolean;
}
```

- **Default**:

When [internationalization](https://rspress.rs/guide/basic/i18n.md) is not enabled, the default value is:

```ts
{
  llmsTxt: { name: 'llms.txt' },
  llmsFullTxt: { name: 'llms-full.txt' },
  mdFiles: true
}
```

When [internationalization](https://rspress.rs/guide/basic/i18n.md) is enabled, it will use [multiple configurations](#group), with the default value being:

```ts
[
  {
    llmsTxt: { name: 'llms.txt' },
    llmsFullTxt: { name: 'llms-full.txt' },
    mdFiles: true,
    include: ({ page }) => page.lang === config.lang,
  },
  // Automatically generate other languages based on locales configuration
  {
    llmsTxt: { name: `${lang}/llms.txt` },
    llmsFullTxt: { name: `${lang}/llms-full.txt` },
    mdFiles: true,
    include: ({ page }) => page.lang === lang,
  },
  // ...
];
```

### llmsTxt

- **Type**: `false | LlmsTxt`

```ts
import type { PageIndexInfo } from '@rspress/core';

export interface LlmsTxt {
  name: string;
  onTitleGenerate?: (context: {
    title: string | undefined;
    description: string | undefined;
  }) => string;
  onLineGenerate?: (page: PageIndexInfo) => string;
  onAfterLlmsTxtGenerate?: (llmsTxtContent: string) => string;
}
```

- **Default**: `{ name: 'llms.txt' }`

Controls whether to generate the `llms.txt` file, or customizes it through hooks.

The default format of an llms.txt file is as follows:

```markdown
# {title}

> {description}

## {nav1.title}

- [{page.title}]({ page.routePath }): {page.frontmatter.description}

## {nav2.title}

- [{page.title}]({ page.routePath }): {page.frontmatter.description}
```

You can modify specific parts through hooks:

- `onTitleGenerate`: Customize the generated title and description sections.
- `onLineGenerate`: Customize each line of the Markdown file.
- `onAfterLlmsTxtGenerate`: Modify the final contents of the `llms.txt` file.

For example:

```ts
pluginLlms({
  llmsTxt: {
    onTitleGenerate: ({ title, description }) => {
      return `# ${title} - llms.txt

> ${description}

Rspress is a static site generator based on Rsbuild and it can generate llms.txt with @rspress/plugin-llms.
`;
    },
  },
});
```

The generated result is:

```markdown
# Rspress - llms.txt

> Rsbuild based static site generator

Rspress is a static site generator based on Rsbuild and it can generate llms.txt with @rspress/plugin-llms.

## guide

- [foo](/foo.md)
```

### mdFiles

- **Type**: `false | MdFiles`

```ts
export interface MdFiles {
  mdxToMd?: boolean;
  remarkPlugins?: PluggableList;
}
```

- **Default**: `{ mdxToMd: false, remarkPlugins: [] }`

Controls whether to generate a Markdown file for the corresponding route. When set to `false`, the Markdown file for that route is not generated.

#### mdxToMd

- **Type**: `boolean`
- **Default**: `false`

Controls whether to convert MDX content to Markdown. If enabled, MDX files are converted to Markdown files through a set of default strategies, but some information may be lost.

#### remarkPlugins

- **Type**: `PluggableList`
- **Default**: `[]`

You can pass in custom remark plugins to modify the Markdown content.

### llmsFullTxt

- **Type**: `false | LlmsFullTxt`

```ts
export interface LlmsFullTxt {
  name: string;
}
```

- **Default**: `{ name: 'llms-full.txt' }`

Controls whether to generate `llms-full.txt`. When set to `false`, `llms-full.txt` is not generated.

### include

- **Type**: `(context: { page: PageIndexInfo }) => boolean`

Controls which pages are included during generation. This is usually used to simplify `llms.txt`.

- Example:

Generate `llms.txt` and other related files for pages whose language is English only:

```ts
pluginLlms({
  llmsTxt: {
    name: 'llms.txt',
  },
  llmsFullTxt: {
    name: 'llms-full.txt',
  },
  include: ({ page }) => {
    return page.lang === 'en';
  },
});
```

### exclude

- **Type**: `(context: { page: PageIndexInfo }) => boolean`

Controls which pages are excluded. This runs after `include`.

- Example:

Exclude a single page under the `/foo` route:

```ts
pluginLlms({
  llmsTxt: {
    name: 'llms.txt',
  },
  llmsFullTxt: {
    name: 'llms-full.txt',
  },
  exclude: ({ page }) => {
    return page.routePath === '/foo';
  },
});
```

## UI component props

### LlmsCopyButtonProps

- **Type**: `LlmsCopyButtonProps`

```ts
interface LlmsCopyButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {}
```

### LlmsViewOptionsProps

- **Type**: `LlmsViewOptionsProps`

```ts
type LlmsViewOptionsItem =
  | {
      title: string;
      icon?: React.ReactNode;
      onClick?: () => void;
    }
  | {
      title: string;
      href: string;
      icon?: React.ReactNode;
    }
  | 'markdownLink'
  | 'chatgpt'
  | 'claude';

interface LlmsViewOptionsProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {
  options?: LlmsViewOptionsItem[];
}
```

#### options

- **Type**: `LlmsViewOptionsItem[]`

```ts
type LlmsViewOptionsItem =
  | {
      title: string;
      icon?: React.ReactNode;
      onClick?: () => void;
    }
  | {
      title: string;
      href: string;
      icon?: React.ReactNode;
    }
  | 'markdownLink'
  | 'chatgpt'
  | 'claude';
```

- **Default**: `['markdownLink', 'chatgpt', 'claude']`

Customizes the options in the dropdown menu. By default, it supports "Copy Markdown Link", [ChatGPT](https://chatgpt.com/), and [Claude](https://claude.ai).

## Generate multiple groups of `llms.txt` at the same time \{#group}

In some cases, such as i18n sites, you may need to generate multiple `llms.txt` groups. Pass an array to do this.

- Example：

```ts
// rspress.config.ts
import { defineConfig } from '@rspress/core';
defineConfig({
  lang: 'en',
  plugins: [
    pluginLlms([
      {
        llmsTxt: {
          name: 'llms.txt',
        },
        llmsFullTxt: {
          name: 'llms-full.txt',
        },
        include: ({ page }) => page.lang === 'en',
      },
      {
        llmsTxt: {
          name: 'zh/llms.txt',
        },
        llmsFullTxt: {
          name: 'zh/llms-full.txt',
        },
        include: ({ page }) => page.lang === 'zh',
      },
    ]),
  ],
});
```
