feat: add useLlmsAlternate composable for per-page markdown discovery#40
Open
sergioazoc wants to merge 3 commits intonuxt-content:mainfrom
Open
feat: add useLlmsAlternate composable for per-page markdown discovery#40sergioazoc wants to merge 3 commits intonuxt-content:mainfrom
sergioazoc wants to merge 3 commits intonuxt-content:mainfrom
Conversation
Emits two RFC 8288 hints so AI agents can discover the markdown counterpart of an HTML page without parsing the body: - <link rel="alternate" type="text/markdown" href="..."> in <head> - Link: <...>; rel="alternate"; type="text/markdown" HTTP header Composable accepts a string, ref, or getter; falsy values are ignored so it is safe to call before async data resolves. Pairs naturally with @nuxt/content's /raw/<path>.md endpoint but works with any markdown URL the consumer chooses to advertise.
Restructures the fixture into a multi-page app so each scenario has its own route and assertion: - / literal href (head + Link header) - /getter reactive getter resolves correctly - /empty null, '' and getter returning undefined are no-ops - /none pages that never call the composable get no Link header
@nuxt/content 3.13.0 introduced the `features/llms` integration that
auto-registers the `/raw/**:slug.md` server handler when nuxt-llms is
present. With this bump, the playground demonstrates the full agent
discovery loop end-to-end:
GET /second-page
→ Link: </raw/second-page.md>; rel="alternate"; type="text/markdown"
GET /raw/second-page.md
→ 200 text/markdown; charset=utf-8 + raw markdown body
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
Adds a
useLlmsAlternate(href)composable that advertises a markdown counterpart of the current page through two RFC 8288 discovery hints:<link rel="alternate" type="text/markdown" href="...">in the document<head>Link: <...>; rel="alternate"; type="text/markdown"HTTP response header (server only)The composable accepts a string, ref, or getter. Falsy values are ignored, so it is safe to call before async data resolves:
Why
/llms.txtadvertises the site at the global level, but agents crawling individual pages have no standard way to know that a markdown counterpart exists at/raw/<path>.md(the endpoint@nuxt/contentalready exposes when this module is installed). They have to either parse the HTML, guess URLs, or sendAccept: text/markdownand hope for content negotiation.The web has had the standard mechanism for this since 1998:
Linkheaders +<link rel="alternate">. It is how RSS auto-discovery, hreflang, andrel="canonical"work. Applying the same pattern to markdown alternates means an agent can read theLinkheader from a singleHEADrequest — without parsing HTML — and switch to the markdown URL for ingestion. The token savings of HTML→Markdown for LLM consumption are well documented; that math only kicks in if the agent knows the markdown URL exists.Demo (end-to-end in the playground)
The playground's
[...slug].vuecallsuseLlmsAlternatewith a getter derived from the loaded content document; the alternate URL is served by@nuxt/content's native/raw/**:slug.mdendpoint.Working in production at https://sergioazocar.com/blog/screaming-architecture-la-clave-para-un-frontend-escalable/ — check the response headers and
<head>.Scope
This PR ships the discovery primitive only. It deliberately does not include:
@nuxt/contentpages — would require integration between the two modules, better as a follow-up once this lands.Varytradeoffs that warrant their own discussion.Both are natural follow-ups that build on this primitive.
Tests
7 new tests in `test/alternate.test.ts` (fixture: `test/fixtures/alternate`) covering:
`pnpm verify` passes: lint, 9/9 tests, typecheck, prepack.
Related
Notes for review