Skip to content

feat: agent discovery (Link headers, markdown negotiation, Content-Signal)#263

Merged
sriramveeraghanta merged 8 commits intomasterfrom
feat/agent-discovery
Apr 21, 2026
Merged

feat: agent discovery (Link headers, markdown negotiation, Content-Signal)#263
sriramveeraghanta merged 8 commits intomasterfrom
feat/agent-discovery

Conversation

@sriramveeraghanta
Copy link
Copy Markdown
Member

@sriramveeraghanta sriramveeraghanta commented Apr 20, 2026

Summary

  • Add Content-Signal: search=yes, ai-train=yes, ai-input=yes to robots.txt
  • Add Link response headers on all paths advertising llms.txt (describedby), /api-reference/introduction (service-doc), and /sitemap.xml (sitemap)
  • Serve source markdown when Accept: text/markdown is sent — static .md files copied into dist by a VitePress buildEnd hook, routed via a Vercel rewrites header matcher

Test plan

Local:

  • pnpm check:format passes
  • pnpm build succeeds and produces 337 .md files alongside .html in dist/
  • docs/.vitepress/dist/robots.txt contains the Content-Signal line

Preview deploy:

  • curl -I https://<preview>.vercel.app/ shows a Link: header with all three relations
  • Default curl https://<preview>.vercel.app/ still returns HTML (regression check)
  • curl -H "Accept: text/markdown" https://<preview>.vercel.app/api-reference/introduction returns markdown body and Content-Type: text/markdown; charset=utf-8 — if returned as text/plain, add an explicit header override in a follow-up

Summary by CodeRabbit

Chores

  • Updated the documentation build process to ensure all markdown source files are properly copied and deployed to the published site.
  • Enhanced content delivery with signal directives specifying preferences for AI training, search indexing, and content access.
  • Added response headers and markdown content negotiation to improve API documentation accessibility and discoverability.

Brainstormed spec for three agent-discovery fixes: Content-Signal in
robots.txt, Link response headers, and markdown content negotiation.
Ephemeral — to be removed after implementation.
Task-by-task implementation plan for the three fixes in the
companion spec. Ephemeral — removed as the final task.
@vercel
Copy link
Copy Markdown

vercel Bot commented Apr 20, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
developer-docs Ready Ready Preview, Comment Apr 20, 2026 3:42pm

Request Review

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Apr 20, 2026

📝 Walkthrough

Walkthrough

VitePress build configuration now includes a buildEnd hook that recursively copies all Markdown files from the source directory to the output directory. Additionally, SEO directives for AI content signals were added to robots.txt, and Vercel deployment configuration was updated with HTTP headers linking to documentation resources and request rewrite rules for Markdown content negotiation.

Changes

Cohort / File(s) Summary
Build & Deployment Configuration
docs/.vitepress/config.mts, vercel.json
VitePress config extended with buildEnd hook to recursively copy .md files during build. Vercel config updated with global headers injecting links to llms.txt, API docs, and sitemap, plus conditional rewrites routing requests with text/markdown accept headers to .md files.
SEO & Crawler Directives
docs/public/robots.txt
Added Content-Signal directive enabling search indexing and AI training (search=yes, ai-train=yes, ai-input=yes).

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Poem

🐰 A rabbit hops through build-time streams,
Copying markdown files and SEO dreams,
Headers now link to llms.txt so bright,
Content-Signals bloom—AI-trained just right!
Vercel rewrites the path for all who roam,

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'feat: agent discovery' directly maps to the PR's primary objective of implementing agent discovery mechanisms (Link headers, markdown negotiation, Content-Signal directives) to make documentation discoverable by AI agents and crawlers.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/agent-discovery

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@vercel.json`:
- Around line 3-13: The Link response header rule for the catch‑all source
"/(.*)" needs to also emit a Vary: Accept header so caches distinguish HTML vs
Markdown responses; update the headers array entry for source "/(.*)" (the
object containing the Link header) to include another header with key "Vary" and
value "Accept" alongside the existing Link header so caches will vary by the
Accept request header.
- Around line 108-113: Add an explicit root rewrite entry before the existing
catch-all rule in the "rewrites" array so requests to "/" with Accept:
text/markdown are rewritten to "/index.md"; specifically, add a rule with
"source": "/" and the same "has" header condition (key: "accept", value matching
".*text/markdown.*") and "destination": "/index.md" placed above the existing
rule that maps "source": "/:path*" to "/:path*.md".
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 963f30db-fd69-4548-9ee1-d87b11c74ebe

📥 Commits

Reviewing files that changed from the base of the PR and between 04c50cc and 2c5fbf7.

📒 Files selected for processing (3)
  • docs/.vitepress/config.mts
  • docs/public/robots.txt
  • vercel.json

Comment thread vercel.json
Comment on lines +3 to +13
"headers": [
{
"source": "/(.*)",
"headers": [
{
"key": "Link",
"value": "</llms.txt>; rel=\"describedby\"; type=\"text/plain\", </api-reference/introduction>; rel=\"service-doc\"; type=\"text/html\", </sitemap.xml>; rel=\"sitemap\"; type=\"application/xml\""
}
]
}
],
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

: "${PREVIEW_URL:?Set PREVIEW_URL to the Vercel preview origin, e.g. https://example.vercel.app}"

curl -fsSI "$PREVIEW_URL/api-reference/introduction" | tr -d '\r' | grep -i '^vary:.*accept'
curl -fsSI -H 'Accept: text/markdown' "$PREVIEW_URL/api-reference/introduction" | tr -d '\r' | grep -i '^vary:.*accept'

Repository: makeplane/developer-docs

Length of output: 177


🏁 Script executed:

git ls-files | grep -i vercel

Repository: makeplane/developer-docs

Length of output: 79


🏁 Script executed:

cat -n vercel.json | head -120

Repository: makeplane/developer-docs

Length of output: 4281


Add Vary: Accept response header for content negotiated Markdown responses.

The rewrite rule at lines 108–113 serves different content (HTML vs. Markdown) based on the Accept header. Without Vary: Accept, caches may serve the wrong representation to clients requesting a different format.

Proposed fix
       "headers": [
         {
           "key": "Link",
           "value": "</llms.txt>; rel=\"describedby\"; type=\"text/plain\", </api-reference/introduction>; rel=\"service-doc\"; type=\"text/html\", </sitemap.xml>; rel=\"sitemap\"; type=\"application/xml\""
+        },
+        {
+          "key": "Vary",
+          "value": "Accept"
         }
       ]
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
"headers": [
{
"source": "/(.*)",
"headers": [
{
"key": "Link",
"value": "</llms.txt>; rel=\"describedby\"; type=\"text/plain\", </api-reference/introduction>; rel=\"service-doc\"; type=\"text/html\", </sitemap.xml>; rel=\"sitemap\"; type=\"application/xml\""
}
]
}
],
"headers": [
{
"source": "/(.*)",
"headers": [
{
"key": "Link",
"value": "</llms.txt>; rel=\"describedby\"; type=\"text/plain\", </api-reference/introduction>; rel=\"service-doc\"; type=\"text/html\", </sitemap.xml>; rel=\"sitemap\"; type=\"application/xml\""
},
{
"key": "Vary",
"value": "Accept"
}
]
}
],
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@vercel.json` around lines 3 - 13, The Link response header rule for the
catch‑all source "/(.*)" needs to also emit a Vary: Accept header so caches
distinguish HTML vs Markdown responses; update the headers array entry for
source "/(.*)" (the object containing the Link header) to include another header
with key "Vary" and value "Accept" alongside the existing Link header so caches
will vary by the Accept request header.

Comment thread vercel.json
Comment on lines +108 to +113
"rewrites": [
{
"source": "/:path*",
"has": [{ "type": "header", "key": "accept", "value": ".*text/markdown.*" }],
"destination": "/:path*.md"
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

: "${PREVIEW_URL:?Set PREVIEW_URL to the Vercel preview origin, e.g. https://example.vercel.app}"

curl -fsSI -H 'Accept: text/markdown' "$PREVIEW_URL/" | tr -d '\r' | grep -Ei '^HTTP/|^content-type:'
curl -fsS -H 'Accept: text/markdown' "$PREVIEW_URL/" | head -n 20

Repository: makeplane/developer-docs

Length of output: 177


🏁 Script executed:

cat -n vercel.json | sed -n '100,120p'

Repository: makeplane/developer-docs

Length of output: 566


🏁 Script executed:

# Search for all rewrite rules in vercel.json to understand the full context
rg -A2 '"source"' vercel.json | head -60

Repository: makeplane/developer-docs

Length of output: 1888


🏁 Script executed:

# Check if there's any rewrite rule for the root path "/" already
rg '"source".*"/"' vercel.json

Repository: makeplane/developer-docs

Length of output: 50


Add explicit root rewrite for Markdown content negotiation.

The catch-all rule /:path*/:path*.md fails for the root path / because the path variable captures an empty string, resulting in /.md instead of /index.md. Add an explicit root rewrite before the catch-all to handle requests to / with Accept: text/markdown header:

Proposed fix
   "rewrites": [
+    {
+      "source": "/",
+      "has": [{ "type": "header", "key": "accept", "value": ".*text/markdown.*" }],
+      "destination": "/index.md"
+    },
     {
       "source": "/:path*",
       "has": [{ "type": "header", "key": "accept", "value": ".*text/markdown.*" }],
       "destination": "/:path*.md"
     }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
"rewrites": [
{
"source": "/:path*",
"has": [{ "type": "header", "key": "accept", "value": ".*text/markdown.*" }],
"destination": "/:path*.md"
}
"rewrites": [
{
"source": "/",
"has": [{ "type": "header", "key": "accept", "value": ".*text/markdown.*" }],
"destination": "/index.md"
},
{
"source": "/:path*",
"has": [{ "type": "header", "key": "accept", "value": ".*text/markdown.*" }],
"destination": "/:path*.md"
}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@vercel.json` around lines 108 - 113, Add an explicit root rewrite entry
before the existing catch-all rule in the "rewrites" array so requests to "/"
with Accept: text/markdown are rewritten to "/index.md"; specifically, add a
rule with "source": "/" and the same "has" header condition (key: "accept",
value matching ".*text/markdown.*") and "destination": "/index.md" placed above
the existing rule that maps "source": "/:path*" to "/:path*.md".

@sriramveeraghanta sriramveeraghanta merged commit a06dfc7 into master Apr 21, 2026
9 checks passed
@sriramveeraghanta sriramveeraghanta deleted the feat/agent-discovery branch April 21, 2026 09:19
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants