opsinjs

Agents & automation

Which surfaces of this site are a contract a machine can rely on, which are not, and what an agent is expected to do when the answer is "that does not exist".

Overview

A large share of the code written against a design system is now written by a model, and models fail against design systems in a very specific way: asked for a component that does not exist, they invent a plausible one. The invented component has a plausible API, plausible props, and no relationship to anything real. In a to-do app that is an annoying hour. In an app that shows somebody their blood-pressure reading it is a defect with a clinical shape.

opsinjs is built on the assumption that this will happen, and tries to make the failure impossible rather than unlikely. The strategy has three parts:

  1. Every guessable URL answers. A component that is only specified still resolves, and the answer says "planned, not implemented" in a form a machine can read. A 404 is what an agent fills with an invention; a definite negative is not.
  2. Every page has a machine twin. Add .md to any docs URL and you get the processed markdown of that page. There is no chrome and no scraping, and the documentation components are left as self-describing tags whose attributes are the content.
  3. Everything measurable is generated. Prop tables, token tables, contrast figures and the catalogue come from source, so what a machine reads is the same thing CI checks.

This page is the map. If you are configuring a tool, jump to MCP server. If you are writing a prompt, jump to Rules for agents.

What is a contract and what is not

The distinction matters more than the list. A contract is something that will not change shape without a version and a changelog entry. Everything else is free to move.

SurfaceStatusWhat it is
/**.mdContractProcessed markdown twin of any docs page
/llms.txtContractCurated index with absolute URLs and section headers
/llms-full.txtContractThe whole corpus, size-capped
/llms-components.txt, /llms-health.txt, /llms-foundations.txt, /llms-reference.txtContractShards, for context windows that cannot take the whole thing. Each carries its sections whole
/r/registry.jsonContractThe shadcn-spec catalog. Required by the MCP server
/r/index.jsonContractName, type, status, category, links and aliases per item
/r/<name>.jsonContractOne registry item at the default base and style
/r/docs.jsonContractThe offline bundle, versioned
The HTML of any pageNot a contractChrome, markup and class names change freely
Anchor idsNot a contractHeadings are edited; link to a page, not to a fragment
/view/**Not a contractChrome-less preview host, and robots.txt disallows it

If you are scraping the HTML, stop; the markdown twin exists precisely so that you do not have to, and it is stable in a way the HTML is not.

Pick a surface

For a coding agent inside an editor

Install the agent skill, or configure the MCP server, or both. The skill carries the rules; the MCP server carries the inventory. They solve different halves of the same problem and are meant to be used together.

For a retrieval pipeline

Start at /llms.txt for the index and fetch the .md twins of the pages it names. See llms.txt and the shards and Raw markdown API.

For a build script or a validator

Use the machine-readable schemas: the catalogue, the token set, the status vocabulary and the glossary, each as JSON at a stable path.

For an agent with no network

Fetch the offline bundle once and carry it.

The one rule that matters most

Every catalogue row is implemented and installable, and every one has been audited against WCAG 2.2 AA by the authors who built it, in a static source pass and a rendered pass, with the findings fixed in the same change. None has had an independent accessibility review, and none has had a clinical review, so nothing here is for a production health surface until a clinician signs it. That is why an agent's first job is to read the status a surface reports before it writes anything. The surface is arranged so that it can, without guessing: every id resolves, and the answer carries the distinction in a field.

For a shipped id the correct behaviour is to install it from the registry and to say that the API may change in any release, that it has been audited against WCAG 2.2 AA by the authors but has had no independent accessibility review and no clinical review, and that it is therefore not for a production health surface until a clinician signs it. The record is ADR 0025. Installing copies the source into the project, because there is no published opsinjs package to import. For a planned id the correct behaviour is to describe the specification, refuse to emit an import, and stop. No id sits there today, so that rule currently guards the mechanism rather than a live entry. Inventing a name that does not exist, or refusing one that ships, are the two failures this whole surface exists to prevent. Both are stated in full, as testable rules, in Rules for agents, and they are what the evals measure.

The discriminator is implemented on /r/index.json, meta.opsinjs.implemented on a registry item, and the x-opsinjs-implemented-count response header on every machine surface. Three redundant channels, because an agent that misses one will usually catch another.

Verify it worked

The twin returns markdown

curl -s https://opsinjs.pensievelabs.org/components/range-bar.md | head -20

You should get frontmatter and prose, not HTML. Documentation components arrive as <PascalCase … /> tags and that is the format working; an import statement at the top means you have raw MDX from somewhere else.

The index is reachable and absolute

/llms.txt should contain fully qualified URLs. A relative URL in an index is useless to a client that fetched it from somewhere else.

Troubleshooting

The .md twin returns HTML. You requested a path that is not a docs page. The rewrite applies to /:path*.md and to /index.md; other routes have no twin.

The MCP server sees no components. That is a real fault. All sixty built items list source files, and the per-item payloads at /r/<name>.json carry that source inline, so every id the server lists resolves to real files and there is no metadata-only entry to mistake for a fault. An inventory that is empty across the board means something is broken: check that components.json carries the @opsinjs entry in the {name} template form and that the fetch is not being blocked.

An agent invented a prop. Report it as an eval failure rather than as a documentation bug. An implemented component's API reference is generated from the source the registry serves, so an invented prop is a generation failure and not a gap in the page. See Evals.

/llms-full.txt is truncated. It is size-capped on purpose, and "use the shards" is only half an answer, because the four shards cover eight of the sixteen sections and no more: Components, Screens, Health, Accessibility, Content & language, Foundations, Theming & tokens and Reference. Start here, Recipes, Patterns, Handbook, Agents, Registry & distribution and Project have no shard, nor do the package pages, which sit outside the sixteen groups. That is roughly a third of the corpus, and a shard is not its recovery route and never was. Two things are. Any capped file that drops a page ends in a ## Truncated block naming every page it dropped, with the .md URL to fetch each one, so what is missing is enumerated rather than implied. And /llms.txt is not capped. It lists every page in the corpus, names the sections that have no shard, and every URL in it answers to a .md suffix. Fetching one twin is a single request and is usually cheaper than a shard you then have to search.

Next

On this page