@rspress/plugin-llms
Generate llms.txt related files for your Rspress site, allowing large language models to better understand your documentation site.
Installation
npm add @rspress/plugin-llms -D
Usage
1. Install plugin
Add the following configuration to your configuration file:
// rspress.config.ts
import { defineConfig } from '@rspress/core';
import { pluginLlms } from '@rspress/plugin-llms';
export default defineConfig({
plugins: [pluginLlms()],
});
Then execute the rspress build
command. While generating the output, the plugin will also generate llms.txt
, llms-full.txt
, and corresponding markdown files for each route in the output directory based on the navigation bar and sidebar.
2. UI display
If you want users reading your documentation site to better utilize large language models to read the documentation, you can add a copy Markdown button at the top of the page through custom theme, with the same effect as this website.
Add a copy button to all pages, example:
theme/index.tsx
import { getCustomMDXComponent as basicGetCustomMDXComponent } from '@rspress/core/theme';
import {
LlmsContainer,
LlmsCopyButton,
LlmsViewOptions,
} from '@rspress/plugin-llms/runtime';
function getCustomMDXComponent() {
const { h1: H1, ...mdxComponents } = basicGetCustomMDXComponent();
const MyH1 = ({ ...props }) => {
return (
<>
<H1 {...props} />
<LlmsContainer>
<LlmsCopyButton />
{/* LlmsViewOptions component can be added as needed */}
<LlmsViewOptions />
</LlmsContainer>
</>
);
};
return {
...mdxComponents,
h1: MyH1,
};
}
export { getCustomMDXComponent };
export * from '@rspress/core/theme';
Add a copy button to specific pages, example:
docs/hello-world.mdx
# Hello world
<LlmsContainer>
<LlmsCopyButton />
<LlmsViewOptions /> {/* LlmsViewOptions component can be added as needed */}
</LlmsContainer>
This is a sample document.
Configuration
This plugin accepts an object parameter with the following 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;
}
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
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' }
Whether to generate the llms.txt file, or to customize the llms.txt file 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 the specified part through hook.
onTitleGenerate
: Customize the generated title and description sections.
onLineGenerate
: Customize each line of the md file.
onAfterLlmsTxtGenerate
: Finally modify the 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 corresponding generation results are:
# 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
export interface MdFiles {
mdxToMd?: boolean;
remarkPlugins?: PluggableList;
}
- Default:
{ mdxToMd: false, remarkPlugins: [] }
Whether to generate a markdown file for the corresponding route. When set to false
, the markdown file for the corresponding route will not be generated.
mdxToMd
- Type:
boolean
- Default:
false
Whether to convert mdx content to md content. If enabled, mdx files will be converted to md files through a set of default strategies, but there may be some information loss.
- 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' }
Whether to generate the llms-full.txt file, the llms-full.txt
file will not be generated when set to false
.
include
- Type:
(context: { page: PageIndexInfo }) => boolean
Whether to include certain pages when generated, generally used to simplify llms.txt.
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
Whether to exclude certain pages, it will be executed after include
.
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> {
textByLang?: Record<string, string>;
text?: string;
}
textByLang
- Type:
Record<string, string>
- Default:
{ en: 'Copy Markdown', zh: '复制 Markdown' }
Replace the text on the button according to the corresponding language.
<LlmsCopyButton textByLang={{ en: 'Copy MD' }} />
text
Text on the copy button, has higher priority than textByLang
.
LlmsViewOptionsProps
- Type:
LlmsViewOptionsProps
type Option =
| {
title: string;
icon?: React.ReactNode;
onClick?: () => void;
}
| {
title: string;
href: string;
icon?: React.ReactNode;
}
| 'markdownLink'
| 'chatgpt'
| 'claude';
interface LlmsViewOptionsProps
extends React.ButtonHTMLAttributes<HTMLButtonElement> {
options?: Option[];
textByLang?: Record<string, string>;
text?: string;
}
options
type Option =
| {
title: string;
icon?: React.ReactNode;
onClick?: () => void;
}
| {
title: string;
href: string;
icon?: React.ReactNode;
}
| 'markdownLink'
| 'chatgpt'
| 'claude';
- Default:
['markdownLink', 'chatgpt', 'claude']
Customize the options in the dropdown menu. By default, supports "Copy Markdown Link", ChatGPT and Claude.
textByLang
- Type:
Record<string, string>
- Default:
{ en: 'Open', zh: '打开' }
Replace the text on the button according to the corresponding language.
text
Text on the button, has higher priority than textByLang
.
Generate multiple groups of llms.txt
at the same time
In some cases, you may generate multiple groups of llms.txt
, such as i18n sites. At this point, you can do it by passing in an array.
// 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',
},
]),
],
});