opsinjs
IntroductionStart here

Add your first component

One command, what it will put in your project, and nothing else to read.

Overview

This is the sixty-second path. If you want the reasoning, the safety rules and the review checks, Quick start is the longer version. If you want to know what the command will actually write into your repository before you run it, that is here too, at the bottom.

Shipped, and no published host yet

status-pill is implemented and its registry item carries the whole of its source, so the command below is a real one rather than a sketch. What is missing is somewhere to fetch it from by default: there is no npm package and there will not be one, and opsinjs.pensievelabs.org is not serving yet, so @opsinjs resolves only once you point it at a host that is serving. components.json has the entry. The component is shipped: the API may change in any release, and it was audited against WCAG 2.2 AA by its own authors rather than an independent reviewer (see ADR 0025), and it has had no clinical review, so use it in a prototype and not in front of a patient.

Run one command

npx shadcn@latest add @opsinjs/status-pill

That is the whole path. No provider to mount, no plugin to register, no tailwind.config to edit. opsinjs is Tailwind v4 and CSS-variable native, so the tokens arrive as CSS.

Know what it writes

Three files, so it is not a surprise:

<aliases.ui>/status-pill.tsx     the component source is yours now, edit freely
<aliases.lib>/opsinjs.ts         units, categories, error codes: what every component reads
<aliases.lib>/status.ts          the four clinical levels, their words and their glyphs

The item declares those destinations as @ui/… and @lib/…, so where they actually land is whatever your components.json aliases say. In a default shadcn project, that is components/ui/status-pill.tsx and lib/. Two things the command does not write, and both are commonly assumed. It writes no CSS: the token layer is a separate registry item and Presets has it. And it does not add the @opsinjs entry to components.json. That entry is the precondition for the command resolving at all, so you add it first, by hand.

The only entry added to package.json is lucide-react, which is where the level glyphs come from and which any project with iconLibrary set to lucide already has. That is the icon library opsinjs assumes. opsinjs distributes source you own, not a package you upgrade. That is a deliberate trade: you get to change anything, and in exchange you take on the merge when we change it. Upgrading is how that merge is made survivable.

Verify it worked

Three checks, in order of how much they tell you:

  1. The file is there and it compiles. It landed where aliases.ui points, it imports cleanly, and your typechecker is quiet. If the only complaint is @/lib/utils, shadcn init was never run in this project: the registry does not ship that file and every copied component imports cn from it.
  2. The tokens resolved. Render one pill and inspect it: its background should come from a custom property in the opsinjs status scope, not from a literal colour. If you see a hard-coded hex, the token layer was not imported.
  3. It survives greyscale. Switch your display or your devtools to greyscale. The pill must still say which level it is, in words and by its icon. If it does not, the token layer loaded but the component is being used wrongly. Colour is never the only carrier of clinical status.
Not written yet.

Nobody has walked this path end to end against a published registry host. Every step below was verified against a local registry server, so what is unverified is the one thing a reader cannot substitute for themselves: that @opsinjs resolves, that the item fetches over the network, and that the file shadcn add writes is byte for byte the file this repository serves.

Troubleshooting

Unknown registry @opsinjs. components.json has no registries entry mapping the namespace to a URL. Nothing preconfigures it and the CLI has no default for it, so this is the first thing to check; see components.json. A DNS or network failure rather than an unknown-registry error means the entry is there and points at opsinjs.pensievelabs.org, which is not serving yet.

The component renders unstyled. The token layer is not imported, or it is imported before Tailwind. CSS order in opsinjs is load-bearing and the exact position is specified in Next.js and Tailwind v4.

Tailwind classes inside the copied file do nothing. Tailwind v4 scans sources declared with @source. A file copied into a directory Tailwind is not watching produces exactly this symptom. See Monorepo for the @source lines.

Next

  • Quick start has the same command with the reasoning attached.
  • StatusPill is the specification, including the three things it must never be used for.
  • Clinical status semantics says what the four levels mean before you assign one.

On this page