opsinjs

Raw markdown API

Every documentation page is available as markdown at the same URL with .md appended. You get processed markdown, not MDX source, with components left as tags.

Overview

Append .md to any documentation URL and you get that page as markdown.

curl -s https://opsinjs.pensievelabs.org/health/two-colour-axes.md

That is the whole API. There is no key, no endpoint, no pagination and no separate documentation site for machines. The twin is the same page, and it cannot fall out of date with the human version because it is produced from the same source at the same time.

Processed markdown, not source

This is the part that matters and the part most sites get wrong.

The twin is not the raw .mdx file. Raw MDX carries imports, and its JSX is written for this application rather than for a reader; a model handed the source either ignores half of it or invents what it contained.

The twin is processed: remark has run over the MDX and stringified it back to markdown, so imports are gone, headings carry explicit ids, and tables and code blocks arrive as markdown. What processing does not do is render the documentation components. <StubNotice name="range-bar" status="shipped" …/> comes out verbatim, attributes and all, and the sentence it renders in the browser is not in the string. That is measured rather than assumed, because it is written down in app/_machine/corpus.ts. This surface is built around it instead of pretending otherwise.

Three consequences worth knowing:

  • The tags are the machine-readable part. A component's attributes are its content: <ComponentPreview name="range-bar" /> names the component, <ContrastReport scope="materials" /> names the scope. The values those components draw are generated from tokens/*.json and registry/catalogue.ts and published separately, at /r/index.json and under the Reference section. Nothing on the page is unreachable; it is just not in the prose.
  • A twin that contains tags says so. Any twin with a <PascalCase … /> in it carries a block quote, between the frontmatter and the body, explaining what the elements are and where their data lives. A page that is not implemented carries a second quote above that one saying so. If you are writing a parser, those quotes are the cue to go and fetch the data rather than errors to report.
  • Frontmatter is rebuilt, not copied through. The twin carries the authored fields plus url, source and section, so a page read in isolation still knows where it came from. On a component page status is the field to trust, and it reads shipped for a built component. One field is not authored at all: a component page or a screen specimen documents something buildable, and its twin also carries implemented, read from the generated index rather than from the MDX, so no edit to the page can contradict it. A guide, a doctrine page or a generated token reference carries no implemented key, because it documents nothing that could be built and a false there would assert something untrue about a page that is real today. For a per-id answer outside the docs tree, read implemented on /r/index.json, which is where that field is generated and where it is guaranteed current.

The docs version header

Every twin response carries the docs version on the x-opsinjs-docs-version header. It is a header and not a frontmatter key, which matters more than it sounds: a twin saved to a file loses it, so read it at fetch time and store it beside the body yourself. Without it a cached copy cannot be distinguished from a current one, and a bug report six months from now cannot say which version of the documentation an agent read.

Four more headers ride on the same response, and the five of them do not all answer at the same scope. Mistaking one for another is the expensive error, so the scope is worth reading off a table rather than inferring:

HeaderAnswers aboutValue
x-opsinjs-docs-versionThe siteThe docs version this build serves
x-opsinjs-kindThis pageThe page's own kind, sent on every twin
x-opsinjs-statusThis page, on a kind: component page onlyThat component's release phase: planned, shipped or deprecated
x-opsinjs-implementedThis page, when the page documents a component or a screen; otherwise the systemWhether that subject has source behind it
x-opsinjs-implemented-countThe systemHow many component ids have real source behind them

A component or screen twin overrides x-opsinjs-implemented with its own subject's answer, exactly as /r/<id>.json does, so HEAD on a component's .md reports that one component's source status rather than the system's. A A planned id would return false there even though the count beside it is not zero, and every catalogue id is built today so every component twin returns true. Every other page names nothing buildable, whether it is a guide, a handbook chapter or a doctrine page, so the header keeps its system value there, which answers "is anything implemented" rather than "is this implemented". x-opsinjs-kind is sent on every twin, and it is how you tell which of the two scopes you were handed: a twin with no x-opsinjs-kind at all is being served by a build older than this contract, and its x-opsinjs-implemented is the system answer whatever the page is about. x-opsinjs-status is a narrower signal and is absent on most twins by design. A release phase belongs to a component, so only a kind: component page sends one; its absence means the page is not a component, never that the page is unfinished. If you need a per-id answer for something that has no documentation page, ask /r/<id>.json or the roster at /r/index.json instead of inferring one from a header.

There is no per-page last-modified date, in the frontmatter or anywhere else. Nothing in the build computes one, and a fabricated date would be worse than an absent one. The version is the only freshness signal this surface offers.

If you cache twins, cache the version with them, and include it when you report a problem.

What has a twin and what does not

Every page under the documentation tree has one. So does the documentation index itself, at /index.md.

Nothing else does. The playgrounds, the colour browser and the preview host are applications, not documents, and there is no meaningful markdown rendering of an interactive tool. Asking for their twin returns the application.

Verify it worked

You get markdown, not HTML

The first bytes should be a frontmatter delimiter, not <!DOCTYPE.

PascalCase tags are present and explained

Search the output for a < followed by an uppercase letter. On most pages you will find several, and that is the twin working: read their attributes, and take the block quote above them as the pointer to where the rendered values are published. What you should not find is an import statement or a <!DOCTYPE. Either one means you have raw source or the HTML page rather than the twin.

The status is present

Every component page's twin carries status in frontmatter, and the value is shipped for a built component. If a component twin omits status altogether, that is a bug worth reporting: it is the field that stops an agent generating against something that does not exist. A twin for any other kind of page carries no status, which is correct rather than a gap.

Troubleshooting

404 on a .md URL. The path is not a documentation page. Twins exist for the docs tree and /index.md only.

The twin shows a tag where the page shows a table. Expected. The documentation components are not rendered into markdown; fetch the values from /r/index.json or the Reference section. If the human page shows the same gap, that is a different fault. An empty table there rather than a filled one means pnpm run generate had not run when the page was built.

The prose differs between the twin and the page. The rendering differs by design; the words should not. Report a wording difference. That invariant is what the whole surface rests on.

I need many pages at once. Do not crawl. Use the shards or the offline bundle, both of which are one request.

Next

On this page