Skip to content

feat(web): serve the REST API reference as markdown for agents - #730

Draft
dash0-dev[bot] wants to merge 9 commits into
mainfrom
feat/agent-readable-api-docs
Draft

dash0-dev[bot] wants to merge 9 commits into
mainfrom
feat/agent-readable-api-docs

Conversation

@dash0-dev

@dash0-dev dash0-dev Bot commented Oct 27, 2026 •

Copy link
Copy Markdown
Contributor

Why

/api-docs is a Scalar page drawn by JavaScript, so an agent that fetches it gets an empty <div id="app"> and a title. The OpenAPI JSON beside it is 166 KB with every schema inlined (the error body appears 111 times). Agents need the reference in a form they can read in one pass.

What changed

  • @lorekit/schemas/openapi/markdown renders the generated OpenAPI document as one Markdown file (~87 KB): an endpoint index, then every operation's parameters, body, responses and a minimal curl (path parameters as <id>, since curl globs {id}), with shared headers and schemas written once and linked.
  • /api-docs.md serves it. /api-docs returns it to Accept: text/markdown (sent private, no-cache, so a CDN that ignores Vary can't hand it to browsers), and the HTML page gains <link rel="alternate"> tags, a plain-text <noscript> note and a Link header (alternate + RFC 8631 service-desc).
  • Fixes two dry-run traps for non-browser callers: X-LoreKit-Dry-Run advertised default: true (the console pre-fill) though the server executes a write without it, now marked x-server-default: false; and it was offered on six read-only POSTs (list, search, facets, pivot, activity, read) that ignore it, now dropped there. A new mcp-core guard (rest-dry-run-parity.spec.ts) holds the spec to each router's requires: write.
  • llms.txt gains a REST API section pointing at /api-docs.md; the deep-links page and the web/openapi agent notes mention it.

How to verify

  • curl -H 'Accept: text/markdown' <preview>/api-docs and curl <preview>/api-docs.md; the page in a browser looks unchanged.
  • pnpm nx test schemas, npx vitest run src/lib/api-docs in packages/web, npx vitest run src/mcp-guards in packages/mcp-core, and the api-docs.e2e.ts journey.

Notes for reviewers

The REST spec has almost no field-level descriptions (1 of ~400 parameters and body fields), so the Markdown shows types, enums, bounds and defaults but not what each field means; adding .describe() to the zod schemas is the natural follow-up. /polish and review-loop have run on this branch (zero open threads).

mthines and others added 4 commits October 27, 2026 11:15
…kdown

Add renderOpenApiMarkdown, a pure renderer that turns the generated
OpenAPI document into one Markdown file: every operation with its
parameters, body, responses and a minimal curl, shared shapes written
once and linked, shared headers documented once.

Mark X-LoreKit-Dry-Run with x-server-default: false and reword its
description: the spec's default: true is only the console pre-fill, and
a request without the header executes for real.

Co-authored-by: dash0-dev[bot] <257284812+dash0-dev[bot]@users.noreply.github.com>
Add /api-docs.md, the OpenAPI document rendered as Markdown, and make
/api-docs negotiate: a request with Accept: text/markdown gets the
Markdown instead of Scalar's empty JavaScript shell. The HTML page now
carries alternate links, a plain-text noscript note and a Link header
(alternate + RFC 8631 service-desc) pointing at both machine formats.

Co-authored-by: dash0-dev[bot] <257284812+dash0-dev[bot]@users.noreply.github.com>
Add a REST API section to llms.txt naming /api-docs.md, the OpenAPI
JSON and the console, and stating that a REST write is real unless it
carries X-LoreKit-Dry-Run: true.

Co-authored-by: dash0-dev[bot] <257284812+dash0-dev[bot]@users.noreply.github.com>
Assert /api-docs.md, Accept: text/markdown negotiation and the HTML
signposts in the api-docs journey. List /api-docs.md on the deep-links
page and describe it in the web and openapi function notes.

Co-authored-by: dash0-dev[bot] <257284812+dash0-dev[bot]@users.noreply.github.com>
@github-actions

github-actions Bot commented Oct 27, 2026 •

Copy link
Copy Markdown
Contributor

The dashboard preview for this PR — redeployed on each push that changes the web app.

Project Deployment Actions Updated
lorekit Ready Ready Preview Oct 27, 2026 12:29pm UTC

Preview always points at this PR's latest commit; Deployment is the immutable build of 7f5e4ae. · Comment /web-preview to force a redeploy. · Workflow logs

@dash0-dev

dash0-dev Bot commented Oct 27, 2026 •

Copy link
Copy Markdown
Contributor Author

✅ No issues found

Re-review at 7f5e4ae: the Accept q-parameter fix is correct and covered by tests, the description now covers both dry-run changes, and all 8 finder candidates were refuted or scored below the bar. No open threads.

Review details
Gate Details
Description vs. code ✅ Description covers the Markdown edition, negotiation, HTML signposts, both dry-run fixes and the parity guard.
Prior review feedback ✅ Earlier review comments are resolved.
Documentation ✅ PR body, CLAUDE.md notes, llms.txt and deep-links explain the Markdown edition and the dry-run default.
Self-review signals ✅ No debug logs, leftover TODOs, or unreviewed stubs.
Code review ✅ The multi-lens review found no blocking issues.
Run Details
Mode full · 6 lines in delta · tier deep · depth checkout
Anomaly ⚠️ single context, no sub-agent dispatch on this host: the intent finder and the verifier ran in the finders own context; holistic and measurability lenses ran abbreviated in-context
Progress open review threads 0 → 1 → 0 → 0 across the last 4 reviews
Checked 19 of 19 changed files read · 8 possible issues → 0 confirmed → 0 posted
Reach 15 changed exports · 8 dependent files · 8 checked
generateSpec — 2 consumer files · 2 checked
generateSpec — 1 consumer file · 1 checked
agentDocsLinkHeader — 3 consumer files · 3 checked
API_DOCS_SPEC_PATH — 2 consumer files · 2 checked
apiDocsMarkdownResponse — 2 consumer files · 2 checked
+10 more
Found produced 8 → posted inline 0 · cleared 0 · carried forward 0 · deferred 0 · below-bar 0
Dropped 2 below-bar
Standards ran — 5 governing docs, 77 bullets against all 19 files; 1 candidate (stale-looking _shared/api/CLAUDE.md wording) contradicted; 0 findings
CI still pending: Web — Playwright e2e (local build + local Supabase), Typecheck, Test & Lint (affected), Web — Storybook interaction + visual tests (changed), Web — Vercel preview (changed) / Deploy Vercel preview · 6 passed
Memories 76 indexed · 5 used (4 knowledge · 1 hotspot)

Memories used

  • knowledge knowledge::renderOpenApiMarkdown@packages/schemas/src/openapi/markdown.ts — finder pointer (re-verified at 7f5e4ae; curl placeholders and anchor facts still hold)
  • knowledge knowledge::generateSpec@packages/schemas/src/openapi/spec.ts — finder pointer (re-verified at 7f5e4ae; 15 advertised ops, six read POSTs excluded)
  • knowledge knowledge::withAgentHints@packages/web/src/lib/api-docs/agent-docs.ts — finder pointer (re-verified at 7f5e4ae)
  • knowledge knowledge::prefersMarkdown@packages/web/src/lib/api-docs/agent-docs.ts — finder pointer; the case-sensitive q fact is stale (fixed in 7f5e4ae) and was dropped
  • hotspot hotspot::packages/schemas/src/openapi/markdown.ts — hotspot checklist line (edge-case class) for the correctness finder

Nothing to report — measurability (3 paths classified), integrations (not activated), severity, 0 files skipped.

pr-reviewer · commit 7f5e4ae · full review · how these findings are produced · updated Oct 27, 2026 12:38pm UTC

mthines and others added 3 commits October 27, 2026 11:53
Extract primaryTag/UNTAGGED, nonNullVariant, hasMeaningfulDefault and
refName for logic the branch repeated; drop fieldTable's always-'Field'
parameter; rename a cryptic local; trim docstrings and a six-line WHY
comment to their summaries.

Co-authored-by: dash0-dev[bot] <257284812+dash0-dev[bot]@users.noreply.github.com>
…s it

The six POST reads (list, search, facets, pivot, activity, read) never
check the header, yet the spec offered it on every POST and the Markdown
said every POST without it changes data. Skip them in the spec, word the
Markdown preamble from the per-operation header list, and add a guard
holding the spec to each router's requires: write.

Co-authored-by: dash0-dev[bot] <257284812+dash0-dev[bot]@users.noreply.github.com>
/api-docs returned its Markdown variant with s-maxage=300, so a CDN that
ignored Vary: Accept could serve it to browsers for five minutes. Send it
as private, no-cache; /api-docs.md stays the cacheable copy.

Co-authored-by: dash0-dev[bot] <257284812+dash0-dev[bot]@users.noreply.github.com>
Comment thread packages/schemas/src/openapi/markdown.ts Outdated
mthines and others added 2 commits October 27, 2026 12:11
…lders

Addresses the pr-reviewer comment: #730 (comment)

Refs: #730
Co-authored-by: dash0-dev[bot] <257284812+dash0-dev[bot]@users.noreply.github.com>
A client sending text/markdown;Q=0 refused Markdown but was read as
q=1 and got it anyway; parameter names are case-insensitive. Raised as
an advisory (below the bar) in the pr-reviewer report on PR #730.

Co-authored-by: dash0-dev[bot] <257284812+dash0-dev[bot]@users.noreply.github.com>

This branch has not been deployed

No deployments
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.

1 participant