Skip to content

Commit 4cfc9c7

Browse files
authored
feat: Generate llms.txt for AI agents (#869)
A new Antora extension emits /llms.txt (https://llmstxt.org/) at build time. It indexes every page of the version that 'stable' points to, with the page description and a link to the AsciiDoc source on GitHub, and cross-links the machine-readable release/CRD data on the Stackable Hub. This gives AI agents a way to discover and navigate the docs without scraping HTML, and to locate the source file behind any page.
1 parent 210b2c5 commit 4cfc9c7

5 files changed

Lines changed: 74 additions & 0 deletions

File tree

antora-playbook.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ antora:
3131
mermaid_library_url: https://cdn.jsdelivr.net/npm/mermaid@10/dist/mermaid.esm.min.mjs
3232
script_stem: mermaid-scripts
3333
- ./supplemental-ui/lib/stackable-operator-helpers.js
34+
- ./supplemental-ui/lib/llms-txt.js
3435
content:
3536
sources:
3637
- url: .

local-antora-playbook.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ antora:
1616
mermaid_library_url: https://cdn.jsdelivr.net/npm/mermaid@10/dist/mermaid.esm.min.mjs
1717
script_stem: mermaid-scripts
1818
- ./supplemental-ui/lib/stackable-operator-helpers.js
19+
- ./supplemental-ui/lib/llms-txt.js
1920
content:
2021
sources:
2122
- url: ./

only-dev-antora-playbook.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ antora:
1616
mermaid_library_url: https://cdn.jsdelivr.net/npm/mermaid@10/dist/mermaid.esm.min.mjs
1717
script_stem: mermaid-scripts
1818
- ./supplemental-ui/lib/stackable-operator-helpers.js
19+
- ./supplemental-ui/lib/llms-txt.js
1920
content:
2021
sources:
2122
- url: ./

supplemental-ui/lib/llms-txt.js

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
// Generates /llms.txt following https://llmstxt.org/ so that AI agents can
2+
// discover the documentation without scraping HTML.
3+
//
4+
// For every component, only the version that 'stable' points to is indexed
5+
// (the latest release, or nightly when building without release branches).
6+
// Each entry carries the published page URL, the page description and a link
7+
// to the AsciiDoc source on GitHub, so agents can both read a page and find
8+
// the file to change.
9+
//
10+
// Useful links:
11+
// Extensions: https://docs.antora.org/antora/latest/extend/extensions/
12+
// Types of events: https://docs.antora.org/antora/latest/extend/generator-events-reference/
13+
module.exports.register = function () {
14+
this.once('beforePublish', ({ playbook, contentCatalog, siteCatalog }) => {
15+
const siteUrl = (playbook.site.url || '').replace(/\/$/, '')
16+
const lines = [
17+
'# Stackable Data Platform Documentation',
18+
'',
19+
'> Documentation for the Stackable Data Platform (SDP), a curated selection of',
20+
'> open source data apps like Apache Kafka, Apache Druid, Apache Trino and',
21+
'> Apache Spark, all working together seamlessly on Kubernetes.',
22+
'',
23+
'Machine-readable release, component and CRD data is available from the',
24+
'Stackable Hub: https://hub.stackable.tech/llms.txt',
25+
'',
26+
'Every entry below links the published page and, in parentheses, its AsciiDoc',
27+
'source on GitHub. To suggest a change to a page, edit that source file.',
28+
]
29+
30+
for (const component of contentCatalog.getComponents()) {
31+
const version = component.latest
32+
const pages = contentCatalog
33+
.findBy({ component: component.name, version: version.version, family: 'page' })
34+
.filter((page) => page.out)
35+
.sort((a, b) => a.pub.url.localeCompare(b.pub.url))
36+
const byModule = new Map()
37+
for (const page of pages) {
38+
const module = page.src.module
39+
if (!byModule.has(module)) byModule.set(module, [])
40+
byModule.get(module).push(page)
41+
}
42+
for (const [module, modulePages] of byModule) {
43+
lines.push('', `## ${component.title}: ${module === 'ROOT' ? 'general' : module}`, '')
44+
for (const page of modulePages) {
45+
const title = (page.asciidoc && page.asciidoc.doctitle ? page.asciidoc.doctitle : page.src.stem)
46+
.replace(/<[^>]+>/g, '')
47+
const description = page.asciidoc && page.asciidoc.attributes['description']
48+
const source = sourceUrl(page.src)
49+
let entry = `- [${title}](${siteUrl}${page.pub.url})`
50+
if (description) entry += `: ${description.replace(/\s+/g, ' ').trim()}`
51+
if (source) entry += ` (source: ${source})`
52+
lines.push(entry)
53+
}
54+
}
55+
}
56+
57+
siteCatalog.addFile({
58+
contents: Buffer.from(lines.join('\n') + '\n', 'utf8'),
59+
out: { path: 'llms.txt' },
60+
})
61+
})
62+
}
63+
64+
function sourceUrl (src) {
65+
const origin = src.origin
66+
if (!origin || !origin.url || !origin.url.startsWith('https://github.com/')) return undefined
67+
const repo = origin.url.replace(/\.git$/, '')
68+
const start = origin.startPath ? `${origin.startPath}/` : ''
69+
return `${repo}/blob/${origin.refname}/${start}${src.path}`
70+
}

truly-local-playbook.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ antora:
1616
mermaid_library_url: https://cdn.jsdelivr.net/npm/mermaid@10/dist/mermaid.esm.min.mjs
1717
script_stem: mermaid-scripts
1818
- ./supplemental-ui/lib/stackable-operator-helpers.js
19+
- ./supplemental-ui/lib/llms-txt.js
1920
content:
2021
sources:
2122
- url: ./

0 commit comments

Comments
 (0)