Skip to content

Conversation

@aryasaatvik
Copy link
Contributor

@aryasaatvik aryasaatvik commented Oct 13, 2025

🤖 LLM-Friendly Documentation Support

This PR implements AI agent-friendly documentation features, addressing maintainer feedback for better performance and cleaner URLs.

✨ Key Features

Content Negotiation

  • Static rewrites based on Accept headers (no middleware overhead)
  • Detects AI agents via text/markdown or text/plain without text/html
  • Clean URL structure: /llms/docs/ instead of /docs/llms.mdx/

Multiple Endpoints

  • /llms-full.txt - Complete documentation corpus for LLMs
  • /llms/docs/[...] - Individual page markdown content
  • /docs/[...] - Regular HTML documentation

Enhanced UX

  • LLM Copy Button and View Options for easy markdown access
  • Page actions integrated into documentation layout

🔧 Technical Changes

  • Static Rewrites: Accept header-based content negotiation in next.config.mjs
  • Route Handlers: Created /llms/docs/[[...slug]] for markdown content
  • API Endpoints: Added /llms-full.txt and /llms.txt for corpus access
  • Dependencies: Updated Fumadocs (core: 15.8.5, mdx: 12.0.3)
  • Configuration: Enabled includeProcessedMarkdown for LLM text extraction

✅ Addresses Maintainer Feedback

  • Performance: Eliminated middleware runtime overhead
  • URL Structure: Implemented clean /llms/docs/ pattern
  • TypeScript: Fixed dependency version mismatches

🧪 Testing

# AI agent (gets markdown)
curl -H "Accept: text/markdown, text/plain" /docs/installation

# Browser (gets HTML)
curl -H "Accept: text/html" /docs/installation

📚 References

…M text generation

- Added middleware to handle markdown rewrites for LLM documentation.
- Introduced new routes for serving LLM text from markdown files.
- Updated source configuration to include processed markdown in documentation.
- Created utility functions for fetching and formatting LLM text.
@vercel
Copy link

vercel bot commented Oct 13, 2025

@aryasaatvik is attempting to deploy a commit to the 47ng Team on Vercel.

A member of the Team first needs to authorize it.

@socket-security
Copy link

socket-security bot commented Oct 13, 2025

Review the following changes in direct dependencies. Learn more about Socket for GitHub.

Diff Package Supply Chain
Security
Vulnerability Quality Maintenance License
Updatedfumadocs-mdx@​11.7.5 ⏵ 12.0.39910074 +396 +1100
Updatedfumadocs-core@​15.6.12 ⏵ 15.8.59810076 +396 +1100
Updatedfumadocs-ui@​15.6.12 ⏵ 15.8.599 +110076 +296 +1100

View full report

@franky47 franky47 changed the title docs: support markdown response for AI doc: support markdown response for AI Oct 13, 2025
Copy link
Member

@franky47 franky47 left a comment

Choose a reason for hiding this comment

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

Thanks!

The typecheck step of the docs fails with this version of Fumadocs (you can see the results locally by running pnpm build --filter docs...).

I see this uses a middleware, is there a way to do this completely statically? Middleware would run on every request and incur additional costs & latency.

Also is the /docs/llms.mdx/[...] a convention used by agents? Or could it be changed to something like /llms/docs/[...], the mdx "extension" seems a bit odd in the middle of the pathname.

Disclaimer: I don't know much about how these agents fetch content, but clean URL suggestions could be:

  • /llms.txt for the root index (from https://llmstxt.org/)
  • /llms-full.txt for the detailed index
  • /llms/docs/installation.md for the markdown content equivalent of /docs/installation

What do you think?

const { rewrite: rewriteLLM } = rewritePath("/docs/*path", "/docs/llms.mdx/*path");

export function middleware(request: NextRequest) {
if (isMarkdownPreferred(request)) {
Copy link
Member

Choose a reason for hiding this comment

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

question: What does this function do?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

it checks the Accept header for the presence of text/plain or text/markdown preference and the order and q value if both text/html and (text/plain or text/markdown) are present.

using a static rewrite also works for claude code and opencode since they dont rely on q value and order

- Replace middleware with static Next.js rewrites for better performance
- Implement clean URL structure: /llms/docs/ instead of /docs/llms.mdx/
- Add Accept header logic for AI agent detection
- Remove middleware.ts to eliminate runtime overhead
- Update route handler path and TypeScript types
@socket-security
Copy link

socket-security bot commented Oct 13, 2025

All alerts resolved. Learn more about Socket for GitHub.

This PR previously contained dependency changes with security issues that have been resolved, removed, or ignored.

View full report

…n documentation

- Introduced a new redirect rule to handle requests for markdown files in the documentation.
- This allows for cleaner URLs and better organization of LLM documentation resources.
@aryasaatvik aryasaatvik requested a review from franky47 October 13, 2025 20:38
@vercel
Copy link

vercel bot commented Oct 14, 2025

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

Project Deployment Preview Comments Updated (UTC)
nuqs Ready Ready Preview Comment Oct 26, 2025 7:15pm

@franky47 franky47 added the documentation Improvements or additions to documentation label Oct 14, 2025
@franky47 franky47 added this to the 🪵 Backlog milestone Oct 14, 2025
- Replace custom cn.ts with existing @/src/lib/utils import
- Ensures proper clsx + twMerge combination for className merging
- Maintains consistency with rest of codebase
- Replace manual URLSearchParams with nuqs createSerializer
- Demonstrates dogfooding of nuqs library capabilities
- Maintains same functionality with cleaner, type-safe approach
- Wrap LLMCopyButton and ViewOptions in Suspense with skeleton fallback
- Use buttonVariants for perfect styling consistency with real buttons
- Prevents layout shifts on slow connections
- Skeleton matches exact dimensions and styling of actual components
- Improves perceived performance and user experience
- Refactor PageActionsSkeleton into its own component for better modularity
- Import and use PageActionsSkeleton in the documentation page
- Enhances code organization and reusability across documentation pages
@franky47
Copy link
Member

Looking at the output of /llms.txt, I see a lot of "noise", like the about page coming first which doesn't bring much value to the context.

Also, the output of llms.txt and llms-full.txt appear to be the same.

I wonder if we could fence off human-only content with HTML comments, like:

content for both humans & llms
<!-- llms:off -->
human only content
<!-- llms:on -->

we could also have LLM-only contents like so:

<!-- llms:only
this is not rendered for humans, but emitted in llms.txt and other markdown endpoints.
-->

- Refactor the GET function to organize documentation pages by directory
- Create a map to group pages and format output with titles and descriptions
- Enhance readability of the generated documentation
- Update the GET function to exclude specific pages from LLM text processing.
- Remove PAGE_EXCLUSIONS from the getLLMText function to streamline logic.
@aryasaatvik
Copy link
Contributor Author

Looking at the output of /llms.txt, I see a lot of "noise", like the about page coming first which doesn't bring much value to the context.

Also, the output of llms.txt and llms-full.txt appear to be the same.

I wonder if we could fence off human-only content with HTML comments, like:

content for both humans & llms
<!-- llms:off -->
human only content
<!-- llms:on -->

we could also have LLM-only contents like so:

<!-- llms:only
this is not rendered for humans, but emitted in llms.txt and other markdown endpoints.
-->

updated llms.txt to only include a table of contents

also added support for page exclusions for llms-full

I think fencing content for llms/humans in .mdx would require creating a fumadocs loader plugin to transform the comments at the mdx compilation step and filtering content. i don't want to do this as a part of this PR

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants