Skip to content

feat(docs): point a lost agent somewhere useful from the 404 - #12599

Open
jd wants to merge 7 commits into
mainfrom
devs/jd/agentic-readiness/point-lost-agent-somewhere-useful-404--bb77d582
Open

feat(docs): point a lost agent somewhere useful from the 404#12599
jd wants to merge 7 commits into
mainfrom
devs/jd/agentic-readiness/point-lost-agent-somewhere-useful-404--bb77d582

Conversation

@jd

@jd jd commented Aug 28, 2026

Copy link
Copy Markdown
Member

The 404 offered a search box and a link home. That works for a person; an
agent that followed a dead link gets a page with nothing machine-readable on
it, and a 404 is the one page where it has no other context to work from.

Add a short recovery list: the documentation index, llms.txt, the sitemap,
the API reference and the OpenAPI document — plus a note that appending .md
to any URL, or sending Accept: text/markdown, returns the Markdown source.
Useful to a human who mistyped a URL too.

@jd

jd commented Aug 28, 2026

Copy link
Copy Markdown
Member Author

This pull request is part of a Mergify stack:

# Pull Request Link
1 fix(seo): restore the homepage OpenGraph image #12593
2 fix(a11y): stop docset grids skipping a heading level #12594
3 feat(docs): publish the API description where machines look for it #12595
4 feat(docs): serve Markdown to clients that ask for it #12596
5 feat(docs): tell agents what Mergify is for in llms.txt #12597
6 feat(seo): describe the site with schema.org JSON-LD #12598
7 feat(docs): point a lost agent somewhere useful from the 404 #12599 👈

@mergify

mergify Bot commented Aug 28, 2026

Copy link
Copy Markdown
Contributor

Merge Protections

🟠 1 of 6 protections blocking · waiting on 🤖 CI

Protection Waiting on
🟠 🤖 Continuous Integration 🤖 CI
🟢 👀 Review Requirements
🟢 Enforce conventional commit
🟢 🔎 Reviews
🟢 📕 PR description
🟢 🚦 Auto-queue

🟠 🤖 Continuous Integration

Waiting for

  • check-success = diagram-tokens
Waiting checks: diagram-tokens.
  • all of:
    • check-success = diagram-tokens
    • check-success = build
    • check-success = lint
    • check-success = test
    • any of:
      • check-success = test-broken-links
      • label = ignore-broken-links
    • any of:
      • check-success=Cloudflare Pages
      • -head-repo-full-name~=^Mergifyio/

Show 5 satisfied protections

🟢 👀 Review Requirements

  • any of:
    • #approved-reviews-by >= 2
    • author = dependabot[bot]
    • author = renovate[bot]
    • all of:
      • author = mergify-ci-bot
      • -head ~= ^docs-agent/

🟢 Enforce conventional commit

Make sure that we follow https://www.conventionalcommits.org/en/v1.0.0/

  • title ~= ^(fix|feat|internal|docs|style|refactor|perf|test|build|ci|chore|revert|ui)(?:\(.+\))?!?:

🟢 🔎 Reviews

  • #changes-requested-reviews-by = 0
  • #review-requested = 0
  • #review-threads-unresolved = 0

🟢 📕 PR description

  • body ~= (?ms:.{48,})

🟢 🚦 Auto-queue

When all merge protections are satisfied, this pull request will be queued automatically.

@mergify
mergify Bot requested a review from a team August 28, 2026 13:32
Copilot AI lite review requested due to automatic review settings August 28, 2026 13:33
@jd
jd force-pushed the devs/jd/agentic-readiness/point-lost-agent-somewhere-useful-404--bb77d582 branch from 4e0375e to af4b8b8 Compare August 28, 2026 13:33
@jd

jd commented Aug 28, 2026

Copy link
Copy Markdown
Member Author

Revision history

# Type Changes Reason Date
1 initial 4e0375e 2026-08-28 13:33 UTC
2 rebase 4e0375e → af4b8b8 (rebase only) 2026-08-28 13:33 UTC
3 rebase af4b8b8 → 12b683f (rebase only) No content change: re-pushed to retrigger the Cloudflare Pages preview build, which failed on the previous SHA while the five earlier PRs in the stack deployed fine (suspected build-concurrency limit… 2026-08-28 13:38 UTC
4 content 12b683f → 26f0c28 Reword the 404 Markdown hint per review on #12599 2026-08-28 14:37 UTC
5 rebase 26f0c28 → db22260 (rebase only) 2026-08-28 15:09 UTC
6 rebase db22260 → 2e2b86a (rebase only) 2026-08-31 13:40 UTC

@mergify
mergify Bot had a problem deploying to Mergify Merge Protections August 28, 2026 13:34 Failure

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Improves the 404 page to provide “next steps” for automated agents (and humans) by adding a small, machine-readable recovery navigation section alongside the existing search and home link.

Changes:

  • Add a “Where to look next” recovery <nav> with links to index, llms.txt, sitemap, API reference, and OpenAPI.
  • Add scoped CSS styles for the recovery section on the 404 page.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread src/pages/404.astro
@jd
jd force-pushed the devs/jd/agentic-readiness/point-lost-agent-somewhere-useful-404--bb77d582 branch from af4b8b8 to 12b683f Compare August 28, 2026 13:38
@mergify
mergify Bot had a problem deploying to Mergify Merge Protections August 28, 2026 13:39 Failure
@jd
jd marked this pull request as ready for review August 28, 2026 14:09
@jd
jd force-pushed the devs/jd/agentic-readiness/point-lost-agent-somewhere-useful-404--bb77d582 branch from 12b683f to 26f0c28 Compare August 28, 2026 14:37
@mergify
mergify Bot had a problem deploying to Mergify Merge Protections August 28, 2026 14:38 Failure
jd added 5 commits August 28, 2026 17:08
`getOgImageUrl` strips the leading and trailing slashes off the pathname to
build the image filename. For the homepage that pathname is `/`, so stripping
left an empty string and the lookup missed — every docs page had an OpenGraph
image and the homepage shipped `<meta property="og:image">` with no content.

The homepage's collection id is `index`, which is what `getStaticPaths` names
its image, so fall back to that when the slug comes out empty.

Covered by a regression test that fails against the old expression. The
generated-image set comes from the content collection and needs the Astro build
pipeline, so the test stubs it and exercises the derivation, which is the half
that was wrong.

Change-Id: Ifb9a23ea2caa20d28489a4f21363d85ed5e3342c
Docset cards rendered their title as `h4`. Almost every grid sits directly
under an `##`, so the outline jumped h2 to h4 — including on the homepage,
whose whole body is the "Products" grid. Screen readers and anything parsing
the document outline read that as a missing level.

Default the card heading to `h3` and make it a prop, because one grid does
belong at h4: the "Components" grid in `ci-insights.mdx` is nested under an
`### Components`, where h3 would make the cards siblings of their own section
heading instead of children.

Change-Id: Ie01f4c2b03f1f2b7f798ae89b056135a5b00800e
The Mergify OpenAPI 3.1 document is already deployed — it is what the API
Reference pages are generated from — but only at `/api-schemas.json`, a
filename that exists nowhere outside this repository. Every OpenAPI client,
SDK generator and crawler probes `/openapi.json`, so nothing finds it and the
docs read as a site with no API at all.

Serve the same bytes at `/openapi.json`. The route does not transform the
document: the spec is synced from the engine repository, and two spellings of
it that could disagree would be worse than one obscure path.

Alongside it, three other entry points that were undiscoverable:

- `<link rel="service-desc">` in every page head, the IANA relation for "the
  description of this site's API" (RFC 8631), plus one for `llms.txt`.
- `robots.txt` had no `Sitemap:` line, so crawlers had to guess
  `sitemap-index.xml` rather than be told.
- `/developers` is the path people and tools guess for a developer portal and
  was a 404; it now redirects to the API reference.

Change-Id: I1b625f960363c8427d5282c052fee74111bf07fa
Every page already ships its Markdown source at `<path>.md`, which is what the
"View as Markdown" button and `llms.txt` link to. But the convention agents
reach for first is to request the page's own URL with `Accept: text/markdown`
(https://acceptmarkdown.com), and that returned HTML.

The site is a static build, so a Cloudflare Pages middleware is the only layer
that sees request headers. It rewrites to the `.md` twin when Markdown is asked
for, answers 404s in the format that was requested, and merges `Accept` into
`Vary` on both variants — without it a CDN would hand whichever variant it
cached first to everyone, which is the failure this is most likely to produce
in production and the least likely to be noticed. The `Vary` goes on `304`
responses too, since those are exactly the ones a cache is about to act on.

Markdown is served only when `text/markdown` is named explicitly and not
outranked by `text/html`. Browsers send `text/html,...,*/*;q=0.8`, so honouring
wildcards would serve raw Markdown to every human visitor; the tests pin the
real Chrome and Firefox Accept headers against that.

HTML is served as the fallback only on a `404` from the `.md` route, not on
anything that is merely not `ok`: `304 Not Modified` is the normal answer to a
client revalidating Markdown it already holds, and treating it as a missing
page answered it with HTML.

Three things about adding a root `_middleware` needed care, all three verified
against the real Pages runtime with `wrangler pages dev dist`:

Cloudflare documents that `_redirects` are not applied to requests served by
Functions, and this repository has 99 of them. `next()` does still route
through the asset server, so every redirect, the `_headers` rules, the `.md`
routes and the static 404 behave exactly as before.

`next()` is called with an explicit request everywhere. A bare `next()` is
documented as forwarding the original request, but once the middleware has
asked for the Markdown twin the runtime forwards *that* request again — so
`/api` and `/cli`, which are built from `src/pages/` and have no `.md`, were
answered with the Markdown 404 instead of their own HTML. The test double
refuses a call with no request so this cannot come back.

A root middleware otherwise turns every request into a Worker invocation,
assets included — roughly thirty per page view, none of which can be
negotiated. `_routes.json` excludes the bundle, the search index, the
OpenGraph images and the static files by name, so only page requests reach the
Function.

Also ignore `.wrangler/` — running the Pages runtime locally drops generated
bundles there, and eslint linted them.

Change-Id: I52f9d2a1c70248b1406412129a633cc3bee219de
`llms.txt` was a page index and nothing else: an agent could see every URL we
publish and still not know whether Mergify was the right tool for the task in
front of it, or how to call it.

Add two sections above the index.

"When to use Mergify" names the jobs concretely — keeping main green, merging
at volume without the CI bill, diagnosing CI, flaky tests, merge requirements
GitHub cannot express, stacked PRs — and, just as usefully, says what is out of
scope. GitHub only, no other code host; GitLab appears solely as a source of CI
results. That one line saves an agent from planning an integration that does
not exist, which is worth more than another paragraph of capabilities.

"For agents" points at the machine-readable surfaces: the `.md` twin of every
page and the `Accept: text/markdown` equivalent, the OpenAPI document with its
base URL and auth scheme, the sitemap, the `.mergify.yml` JSON Schema, and how
to install the CLI. That last one because naming a CLI without an install path
leaves an agent exactly where it started; the paths are the Homebrew tap, the
install script and the Windows release zip, per /cli/usage.

Change-Id: I03f7b473ced0969e850d78b48758e1849535062f
@jd
jd force-pushed the devs/jd/agentic-readiness/point-lost-agent-somewhere-useful-404--bb77d582 branch from 26f0c28 to db22260 Compare August 28, 2026 15:09
@mergify
mergify Bot had a problem deploying to Mergify Merge Protections August 28, 2026 15:10 Failure
jd added 2 commits August 31, 2026 15:40
The docs carried no structured data, so who publishes them, how to contact
Mergify and what product they document were all inferable only from prose.
Search engines and assistants both use JSON-LD for that entity resolution.

Emit one `@graph` per page: an Organization node with the registered address,
support and sales contact points and the canonical social profiles; a
SoftwareApplication node for the product; and either a WebSite node on the
homepage or a TechArticle node for the page itself. The Organization is
declared once and referenced by `@id` from the others rather than repeated.

Every value is taken from something already published: the footer's social
links, the addresses used across the docs, the pricing page. Nothing is
asserted that a reader cannot check against a page, which is the whole point of
publishing it.

`<` is escaped to the JSON unicode escape for it in the serialized graph. Page titles and
descriptions come from frontmatter in this repository, so nothing hostile is
expected there, but `JSON.stringify` leaves `</script>` intact and inlining it
would end the tag early.

Change-Id: Idd84bc050695e27d6d8a361538e2ef89da8dd32e
The 404 offered a search box and a link home. That works for a person; an
agent that followed a dead link gets a page with nothing machine-readable on
it, and a 404 is the one page where it has no other context to work from.

Add a short recovery list: the documentation index, `llms.txt`, the sitemap,
the API reference and the OpenAPI document — plus a note that appending `.md`
to any URL, or sending `Accept: text/markdown`, returns the Markdown source.
Useful to a human who mistyped a URL too.

Change-Id: Ibb77d5829360bfb5b6ae4b1768362c860f5670d8
@jd
jd force-pushed the devs/jd/agentic-readiness/point-lost-agent-somewhere-useful-404--bb77d582 branch from db22260 to 2e2b86a Compare August 31, 2026 13:40
@mergify
mergify Bot requested a deployment to Mergify Merge Protections August 31, 2026 13:41 In progress
Base automatically changed from devs/jd/agentic-readiness/describe-site-schema-org-json-ld--dd84bc05 to main September 9, 2026 08:20
@mergify
mergify Bot requested a review from a team September 9, 2026 08:43
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

4 participants