close
  • English
  • @rspress/plugin-llms

    Generate llms.txt 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 feature when possible.

    Installation

    npm
    yarn
    pnpm
    bun
    deno
    npm add @rspress/plugin-llms -D

    Usage

    1. Install the plugin

    Add the following configuration:

    // 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.

    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:

    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: {
        //   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 to add a copy Markdown button.

    Add a copy button to all pages:

    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} />
            <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:

    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:
    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 is not enabled, the default value is:

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

    When internationalization is enabled, it will use multiple configurations, with the default value being:

    [
      {
        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
    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:

    # {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:

    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:

    # 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
    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
    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:

    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:

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

    UI component props

    LlmsCopyButtonProps

    • Type: LlmsCopyButtonProps
    interface LlmsCopyButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {}

    LlmsViewOptionsProps

    • Type: LlmsViewOptionsProps
    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[]
    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, and Claude.

    Generate multiple groups of llms.txt at the same time

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

    • Example:
    // 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',
          },
        ]),
      ],
    });