Skip to content

Commit f57ff58

Browse files
committed
build: generate llms.txt and markdown files of the documentation for optimal AI consumption
INSTUI-4701
1 parent e66ad32 commit f57ff58

File tree

7 files changed

+1020
-4
lines changed

7 files changed

+1020
-4
lines changed
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
---
2+
title: AI features
3+
category: Contributor Guides
4+
order: 8
5+
---
6+
7+
## Generating AI agent friendly markdown files for components and guides
8+
9+
InstUI's JSON metadata is used to create a markdown version of the documentation for easier use by AI tools and coding assistants.
10+
11+
These markdown files are created during the build process then are made available for users using specific links.
12+
13+
This collection includes structured files for almost everything under the 'Getting Started', 'Guides', 'Patterns' and 'Components' (including Components/AI Components and Components/Utilities) sections of the documentation.
14+
15+
How it works:
16+
The core logic resides in **packages/**docs**/buildScripts/ai-accessible-documentation/generate-ai-accessible-markdowns.mts**.
17+
18+
1. **Input and output**
19+
Input: The script processes the JSON files found under **packages/**docs**/**build**/docs** if they are belong to the corresponding sections mentioned above.
20+
Output: A directory of generated .md files under **packages/**docs**/**build**markdowns**, which are also compressed into a documentation.zip archive as well which also can be found in this directory.
21+
22+
2. **Data loading and classification**
23+
The script reads all JSON files from the specified docs folder.
24+
Identifies the necessary components and guides based on data.category value.
25+
26+
3. **Markdown generation**
27+
A markdown file is generated using the data found under the 'description' key. As for components, an addtional table of props and a 'Usage' section is generated for showing how to import the component.
28+
As for the table of props, the props of a child component (e.g. Tabs.Panel) of a parent component (e.g. Tabs) is also included in the table.
29+
30+
4. **Index file creation and packaging**
31+
After all individual markdown files are written, INDEX.md file is generated, which acts as a master list of contents for the entire documentation set.
32+
Finally, the script uses the system's zip command to package all .md files in the output directory into the final documentation.zip file, which can be downloaded here: https://instructure.design/markdowns/documentation.zip
33+
The AI-friendly markdown files are now avaliable either downloading the documentation.zip file or through a link that follows this pattern: https://instructure.design/markdowns/Alert.md
34+
35+
## Generating llms.txt for LLMs
36+
37+
In addition to the markdown files, a llms.txt file is also generated. This file is specifically formatted for optimal consumption by Large Language Models (LLMs) and AI coding agents.
38+
This file contains a catalog of links pointing to the online markdown files of InstUI components and guides generated above and short description of each component/guide
39+
40+
How it works:
41+
The core logic resides in **packages/**docs**/buildScripts/ai-accessible-documentation/ggenerate-ai-accessible-llms-file.mts**.
42+
43+
1. **Input and output**
44+
Input: The script processes the following JSON file: **packages/**docs**/**build**/markdown-and-sources-data.json**
45+
Output: An llms.txt file is placed into **packages/**docs**/**build\*\*\*\* which can be found here: https://instructure.design/llms.txt
46+
47+
2. **Data loading and classification**
48+
The script indenftifies the necessary elements looking for "Getting Started", "Guides", "Patterns", and "Components" section names.
49+
50+
3. **Markdown generation**
51+
It creates a documentation structure like this:
52+
53+
```md
54+
---
55+
type: code
56+
---
57+
58+
# Instructure UI (InstUI) - React Component Library
59+
60+
## Documentation
61+
62+
### User Guides
63+
64+
#### Getting Started
65+
66+
#### Guides
67+
68+
#### Patterns
69+
70+
### Components
71+
72+
#### Utilities
73+
74+
#### AI components
75+
```
76+
77+
It generates links for the components/guides and appends a brief summary of each of them using the **packages/**docs**/buildScripts/ai-accessible-documentation/summaries-for-llms-file.json** file, searching for matching component/guide title.

docs/contributor-docs/contributing.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,7 @@ Please update the documentation and examples with any changes.
102102
11. Visit [http://localhost:9090](http://localhost:9090) in a browser. You should see your component listed in the docs.
103103
12. Start making changes to your component, and watch it update in the browser automatically.
104104
13. Resolve all `FIXME` comments in the generated code (except in the `MyComponentLocator.ts`).
105+
14. Add a short description of the new component to the **packages/**docs**/buildScripts/ai-accessible-documentation/summaries-for-llms-file.json file**. This will optimize the component's documentation for consumption by AI agents.
105106

106107
### Adding a new dependency
107108

docs/getting-started/usage.md

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,20 @@ Congrats, you have now a (very) basic app that uses Instructure UI :)
7474

7575
Just add the `@instructure/ui` dependency as shown above and wrap the part of your app that will use InstUI in `<InstUISettingsProvider>` and start using InstUI components.
7676

77+
## Using InstUI with AI coding agents
78+
79+
InstUI provides a compressed, downloadable collection of all component documentation and user guides in an AI-agent-friendly markdown format.
80+
81+
You can download the archive from the following link:
82+
https://instructure.design/markdowns/documentation.zip
83+
84+
The download includes an INDEX.md file that references all available documentation within the compressed folder.
85+
86+
These files are designed to be used as context for AI coding agents.
87+
88+
Additionally, an llms.txt file is available. This file contains a catalog of links pointing to the online markdown files for InstUI components and guides, which are also accessible to AI agents. It can be found at:
89+
https://instructure.design/llms.txt
90+
7791
## Further reading
7892

7993
- To use a different theme or customize one read about [Using theme overrides](#using-theme-overrides)
Lines changed: 140 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,140 @@
1+
/**
2+
* Processes InstUI JSON metadata to generate a file
3+
* formatted for Large Language Models (LLMs) and AI agent consumption
4+
* - Contains a catalog of links pointing to ai-accessible markdown files about InstUI components and guides
5+
* - Contains a summary of each component/guide next to the links
6+
*/
7+
8+
import { writeFileSync, readFileSync } from 'fs'
9+
10+
interface SectionData {
11+
docs?: string[]
12+
sections?: string[]
13+
title?: string
14+
}
15+
16+
interface GenerateLLMSOptions {
17+
summariesFilePath?: string
18+
baseUrl?: string
19+
outputFilePath?: string
20+
}
21+
22+
function generateAIAccessibleLlmsFile(
23+
sourceFilePath: string,
24+
options: GenerateLLMSOptions = {}
25+
): string {
26+
const { summariesFilePath, baseUrl = '', outputFilePath } = options
27+
28+
const fileContent = readFileSync(sourceFilePath, 'utf-8')
29+
const jsonData = JSON.parse(fileContent)
30+
const { sections, library } = jsonData
31+
32+
const version = library?.version
33+
34+
let summaries: Record<string, string> = {}
35+
// Generate summaries object from the summaries file for later lookup
36+
if (summariesFilePath) {
37+
try {
38+
const summariesContent = readFileSync(summariesFilePath, 'utf-8')
39+
const data = JSON.parse(summariesContent)
40+
41+
data.forEach((item: { title: string; summary?: string }) => {
42+
summaries[item.title] = item.summary || ''
43+
})
44+
} catch (error) {
45+
console.warn('Could not load summaries file:', error)
46+
}
47+
}
48+
49+
let LlmsMarkdownContent = `# Instructure UI (InstUI) - React Component Library\n\n- version ${version} \n\n`
50+
LlmsMarkdownContent += `- Instructure UI (InstUI) is a comprehensive React component library.\n\n`
51+
52+
// Add main Documentation section
53+
LlmsMarkdownContent += `## Documentation\n\n`
54+
55+
// Add User Guides section
56+
LlmsMarkdownContent += `### User Guides\n`
57+
58+
Object.entries(sections as Record<string, SectionData>).forEach(
59+
([sectionKey, sectionData]) => {
60+
const sectionTitle = sectionData.title || sectionKey
61+
62+
// Only process these specific sections
63+
if (!['Getting Started', 'Guides', 'Patterns'].includes(sectionTitle)) {
64+
return
65+
}
66+
67+
LlmsMarkdownContent += `#### ${sectionTitle}\n\n`
68+
69+
if (sectionData.docs && sectionData.docs.length > 0) {
70+
const uniqueDocs = [...new Set(sectionData.docs)]
71+
uniqueDocs.forEach((doc) => {
72+
// Skip unnecessary documents
73+
if (
74+
doc === 'CODE_OF_CONDUCT' ||
75+
doc === 'LICENSE' ||
76+
doc.includes('upgrade-guide')
77+
) {
78+
return
79+
}
80+
const displayName = doc
81+
.replace(/([A-Z])/g, ' $1')
82+
.replace(/-/g, ' ')
83+
.trim()
84+
.toLowerCase()
85+
.replace(/^\w/, (char) => char.toUpperCase())
86+
87+
const summary = summaries[doc]
88+
LlmsMarkdownContent += `- [${displayName}](${baseUrl}${doc}.md)${
89+
summary ? `: ${summary}` : ''
90+
}\n`
91+
})
92+
}
93+
LlmsMarkdownContent += '\n'
94+
}
95+
)
96+
97+
// Add Components section under Documentation
98+
LlmsMarkdownContent += `### Components\n\n`
99+
100+
const componentsSection = sections['components'] as SectionData | undefined
101+
if (componentsSection) {
102+
const allComponents = [...new Set(componentsSection.docs || [])]
103+
allComponents.forEach((component) => {
104+
const summary = summaries[component]
105+
LlmsMarkdownContent += `- [${component}](${baseUrl}${component}.md)${
106+
summary ? `: ${summary}` : ''
107+
}\n`
108+
})
109+
}
110+
111+
// Process component subsections like Components/AI Components and Components/Utilities, skip deprecated
112+
if (componentsSection?.sections && componentsSection.sections.length > 0) {
113+
const subsections = componentsSection.sections
114+
subsections.forEach((subsectionPath: string) => {
115+
if (subsectionPath.toLowerCase().includes('deprecated')) return
116+
117+
const subsection = sections[subsectionPath] as SectionData | undefined
118+
if (subsection && subsection.docs && subsection.docs.length > 0) {
119+
const subsectionTitle = subsection.title
120+
LlmsMarkdownContent += `\n#### ${subsectionTitle}\n\n`
121+
// Avoid duplicates
122+
const uniqueSubDocs = [...new Set(subsection.docs)]
123+
uniqueSubDocs.forEach((doc) => {
124+
const summary = summaries[doc]
125+
LlmsMarkdownContent += `- [${doc}](${baseUrl}${doc}.md)${
126+
summary ? `: ${summary}` : ''
127+
}\n`
128+
})
129+
}
130+
})
131+
}
132+
133+
if (outputFilePath) {
134+
writeFileSync(outputFilePath, LlmsMarkdownContent)
135+
}
136+
137+
return LlmsMarkdownContent
138+
}
139+
140+
export { generateAIAccessibleLlmsFile }

0 commit comments

Comments
 (0)