Skip to content

Commit 747e935

Browse files
rachaelrenkoz-agent
andcommitted
feat: improve agent-friendly docs score (AFDocs quick wins)
- Add llms.txt directive to all HTML pages (visually-hidden div in header) and all generated .md files (blockquote at top) - Add Astro middleware for Accept: text/markdown content negotiation, using existing shouldServeMarkdown() helper - Fix llms.txt coverage: university/** → guides/** (directory was renamed), add community pages to Support customSet - Add MCP discovery file at .well-known/mcp.json pointing to Kapa MCP - Verify <link rel=alternate type=text/markdown> already appears early in <head> — no repositioning needed Checks addressed: llms-txt-directive-html (FAIL → PASS) llms-txt-directive-md (FAIL → PASS) content-negotiation (FAIL → PASS) content-start-position (mitigated via Tasks 1+2) llms-txt-coverage (80% → improved) MCP Server Discoverable (FAIL → PASS) Co-Authored-By: Oz <oz-agent@warp.dev>
1 parent 1e7482a commit 747e935

5 files changed

Lines changed: 56 additions & 8 deletions

File tree

astro.config.mjs

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -139,9 +139,9 @@ export default defineConfig({
139139
// widely consumed by AI agents.
140140
starlightLlmsTxt({
141141
projectName: 'Warp',
142-
// Excludes open-source-licenses from llms-full.txt and llms-small.txt.
143-
// The file is ~25k lines and causes a stack overflow in hast-util-to-text.
144-
// llms-custom sets exclude it separately via explicit path enumeration below.
142+
// Excludes pages from llms-small.txt that cause a stack overflow
143+
// in hast-util-to-text due to their size. Note: the `exclude`
144+
// option only applies to llms-small.txt, not llms-full.txt.
145145
exclude: ['support-and-community/community/open-source-licenses'],
146146
description:
147147
'Documentation for Warp, the agentic development environment, and Oz, Warp\'s programmable agent for running and coordinating agents at scale.',
@@ -153,10 +153,13 @@ export default defineConfig({
153153
{ label: 'Getting Started', description: 'Installation, quickstart, and migration guides.', paths: ['getting-started/**'] },
154154
{ label: 'Knowledge and Collaboration', description: 'Warp Drive, teams, and the Admin Panel.', paths: ['knowledge-and-collaboration/**'] },
155155
{ label: 'Reference', description: 'CLI and API reference.', paths: ['reference/**'] },
156-
// Excludes support-and-community/community/ — open-source-licenses.mdx is ~25k
157-
// lines and causes a stack overflow in hast-util-to-text during llms-txt generation.
158-
{ label: 'Support', description: 'Troubleshooting, billing, and privacy.', paths: ['support-and-community/index', 'support-and-community/plans-and-billing/**', 'support-and-community/privacy-and-security/**', 'support-and-community/troubleshooting-and-support/**'] },
159-
{ label: 'Guides (Warp University)', description: 'Task-oriented walkthroughs.', paths: ['university/**'] },
156+
// Includes all support-and-community/ pages except open-source-licenses.mdx
157+
// (excluded globally above — ~25k lines causes a stack overflow in hast-util-to-text).
158+
{ label: 'Support', description: 'Troubleshooting, billing, and privacy.', paths: ['support-and-community/index', 'support-and-community/plans-and-billing/**', 'support-and-community/privacy-and-security/**', 'support-and-community/troubleshooting-and-support/**', 'support-and-community/community/contributing', 'support-and-community/community/open-source-partnership', 'support-and-community/community/refer-a-friend'] },
159+
{ label: 'Guides', description: 'Task-oriented walkthroughs and tutorials.', paths: ['guides/**'] },
160+
// Changelog excluded — the single page (4k lines) causes a stack overflow
161+
// in hast-util-to-text during llms-full.txt generation. The page is still
162+
// available at /changelog/ and indexed by the sitemap.
160163
],
161164
}),
162165
],

public/.well-known/mcp.json

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
{
2+
"name": "Warp Documentation",
3+
"description": "Search and retrieve Warp documentation — the agentic development environment and Oz, Warp's programmable agent platform.",
4+
"url": "https://warp.mcp.kapa.ai/sse",
5+
"transport": "sse"
6+
}

src/components/CustomHeader.astro

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,10 @@ import ThemeSelect from 'virtual:starlight/components/ThemeSelect';
1818
import WarpTopicNav from './WarpTopicNav.astro';
1919
---
2020

21+
<div class="llms-directive sr-only" aria-hidden="true">
22+
For the complete documentation in markdown, see <a href="/llms.txt">llms.txt</a>.
23+
Markdown versions of each page are available by appending .md to any URL.
24+
</div>
2125
<div class="header">
2226
<div class="title-wrapper sl-flex">
2327
<SiteTitle />

src/integrations/docs-markdown-integration.js

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,10 @@ function convertHtmlToMarkdown(html) {
8888
const clone = /** @type {HTMLElement} */ (contentRoot.cloneNode(true));
8989
sanitizeRoot(clone);
9090
const markdownBody = turndown.turndown(clone.innerHTML).trim();
91-
const sections = [`# ${normalizeWhitespace(title)}`];
91+
const llmsDirective =
92+
'> For the complete documentation index, see [llms.txt](/llms.txt).\n' +
93+
'> Markdown versions of each page are available by appending .md to any URL.';
94+
const sections = [llmsDirective, `# ${normalizeWhitespace(title)}`];
9295

9396
if (description) {
9497
sections.push(description);

src/middleware.ts

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
import { defineMiddleware } from 'astro:middleware';
2+
import {
3+
shouldServeMarkdown,
4+
isEligibleDocHtmlPath,
5+
getMarkdownPathFromHtmlPath,
6+
} from './lib/docs-markdown.js';
7+
8+
/**
9+
* Content negotiation middleware.
10+
*
11+
* When an agent sends `Accept: text/markdown` (or is identified by user-agent),
12+
* rewrite the request to the pre-rendered `.md` variant of the page. This lets
13+
* agents like Claude Code, Cursor, and OpenCode get clean markdown without
14+
* needing to discover the `.md` URL convention first.
15+
*
16+
* The `shouldServeMarkdown` helper handles both explicit Accept-header
17+
* negotiation and user-agent fallback detection (see `src/lib/docs-markdown.js`).
18+
*/
19+
export const onRequest = defineMiddleware(async (context, next) => {
20+
const { request, url } = context;
21+
22+
if (!isEligibleDocHtmlPath(url.pathname)) {
23+
return next();
24+
}
25+
26+
if (!shouldServeMarkdown(request)) {
27+
return next();
28+
}
29+
30+
const mdPath = getMarkdownPathFromHtmlPath(url.pathname);
31+
return context.rewrite(mdPath);
32+
});

0 commit comments

Comments
 (0)