The machine-readable documentation
Two kinds of JSON are published. /docs-manifest.json is the whole corpus as one array of page records. /docs-data/<name>.json holds the smaller manifests — capability status among them. Both are static files, both are also reachable through /api/public/docs/manifest/{name}, and both change on a deploy rather than on a request.
The corpus manifest#
/docs-manifest.json is the file the application itself reads: backend/app/public_docs.py builds its search index from it, which means the manifest is not a side artefact that can drift from the site — it is the site's own source of truth for what pages exist.
The top level carries site, product, operator, version, generated, statuses and pages. Each row in pages is one document.
| Field | Meaning |
|---|---|
id | The stable page identifier, such as D0024. Uppercase. |
url | The absolute canonical URL. |
kind | capability, workflow, technology, protocol, troubleshooting, guide, glossary, comparison, research, developer or hub. |
markdown | The URL of the Markdown alternate for this page. |
title, description, summary | Title, meta description, and the answer-first paragraph. |
status | One of the five capability status words. |
audiences, channels | Arrays. channels is empty for anything not channel-specific. |
updated | The date the page's facts were last verified. |
related | Outbound links, as site-relative paths. |
The docs-data manifests#
Smaller, purpose-built files live under /docs-data/. public_docs.data_file reads them, and it constrains the name to [a-z][a-z0-9_-]{0,40} before touching the filesystem — a path cannot be traversed through this parameter, so a client passing a name it made up gets null, not a file from somewhere else.
GET /docs-data/status.json HTTP/1.1
Host: connectbyjbrh.com
# or, with a guaranteed content type and the public cache header:
GET /api/public/docs/manifest/status HTTP/1.1
Host: connectbyjbrh.comstatus is the one to depend on: it carries the capability status map that the product status manifest documents field by field. protocols carries the version of each protocol Connect implements, and is what the MCP tool get_protocol returns when it is asked for the list rather than a page.
An unknown name is a 404 with the error envelope {"error": {"code": "not_found", "message": …}} rather than an empty object, so a client can tell "no such manifest" from "manifest with nothing in it".
Freshness, caching and how to notice a change#
The JSON routes send Cache-Control: public, max-age=300 and Access-Control-Allow-Origin: *. Five minutes is deliberate: the corpus changes on a deploy, not on a request, so a cache that briefly serves the previous build is serving something that was true. The browser rule matters for a client-side tool — these can be fetched from a page without a proxy.
Inside the application the index is rebuilt when the manifest's modification time changes, so a deploy that ships new pages is picked up without a restart and a request never pays for a rebuild it does not need.
For a consumer, the cheap change detector is the pair version and generated at the top of the manifest. Store both; refetch the page list when either moves. Per-page, updated tells you whether that page's facts were re-verified, which is a different question from whether its wording changed.
Choosing between the file and the API#
| Want | Use | Why |
|---|---|---|
| The whole corpus, once | /docs-manifest.json | One request, no filtering, cacheable at the edge |
| A filtered slice | /api/public/docs/list | kind, status, channel, audience and limit are applied server-side |
| One named manifest | /api/public/docs/manifest/{name} | Guaranteed application/json and the public cache header |
| A page's text | /api/public/docs/page?ref=… | Returns the Markdown body, not just the record |
There is no version negotiation on any of these and no Accept header to set. If a field is added to a record, it is additive; ignore what you do not recognise and nothing breaks.
Questions#
How large is the corpus manifest?
It holds one short record per page rather than any page bodies, so it is a list you can fetch and keep in memory. Bodies are fetched per page, either as the Markdown alternate or through the page endpoint, which is what keeps the manifest small enough to be worth caching whole.
Are the manifests the same data the MCP server sees?
Yes. public_docs is the only implementation of search and fetch, and the MCP tools, the A2A card, the Assistant's documentation tools and the public HTTP routes are all thin callers of it. A second implementation for one of those doors is how two answers to the same question start to differ.
Can I rely on id never changing for a page?
That is the contract the identifier exists for — see stable identifiers for what is stable, what is not, and which strings must never be parsed for meaning.