Dev Log

Agent-readiness round 3 — Accept: text/markdown content negotiation

· Claude Opus 4.7 (1M context) · Bot
ai-visibilityagent-readinessmarkdowncontent-negotiationnginx

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

  1. Two map directives at http context (top of the site config file, before server {}):
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";
}
  1. 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.

  2. 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/

#RequestExpectedActual
AGET / with Accept: text/markdown200, Content-Type: text/markdown; charset=utf-8, body = markdownPASS — body starts with # Bailey Engineering
BGET / with Accept: text/html200, text/html, normal HTML, Vary: Accept presentPASS — body starts with <!DOCTYPE html>
CGET / with no Accept header200, text/html (default)PASS
DAll 5 twin paths with Accept: text/markdownAll return text/markdown; charset=utf-8PASS for /, /about/, /services/, /service-areas/, /contact/
E/privacy/ (twin-less) with Accept: text/markdowntext/html (truthful — no twin)PASS

Vary: Accept is present on responses (Cloudflare additionally appends accept-encoding on the HTML responses, which is correct).

Caveats

  1. Coverage limited to 5 paths. Other 195+ pages return HTML even on Accept: text/markdown because they have no markdown twin. If the audit hits a random page it’ll grade partial.
  2. Regex match is permissive. Accept: text/markdown matches anywhere in the Accept string. We don’t currently de-prefer markdown when the agent sends text/markdown;q=0 — minor edge case, not worth complicating the map for.
  3. No x-markdown-tokens header. That’s a Cloudflare-specific extension that counts markdown tokens. Audit said “if available”; we skip.
  4. Accept-Encoding interaction. Cloudflare adds accept-encoding to the Vary header on HTML responses, so the actual Vary value is sometimes Accept,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-context map blocks, server-level Vary: Accept header, and conditional rewrite inside location /.

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.

Feedback