Skip to content

feat(agent-readiness): RFC 9727 API catalog + native openapi.yaml serve#3343

Merged
koala73 merged 4 commits into
mainfrom
feat/agent-readiness-api-catalog
Apr 23, 2026
Merged

feat(agent-readiness): RFC 9727 API catalog + native openapi.yaml serve#3343
koala73 merged 4 commits into
mainfrom
feat/agent-readiness-api-catalog

Conversation

@koala73

@koala73 koala73 commented Apr 23, 2026

Copy link
Copy Markdown
Owner

Summary

  • Closes feat(agent-readiness): publish API catalog at /.well-known/api-catalog (RFC 9727) #3309 (RFC 9727 API catalog).
  • Serves worldmonitor.openapi.yaml natively from Vercel at https://www.worldmonitor.app/openapi.yaml (build-time copy from docs/api/) — correct Content-Type: application/yaml, no Mintlify proxy hop.
  • Publishes /.well-known/api-catalog (RFC 9727 linkset) with:
    • service-desc/openapi.yaml (the sebuf-bundled 190-operation spec)
    • service-doc/docs/documentation (Mintlify landing)
    • status/api/health
    • Separate anchor for /mcp referencing its SEP-1649 card

Why native serve instead of the Mintlify-proxied URL

Today worldmonitor.openapi.yaml serves via the /docs/:match* → Mintlify rewrite, returning Content-Type: application/octet-stream, text/yaml (doubled). For a public service-desc target referenced by agent scanners, we want a first-party URL with a clean content-type and no proxy dependency. The file is still committed in docs/api/ (unchanged) for Mintlify docs consumption; we just also copy it to public/ at build time.

Changes

  • .gitignore: add /public/openapi.yaml (build output, derived from docs/api/worldmonitor.openapi.yaml).
  • package.json: prebuild hook copies the bundle into public/ before any npm run build invocation.
  • vercel.json:
    • exclude openapi.yaml from the SPA catch-all rewrite (two occurrences: rewrites + no-cache headers).
    • set Content-Type: application/yaml; charset=utf-8 on /openapi.yaml.
    • set Content-Type: application/linkset+json on /.well-known/api-catalog (required by RFC 9727; the generic /.well-known/(.*) catch-all sets CORS + cache but not Content-Type).
  • public/.well-known/api-catalog: new linkset JSON (extensionless per RFC 9727).
  • tests/deploy-config.test.mjs: update the hard-coded SPA catch-all regex assertion to match the new exclusion list — guardrail still validates HTML entry caching.

Test plan

  • Preview deploy: curl -sI <preview>/openapi.yaml returns 200, Content-Type: application/yaml; charset=utf-8.
  • Preview deploy: curl -s <preview>/openapi.yaml | head -3 shows valid OpenAPI YAML (openapi: 3.1.0 ...).
  • Preview deploy: curl -sI <preview>/.well-known/api-catalog returns 200, Content-Type: application/linkset+json.
  • Preview deploy: curl -s <preview>/.well-known/api-catalog | jq . valid JSON, matches RFC 9264 linkset shape.
  • Post-merge prod: same four checks at https://worldmonitor.app and https://www.worldmonitor.app.
  • Re-run isitagentready.com scan — API Catalog check flips green.

Refs PR #3341 (sebuf v0.11.1 bundle landed), epic #3306.

koala73 added 2 commits April 23, 2026 18:00
Closes #3309, part of epic #3306.

- Serves the sebuf-bundled OpenAPI spec natively at
  https://www.worldmonitor.app/openapi.yaml with correct
  application/yaml content-type (no Mintlify proxy hop).
  Build-time copy from docs/api/worldmonitor.openapi.yaml.
- Publishes RFC 9727 API catalog at /.well-known/api-catalog
  with service-desc pointing at the native URL, status rel
  pointing at /api/health, and a separate anchor for the MCP
  endpoint referencing its SEP-1649 card (#3311).

Refs PR #3341 (sebuf v0.11.1 bundle landed).
The deploy-config guardrail hard-codes the SPA catch-all regex string
and asserts its Cache-Control is no-cache. The prior commit added
openapi.yaml to the exclusion list; this updates the test to match so
the guardrail continues to protect HTML entry caching.
@vercel

vercel Bot commented Apr 23, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
worldmonitor Ready Ready Preview, Comment Apr 23, 2026 2:32pm

Request Review

@greptile-apps

greptile-apps Bot commented Apr 23, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR implements RFC 9727 API catalog discovery by serving public/.well-known/api-catalog (a RFC 9264 linkset pointing to the OpenAPI spec, docs, health endpoint, and MCP server card) and by natively serving worldmonitor.openapi.yaml from Vercel with a clean Content-Type: application/yaml; charset=utf-8 — bypassing the Mintlify proxy that was doubling the content-type header. The vercel.json, .gitignore, prebuild hook, and SPA catch-all regex are all updated consistently, and the existing deploy-config guardrail test is kept in sync.

Confidence Score: 5/5

Safe to merge — all remaining findings are P2 style/DX suggestions that do not affect production behaviour.

No P0 or P1 issues found. The two P2 comments cover: (1) the prebuild hook not firing for non-default build scripts (production Vercel uses npm run build, so no deployment impact), and (2) a more precise MIME type hint in the linkset JSON. Both are minor and non-blocking.

No files require special attention for merging.

Important Files Changed

Filename Overview
vercel.json Adds specific header blocks for /.well-known/api-catalog and /openapi.yaml with correct Content-Types; excludes openapi.yaml from both SPA catch-all rules consistently.
package.json Adds prebuild hook that copies docs/api/worldmonitor.openapi.yaml → public/openapi.yaml; hook only fires for the default build script, not variant builds.
public/.well-known/api-catalog New RFC 9727 / RFC 9264 linkset JSON with well-formed anchors and hrefs; service-desc uses application/yaml (valid but less specific than application/vnd.oai.openapi).
tests/deploy-config.test.mjs Updates the SPA no-cache regex assertion to include the new openapi.yaml exclusion — guardrail remains accurate.
.gitignore Correctly ignores /public/openapi.yaml as a derived build artifact.

Sequence Diagram

sequenceDiagram
    participant Scanner as Agent Scanner
    participant Vercel as Vercel Edge
    participant Public as public/ static files
    participant DocsAPI as docs/api/ source

    Note over DocsAPI,Public: npm run build (prebuild hook)
    DocsAPI->>Public: "cp worldmonitor.openapi.yaml to public/openapi.yaml"

    Scanner->>Vercel: "GET /.well-known/api-catalog"
    Vercel->>Public: "serve api-catalog (extensionless JSON)"
    Vercel-->>Scanner: "200 Content-Type: application/linkset+json"

    Scanner->>Vercel: "GET /openapi.yaml (service-desc href)"
    Vercel->>Public: "serve openapi.yaml (build artifact)"
    Vercel-->>Scanner: "200 Content-Type: application/yaml"

    Scanner->>Vercel: "GET /docs/documentation (service-doc href)"
    Vercel-->>Scanner: "302 to Mintlify proxy"
Loading

Reviews (1): Last reviewed commit: "test(deploy-config): update SPA catch-al..." | Re-trigger Greptile

Comment thread package.json Outdated
Comment thread public/.well-known/api-catalog Outdated
- Extract openapi.yaml copy into named script `build:openapi` and
  prefix every web-variant build (build:full/tech/finance/happy/
  commodity). prebuild delegates to the same script so the default
  `npm run build` path is unchanged. Swap shell `cp` for Node's
  cpSync for cross-platform safety.
- Bump service-desc MIME type in /.well-known/api-catalog from
  application/yaml to application/vnd.oai.openapi (IANA-registered
  OpenAPI media type). Endpoint Content-Type stays application/yaml
  for browser/tool compatibility.
- status.href in /.well-known/api-catalog was pointing at
  https://api.worldmonitor.app/health (which serves the SPA HTML,
  not a health response). Corrected to /api/health, which returns
  the real {"status":"HEALTHY",...} JSON from api/health.js.
- Extend tests/deploy-config.test.mjs with assertions that would
  have caught this regression: linkset structure, status/service-
  desc href shapes, and presence of build:openapi across every
  web-variant build script.
@koala73

koala73 commented Apr 23, 2026

Copy link
Copy Markdown
Owner Author

Round-2 review feedback addressed in e94af87 (plus one item from the previous commit):

P1 — status href was pointing at the SPA, not the health endpoint
https://api.worldmonitor.app/health 200s on text/html (the SPA bundle), while the real JSON endpoint is at /api/health (served by api/health.js, returns {"status":"HEALTHY",...}). Corrected status[0].href in public/.well-known/api-catalog to /api/health. Verified both paths with curl -I against prod.

P2 — prebuild only fires for the default build script
Already addressed in fa27eca8a (previous commit on this branch): extracted the copy into a named build:openapi script and prefixed every web-variant build (build:full / build:tech / build:finance / build:happy / build:commodity). prebuild kept as a thin delegator for the default npm run build path. build:desktop and build:pro are intentionally excluded — Tauri sidecar and the standalone pro-test workspace don't ship the spec.

P2 — guardrail test coverage
Added a new agent readiness: api-catalog + openapi build suite in tests/deploy-config.test.mjs that asserts:

  • Linkset structure: api anchor first, points at https://api.worldmonitor.app/, status href ends with /api/health and lives on the api host, service-desc ends with /openapi.yaml with application/vnd.oai.openapi type, second MCP anchor with service-desc pointing at /.well-known/mcp/server-card.json.
  • Build chain: build:openapi exists and references both docs/api/worldmonitor.openapi.yaml and public/openapi.yaml; every web-variant build chains npm run build:openapi; prebuild hook still present; openapi source exists on disk.

Confirmed the P1 assertion would have caught the regression: temporarily reverted the fix locally → red (AssertionError: status href must end with /api/health...) → re-applied → green. Full suite: 30/30 pass.

@koala73
koala73 merged commit dff14ed into main Apr 23, 2026
10 checks passed
@koala73
koala73 deleted the feat/agent-readiness-api-catalog branch April 23, 2026 14:46
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat(agent-readiness): publish API catalog at /.well-known/api-catalog (RFC 9727)

1 participant