-
-
Notifications
You must be signed in to change notification settings - Fork 76
Add llms.txt for machine-readable docs index #313
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
98fb587
855ed41
d3c54c0
a62f4d8
be0c244
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -8,6 +8,7 @@ import { | |
| } from "vitepress-plugin-group-icons" | ||
|
|
||
| import versions from './versions.json' | ||
| import { generateLlmsTxt } from './llms-txt' | ||
|
|
||
| // Build version dropdown items with absolute URLs for cross-version navigation | ||
| // This forces full page reload instead of client-side routing | ||
|
|
@@ -61,7 +62,8 @@ export default defineConfig({ | |
| ['meta', { property: 'og:description', content: 'The AI framework for Rails with less code & more fun.' }], | ||
| ['meta', { property: 'og:url', content: 'https://activeagents.ai' }], | ||
| ['meta', { property: 'og:type', content: 'website' }], | ||
| ['script', { async: '', defer: '', src: 'https://buttons.github.io/buttons.js' }] | ||
| ['script', { async: '', defer: '', src: 'https://buttons.github.io/buttons.js' }], | ||
| ['link', { rel: 'help', type: 'text/markdown', href: '/llms.txt', title: 'LLM Documentation' }] | ||
|
||
| ], | ||
| cleanUrls: true, | ||
| themeConfig: { | ||
|
|
@@ -145,6 +147,7 @@ export default defineConfig({ | |
| { text: 'Contributing', | ||
| items: [ | ||
| { text: 'Documentation', link: '/contributing/documentation' }, | ||
| { text: 'LLMs.txt', link: '/llms_txt' }, | ||
| ] | ||
| }, | ||
| ], | ||
|
|
@@ -161,5 +164,7 @@ export default defineConfig({ | |
| { icon: 'github', link: 'https://github.com/activeagents/activeagent' } | ||
| ], | ||
| }, | ||
| lastUpdated: true | ||
| lastUpdated: true, | ||
|
|
||
| buildEnd: generateLlmsTxt | ||
| }) | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,126 @@ | ||
| import { readFileSync, writeFileSync } from 'fs' | ||
| import { join } from 'path' | ||
| import type { SiteConfig } from 'vitepress' | ||
|
|
||
| const BASE_URL = 'https://docs.activeagents.ai' | ||
|
|
||
| const sections = [ | ||
| { | ||
| title: 'Getting Started', | ||
| pages: [{ path: 'getting_started' }], | ||
| }, | ||
| { | ||
|
Comment on lines
+7
to
+12
|
||
| title: 'Framework', | ||
| pages: [ | ||
| { path: 'framework' }, | ||
| { path: 'agents' }, | ||
| { path: 'providers' }, | ||
| { path: 'framework/configuration' }, | ||
| { path: 'framework/instrumentation' }, | ||
| { path: 'framework/retries' }, | ||
| { path: 'framework/rails' }, | ||
| { path: 'framework/testing' }, | ||
| ], | ||
| }, | ||
| { | ||
| title: 'Agents', | ||
| pages: [ | ||
| { path: 'actions' }, | ||
| { path: 'agents/generation' }, | ||
| { path: 'agents/instructions' }, | ||
| { path: 'agents/streaming' }, | ||
| { path: 'agents/callbacks' }, | ||
| { path: 'agents/error_handling' }, | ||
| ], | ||
| }, | ||
| { | ||
| title: 'Actions', | ||
| pages: [ | ||
| { path: 'actions/messages' }, | ||
| { path: 'actions/embeddings' }, | ||
| { path: 'actions/tools' }, | ||
| { path: 'actions/mcps' }, | ||
| { path: 'actions/structured_output' }, | ||
| { path: 'actions/usage' }, | ||
| ], | ||
| }, | ||
| { | ||
| title: 'Providers', | ||
| pages: [ | ||
| { path: 'providers/anthropic' }, | ||
| { path: 'providers/ollama' }, | ||
| { path: 'providers/open_ai' }, | ||
| { path: 'providers/open_router' }, | ||
| { path: 'providers/mock' }, | ||
| ], | ||
| }, | ||
| { | ||
| title: 'Examples', | ||
| pages: [ | ||
| { path: 'examples/browser-use-agent' }, | ||
| { path: 'examples/data_extraction_agent' }, | ||
| { path: 'examples/mcp-integration-agent' }, | ||
| { path: 'examples/research-agent' }, | ||
| { path: 'examples/support-agent' }, | ||
| { path: 'examples/translation-agent' }, | ||
| { path: 'examples/web-search-agent' }, | ||
| ], | ||
| }, | ||
| { | ||
| title: 'Contributing', | ||
| pages: [ | ||
| { path: 'contributing/documentation' }, | ||
| ], | ||
| }, | ||
| ] | ||
|
|
||
| function parseFrontmatter(filePath: string): Record<string, string> { | ||
| const content = readFileSync(filePath, 'utf-8') | ||
| const match = content.match(/^---\n([\s\S]*?)\n---/) | ||
| if (!match) return {} | ||
|
|
||
| const fm: Record<string, string> = {} | ||
| for (const line of match[1].split('\n')) { | ||
| const m = line.match(/^(\w+):\s*(.+)$/) | ||
| if (m) fm[m[1]] = m[2].replace(/^["']|["']$/g, '') | ||
| } | ||
| return fm | ||
| } | ||
|
|
||
| export async function generateLlmsTxt(siteConfig: SiteConfig) { | ||
| let count = 0 | ||
| const lines: string[] = [] | ||
|
|
||
| lines.push('# Active Agent') | ||
| lines.push('') | ||
| lines.push('> ActiveAgent extends Rails MVC to AI interactions. Build intelligent agents using familiar patterns — controllers, actions, callbacks, and views. The AI framework for Rails with less code & more fun.') | ||
| lines.push('') | ||
|
|
||
| for (const section of sections) { | ||
| lines.push(`## ${section.title}`) | ||
| lines.push('') | ||
|
|
||
| for (const page of section.pages) { | ||
| const filePath = join(siteConfig.srcDir, `${page.path}.md`) | ||
| let fm: Record<string, string> | ||
| try { | ||
| fm = parseFrontmatter(filePath) | ||
| } catch (error) { | ||
| throw new Error(`Failed to read ${page.path}.md at ${filePath}: ${(error as Error).message}`) | ||
| } | ||
|
|
||
| const title = fm.title || page.path | ||
| const desc = fm.description || '' | ||
| const url = `${BASE_URL}/${page.path}` | ||
|
|
||
| lines.push(`- [${title}](${url}): ${desc}`) | ||
|
Comment on lines
+112
to
+116
|
||
| count++ | ||
| } | ||
|
|
||
| lines.push('') | ||
| } | ||
|
|
||
| const outPath = join(siteConfig.outDir, 'llms.txt') | ||
| writeFileSync(outPath, lines.join('\n') + '\n') | ||
| console.log(`Generated ${outPath} with ${count} entries`) | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,31 @@ | ||
| --- | ||
| title: LLMs.txt | ||
| description: Machine-readable documentation index for AI tools and large language models following the llms.txt specification. | ||
| --- | ||
| # {{ $frontmatter.title }} | ||
|
|
||
| Active Agent publishes an [`llms.txt`](/llms.txt) file — a curated, machine-readable index of documentation pages, following the [llms.txt specification](https://llmstxt.org). | ||
|
|
||
| ## What is llms.txt? | ||
|
|
||
| The llms.txt spec provides a standard way for websites to offer documentation in a format optimized for large language models. Instead of crawling HTML pages, AI tools can fetch a single markdown file with structured links and descriptions for every page. | ||
|
|
||
| ## Using llms.txt | ||
|
|
||
| Point your AI tool at the file: | ||
|
|
||
| ``` | ||
| https://docs.activeagents.ai/llms.txt | ||
| ``` | ||
|
|
||
| Most AI-powered coding assistants and chat interfaces can ingest this URL directly to get full context on Active Agent. | ||
|
|
||
| ## Regenerating | ||
|
|
||
| The file is regenerated on every docs deploy as part of the VitePress build. To regenerate locally: | ||
|
|
||
| ```bash | ||
| npm run docs:build | ||
| ``` | ||
|
|
||
| This parses frontmatter from the curated list of documentation markdown files and writes `llms.txt` to the build output directory. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
CI validation only enforces
ENTRIES >= 30, so a partial/incorrect llms.txt could still pass (especially since generation currently can skip missing pages). Since the generator’s page list is fixed, consider asserting the exact expected entry count (or otherwise validating every expected URL/title) to reliably catch regressions.