Skip to content

docs: refactor with nuxt-agent-discovery module - #6883

Open
benjamincanac wants to merge 11 commits into
v4from
docs/agent-discovery-module
Open

docs: refactor with nuxt-agent-discovery module#6883
benjamincanac wants to merge 11 commits into
v4from
docs/agent-discovery-module

Conversation

@benjamincanac

@benjamincanac benjamincanac commented Aug 25, 2026

Copy link
Copy Markdown
Member

🔗 Linked issue

❓ Type of change

  • 📖 Documentation (updates to the documentation or readme)
  • 🐞 Bug fix (a non-breaking change that fixes an issue)
  • 👌 Enhancement (improving an existing functionality)
  • ✨ New feature (a non-breaking change that adds functionality)
  • 🧹 Chore (updates to the build process or auxiliary tools and libraries)
  • ⚠️ Breaking change (fix or feature that would cause existing functionality to change)

📚 Description

nuxt/ui docs, nuxt.com, Docus and comark-docs each hand-rolled markdown content negotiation, CDN rewrites and the discovery documents that advertise them. The four copies drifted, and the drift causes live bugs (docus.dev serves HTML to ClaudeBot today). This moves that surface into nuxt-agent-discovery and keeps only what is genuinely site-specific.

Deleted, now owned by the module

  • docs/server/utils/markdownNegotiation.ts
  • docs/server/routes/raw/[...slug].md.get.ts
  • docs/server/routes/raw/index.md.get.ts
  • docs/server/routes/.well-known/api-catalog.get.ts
  • docs/server/middleware/markdown.ts
  • docs/server/error.ts
  • docs/server/routes/sitemap.md.get.ts
  • docs/server/routes/.well-known/mcp/server-card.json.get.ts
  • docs/modules/md-rewrite.ts
  • docs/server/routes/sitemap.xml.get.ts
  • docs/app/composables/useCanonical.ts
  • docs/server/utils/extractSections.ts
  • docs/server/utils/openapi.ts (discovery half)
  • docs/public/robots.txt (agent list; its Disallow prefixes move to robots.disallow), skills/index.json

@nuxtjs/sitemap and @nuxtjs/robots take over their own files, with the module feeding both from the same user-agent list negotiation matches. The module also removes @nuxt/content's own llms feature and generates llms.txt / llms-full.txt from the content adapter, so a page reads identically whether an agent fetches /raw/**.md or the single full document.

Kept, wired through the module's hooks and helpers

  • transformMDC runs on agent-discovery:document, which is now the path both /raw/**.md and llms-full.txt take.
  • /raw/index.md is generated by the module. The homepage is a Vue page with no document behind it, so agent-discovery:index supplies its title and description from the index collection plus the agent-facing prose; the frontmatter, canonical links, resources block and trailer come from the module and now match what a content page returns.
  • The MCP server card is built entirely by the module, which reads @nuxtjs/mcp-toolkit's own definitions. The site plugin that copied them onto the card is gone.
  • get-documentation-page and get-component call getAgentDocument() instead of $fetching /raw/**.md back out of their own serverless function, and search-documentation calls listAgentPages() instead of querying the collection directly. Both URLs in its results come from the module's route config now.
  • openapi.json keeps its /api/** paths, the MCP endpoint and its prose; the discovery half comes from agentDiscoveryOpenApi(). The 11 site-specific paths and all 11 schemas are unchanged.
  • extractSections.ts is deleted in favour of the module's, which falls back to the whole document when no requested heading matches instead of returning the title alone.
  • Everything under server/mcp/ is otherwise untouched.

Behaviour changes

Verified against the preview deployment.

  • Raw pages render through one pipeline. Each page gains its description blockquote and the related links from its links frontmatter — what @nuxt/content's own raw route does and this site had diverged from. In-body relative links and the ## Sitemap trailer are now absolute, since these files are read detached from the site. Of 184 pages, every diff is one of those three changes.
  • llms-full.txt renders through the same adapter, so it matches the raw twins page for page: 166 → 164 documents (the two installation pages were previously rendered twice, matching both /docs/getting-started/installation% and /docs/getting-started%).
  • llms.txt gains an Overview section linking /raw/index.md, 169 → 170 links. Same link set otherwise, reordered.
  • sitemap.md links point at the /raw/** twins rather than .md page URLs, so it agrees with llms.txt on every page. 192 entries.
  • sitemap.xml covers 192 URLs instead of 183. The homepage and every non-docs section (/blog, /templates, /showcase, /figma, /team, /community, /releases) were missing, because the old route only queried the docs collection. Every page collection declares defineSitemapSchema(), which is what @nuxtjs/sitemap walks.
  • robots.txt allows 18 agents instead of 9, generated from the shared list so the two can't drift. CCBot is no longer named explicitly; the wildcard Allow: / still permits it. The eight Disallow prefixes the static file carried move to robots.disallow in nuxt.config.ts, since the module only contributes Allow: / groups.
  • The skills index is generated from the files on disk. It was hand-maintained and would fall behind whenever a reference file was added. The generated output is byte-identical to the file it replaces.
  • /raw/figma.md, /raw/showcase.md, /raw/templates.md now 404. Those pages are YAML data with no markdown body, so they have no markdown representation.
  • search-documentation returns 183 pages instead of 194, and requires every search term to match across the title, path and description where it previously matched one substring against the title or description. The 11 dropped entries are @nuxt/content's .navigation files, which the old collection query listed as if they were documentation: every one rendered a 404 body and had no markdown twin. Results gain a markdown_url; the existing fields are unchanged and identical page for page.
  • /.well-known/api-catalog groups llms.txt under the / anchor rather than /docs, and is now cached for an hour rather than carrying s-maxage.
  • The Link header on / carries the same links plus the skills index, in a different order.

Known limitation: Accept q-values at the edge

The module parses q-values per RFC 9110, so the Nitro middleware serves HTML to a client that ranks markdown below it. The CDN rewrite is a regex over the raw header, and Vercel runs RE2, so it can only express the outright refusal: a missing matcher keeps text/markdown;q=0 from being rewritten, which is confirmed working on the preview. A partial preference like text/markdown;q=0.1, text/html;q=0.9 still gets markdown on a prerendered page.

Verification

Diffed against a full pre-migration build: llms.txt, openapi.json, /raw/index.md, sitemap.md and all 184 prerendered raw pages, with every difference listed above and nothing else moved.

On the preview deployment: negotiation by Accept, by user agent and by .md URL, including all four q=0 spellings falling through to HTML; Vary and the discovery Link header; the markdown 404 for agents against the HTML one for browsers; and every discovery document (llms.txt 170 links, llms-full.txt 164 documents, sitemap.xml 192 URLs, sitemap.md 192 entries, robots.txt 19 groups, 15 skill files).

The MCP server card lists all 12 tools, 5 resources and 3 prompts with its capabilities, and get-documentation-page returns bytes identical to /raw/docs/components/badge.md, narrows correctly to named ## sections, falls back to the whole document for a heading that does not exist, and resolves a section path to its first document.

Re-run end to end against the published nuxt-agent-discovery@0.1.0: every count is unchanged and llms-full.txt is byte-identical at 2244037 bytes, so the module's pre-publish correctness pass moved nothing here.

pnpm lint, pnpm typecheck and a NITRO_PRESET=vercel build pass.

📝 Checklist

  • I have linked an issue or discussion.
  • I have updated the documentation accordingly.

…covery

`nuxt/ui` docs, `nuxt.com`, Docus and `comark-docs` each hand-rolled
markdown content negotiation, CDN rewrites and the discovery documents
that advertise them, and the four copies had drifted. Move that surface to
`nuxt-agent-discovery` and keep only what is genuinely site-specific.

Deleted, now owned by the module: the Vercel rewrite module, the markdown
middleware, the markdown error handler, the negotiation utility, the raw
markdown route, the api-catalog, `sitemap.md`, `sitemap.xml`, the MCP
server card handler, the static `robots.txt` and the hand-written skills
index. `@nuxtjs/sitemap` and `@nuxtjs/robots` take over their own files,
with the module feeding both from the shared user-agent list.

Kept, wired through the module's hooks: `transformMDC` runs on
`agent-discovery:document`, the MCP server card is enriched with the live
tool list on `agent-discovery:mcp-server-card`, and the hand-written
homepage markdown renders the discovery registry with
`renderAgentResources()`.

Behaviour changes worth knowing:

- `Accept: text/markdown;q=0, text/html` now returns HTML. The old
  substring matcher ignored q-values.
- Raw pages gain the related links from their `links` frontmatter, which is
  what `@nuxt/content`'s own raw route does and this site had diverged from.
- `sitemap.xml` covers 192 URLs instead of 183: the homepage and every
  non-docs section were missing, because the old route only queried the
  `docs` collection.
- `robots.txt` allows 18 agents instead of 9, generated from the same list
  negotiation matches so the two cannot drift. `CCBot` is no longer named
  explicitly; the wildcard group still allows it.
- The skills index is generated from the files on disk rather than
  hand-maintained.

`llms.txt`, `openapi.json`, `/raw/index.md` and all 184 prerendered raw
pages were diffed against the pre-migration build; the only differences are
the ones listed above.
@github-actions github-actions Bot added the v4 #4488 label Aug 25, 2026
@benjamincanac benjamincanac changed the title refactor(docs): replace the agent-discovery layer with nuxt-agent-discovery docs: replace the agent-discovery layer with nuxt-agent-discovery Aug 25, 2026
@pkg-pr-new

pkg-pr-new Bot commented Aug 25, 2026

Copy link
Copy Markdown
npm i https://pkg.pr.new/@nuxt/ui@6883

commit: c04d24f

@codspeed-hq

codspeed-hq Bot commented Aug 25, 2026

Copy link
Copy Markdown

Merging this PR will not alter performance

✅ 31 untouched benchmarks


Comparing docs/agent-discovery-module (c04d24f) with v4 (9bdb89b)

Open in CodSpeed

`nuxt-agent-discovery` now removes `@nuxt/content`'s llms plugin and renders
`llms-full.txt` through the content adapter, so `content:llms:generate:document`
no longer fires. `transformMDC` already runs on `agent-discovery:document`,
which is the same path `llms-full.txt` takes now, so the transform is
unaffected.
@benjamincanac benjamincanac changed the title docs: replace the agent-discovery layer with nuxt-agent-discovery docs: refactor with nuxt-agent-discovery module Aug 26, 2026
The negotiated pages, their raw twins, the sitemaps, the llms indexes and
the `.well-known` documents are the same on every site running the module,
derived from `routes`, `rawPrefix` and the link registry. Restating them
here meant a second copy of the route config to keep in step.

`agentDiscoveryOpenApi()` contributes them, along with the `Vary` header,
the markdown 404 and the `Linkset` / `SkillsIndex` schemas. What stays is
what only this site knows: `/api/**`, the MCP endpoint, and the prose. Site
values merge last, so any generated path can still be overridden.

The 11 site-specific paths and all 11 schemas come out unchanged; the 11
module-owned ones now carry generic descriptions and, for the moment, no
`operationId`.
The hook carries the title and description now, so the hand-written route has nothing left that the module cannot build.
The card now reads `listMcpDefinitions()` itself, and `getAgentDocument()` returns the bytes `/raw/**.md` serves without the tools fetching their own route back out of the function.
`listAgentPages()` resolves both URLs from the same route config the negotiation uses, and the remaining MCP definitions take the site URL from `SITE_URL` rather than writing it out.
The static `public/robots.txt` carried eight disallowed prefixes that nothing put back: `nuxt-agent-discovery` only contributes `Allow: /` groups for the agent user agents.
@socket-security

socket-security Bot commented Aug 27, 2026

Copy link
Copy Markdown

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

Diff Package Supply Chain
Security
Vulnerability Quality Maintenance License
Addednuxt-agent-discovery@​0.1.0761009988100
Added@​nuxtjs/​robots@​6.2.0991009597100
Added@​nuxtjs/​sitemap@​8.5.0971009799100

View full report

@coderabbitai

coderabbitai Bot commented Aug 27, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: ca38cc5d-c82b-48aa-945a-f694df8cc189

📥 Commits

Reviewing files that changed from the base of the PR and between b751eae and c04d24f.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (32)
  • docs/app/composables/useCanonical.ts
  • docs/content.config.ts
  • docs/modules/md-rewrite.ts
  • docs/nuxt.config.ts
  • docs/package.json
  • docs/public/robots.txt
  • docs/server/error.ts
  • docs/server/mcp/prompts/implement-component-with-props.ts
  • docs/server/mcp/tools/get-component-metadata.ts
  • docs/server/mcp/tools/get-component.ts
  • docs/server/mcp/tools/get-documentation-page.ts
  • docs/server/mcp/tools/get-migration-guide.ts
  • docs/server/mcp/tools/search-components.ts
  • docs/server/mcp/tools/search-composables.ts
  • docs/server/mcp/tools/search-documentation.ts
  • docs/server/middleware/markdown.ts
  • docs/server/plugins/agent-discovery.ts
  • docs/server/plugins/llms.ts
  • docs/server/routes/.well-known/api-catalog.get.ts
  • docs/server/routes/.well-known/mcp/server-card.json.get.ts
  • docs/server/routes/openapi.json.get.ts
  • docs/server/routes/raw/[...slug].md.get.ts
  • docs/server/routes/raw/index.md.get.ts
  • docs/server/routes/sitemap.md.get.ts
  • docs/server/routes/sitemap.xml.get.ts
  • docs/server/utils/extractSections.ts
  • docs/server/utils/llms.ts
  • docs/server/utils/markdownNegotiation.ts
  • docs/server/utils/openapi.ts
  • docs/server/utils/site.ts
  • pnpm-workspace.yaml
  • skills/index.json
💤 Files with no reviewable changes (14)
  • docs/public/robots.txt
  • docs/server/error.ts
  • docs/server/routes/sitemap.xml.get.ts
  • docs/modules/md-rewrite.ts
  • docs/server/routes/.well-known/mcp/server-card.json.get.ts
  • docs/server/routes/raw/index.md.get.ts
  • docs/app/composables/useCanonical.ts
  • docs/server/utils/markdownNegotiation.ts
  • skills/index.json
  • docs/server/routes/sitemap.md.get.ts
  • docs/server/utils/extractSections.ts
  • docs/server/routes/raw/[...slug].md.get.ts
  • docs/server/routes/.well-known/api-catalog.get.ts
  • docs/server/middleware/markdown.ts

Included review availability: Your plan provides up to 8 included reviews per hour; 7 remain after this review.


📝 Walkthrough

Walkthrough

The documentation site now uses @nuxtjs/robots, @nuxtjs/sitemap, and nuxt-agent-discovery. Sitemap schemas and agent-discovery settings are defined in the site configuration. MCP tools resolve documents and search pages through agent-discovery APIs. LLM links resolve at render time. OpenAPI documents merge discovery-provided fragments. Shared absolute URLs use SITE_URL.

Estimated code review effort: 4 (Complex) | ~60 minutes

Merge Risk: 🔵 Low · up to c04d2

The migration centralizes documentation discovery behavior but makes the public OpenAPI contract dependent on a new external module that receives request context without local validation. Fixed canonical configuration and prerendering limit the impact, so the PR is mergeable with explicit owner awareness of this integration boundary.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 33.33% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 3 functions across 16 files. (2 skipped: … Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly identifies the main change: refactoring the documentation site to use the nuxt-agent-discovery module.
Description check ✅ Passed The description directly explains the migration, removed duplicated functionality, retained integrations, behavior changes, known limitation, and verification results.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Full details: Docstring Coverage

Explanation

Docstring coverage is 33.33% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 3 functions across 16 files. (2 skipped: 2 unsupported.)

  • Fix all pre-merge checks with AI
✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch docs/agent-discovery-module

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.

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

Labels

v4 #4488

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant