Agent-readiness round 3 — Accept: text/markdown content negotiation
Why this exists
Round 1 (earlier today) shipped markdown TWIN URLs (/index.md, etc.) advertised via <link rel="alternate" type="text/markdown"> in HTML head. The isitagentready.com audit specifically wants Accept: text/markdown content negotiation — same URL, different Content-Type based on the request header. That’s what this round adds.
Cloudflare-dashboard check came back negative (no edge-side toggle on Bailey’s plan), so this is implemented origin-side at nginx.
What was done
Nginx config — three additions
- Two
mapdirectives at http context (top of the site config file, beforeserver {}):
map $http_accept $wants_md {
default "";
"~*text/markdown" "yes";
}
map "$wants_md:$uri" $md_rewrite {
default "";
"yes:/" "/index.md";
"yes:/about/" "/about.md";
"yes:/services/" "/services.md";
"yes:/service-areas/" "/service-areas.md";
"yes:/contact/" "/contact.md";
}
-
add_header Vary "Accept" always;at server level (alongside the existing Link header), so any cache (browser, intermediary, future Cloudflare cache) keys HTML and markdown responses separately. -
Conditional rewrite inside
location /:
if ($md_rewrite) {
rewrite ^ $md_rewrite last;
}
The if + rewrite ... last; pattern is one of the safe if forms per nginx’s “if is evil” doctrine.
Why http-context for the maps
map directives can only live at http scope, not inside a server {} block. The site config in /etc/nginx/sites-available/baileyengineers.com is included by nginx.conf inside the http {} block, so directives at the top of the file ARE at http scope. Maps don’t affect other server blocks unless those blocks reference $wants_md / $md_rewrite, which they don’t.
Deploy
Applied via the safe-edit pattern. Backup at /etc/nginx/sites-available/baileyengineers.com.bak-20260506-000019. nginx -t passed; systemctl reload nginx clean. No dist/ deploy required — the .md twin files are already in production from round 1.
Smoke tests — all green via https://baileyengineers.com/
| # | Request | Expected | Actual |
|---|---|---|---|
| A | GET / with Accept: text/markdown | 200, Content-Type: text/markdown; charset=utf-8, body = markdown | PASS — body starts with # Bailey Engineering |
| B | GET / with Accept: text/html | 200, text/html, normal HTML, Vary: Accept present | PASS — body starts with <!DOCTYPE html> |
| C | GET / with no Accept header | 200, text/html (default) | PASS |
| D | All 5 twin paths with Accept: text/markdown | All return text/markdown; charset=utf-8 | PASS for /, /about/, /services/, /service-areas/, /contact/ |
| E | /privacy/ (twin-less) with Accept: text/markdown | text/html (truthful — no twin) | PASS |
Vary: Accept is present on responses (Cloudflare additionally appends accept-encoding on the HTML responses, which is correct).
Caveats
- Coverage limited to 5 paths. Other 195+ pages return HTML even on
Accept: text/markdownbecause they have no markdown twin. If the audit hits a random page it’ll grade partial. - Regex match is permissive.
Accept: text/markdownmatches anywhere in the Accept string. We don’t currently de-prefer markdown when the agent sendstext/markdown;q=0— minor edge case, not worth complicating the map for. - No
x-markdown-tokensheader. That’s a Cloudflare-specific extension that counts markdown tokens. Audit said “if available”; we skip. - Accept-Encoding interaction. Cloudflare adds
accept-encodingto the Vary header on HTML responses, so the actualVaryvalue is sometimesAccept,accept-encoding. Caches handle multi-value Vary correctly.
Files affected
Created:
.tmp/nginx-edit/baileyengineers.com.live3(downloaded baseline).tmp/nginx-edit/baileyengineers.com.proposed3(applied).tmp/nginx-edit/bak-path-v3.txt(server-side backup path)src/content/devlog/2026-05-05-agent-readiness-accept-negotiation.md(this file)
Modified on production:
/etc/nginx/sites-available/baileyengineers.com— added two http-contextmapblocks, server-levelVary: Acceptheader, and conditional rewrite insidelocation /.
When to re-test
Per memory feedback_visibility_retest_cadence, don’t re-run isitagentready.com before ~2026-05-26. The Accept-negotiation behavior is testable immediately via curl -H "Accept: text/markdown", but isitagentready.com’s crawler may have its own caching/cadence.