---
title: "Agent skill"
description: "Install the opsinjs skill so that the clinical and token rules apply to every generation, without pasting them into a prompt each time."
url: "https://opsinjs.pensievelabs.org/agents/agent-skill"
source: "https://opsinjs.pensievelabs.org/agents/agent-skill.md"
section: "Agents & automation"
kind: "guide"
reviewed: "2026-09-20"
reviewer: "engineering"
aliases: ["skill", "skills.sh", "claude skill", "install rules"]
---

> Elements written as `<PascalCase … />` below are opsinjs documentation
> components. Their attributes are the content: the values they render are
> generated from `tokens/*.json` and `registry/catalogue.ts` and are
> published separately at https://opsinjs.pensievelabs.org/r/index.json and under the Reference
> section.
> Nothing is missing from this page. The data simply does not live in
> the prose.

<PageTemplate kind="guide" />

## Overview [#overview]

The MCP server tells an assistant *what exists*. The skill tells it *what it is
allowed to do with that*. They are complementary and the second one is the half
that carries the safety argument.

A skill is a small bundle of instructions that a coding assistant loads
automatically when it recognises the project. The opsinjs skill contains four
rule files and an eval set, and it lives in this repository at
`skills/opsinjs/`. You can therefore read every word of it before installing
it, which is a property worth insisting on for anything that shapes generated
health UI.

## Install it [#install-it]

<CodeBlockTabs defaultValue="npm" groupId="package-manager">
  <CodeBlockTabsList>
    <CodeBlockTabsTrigger value="npm">
      npm
    </CodeBlockTabsTrigger>

    <CodeBlockTabsTrigger value="pnpm">
      pnpm
    </CodeBlockTabsTrigger>

    <CodeBlockTabsTrigger value="yarn">
      yarn
    </CodeBlockTabsTrigger>

    <CodeBlockTabsTrigger value="bun">
      bun
    </CodeBlockTabsTrigger>
  </CodeBlockTabsList>

  <CodeBlockTab value="npm">
    ```bash
    npx skills add prashantonomy/opsinjs
    ```
  </CodeBlockTab>

  <CodeBlockTab value="pnpm">
    ```bash
    pnpm dlx skills add prashantonomy/opsinjs
    ```
  </CodeBlockTab>

  <CodeBlockTab value="yarn">
    ```bash
    yarn dlx skills add prashantonomy/opsinjs
    ```
  </CodeBlockTab>

  <CodeBlockTab value="bun">
    ```bash
    bun x skills add prashantonomy/opsinjs
    ```
  </CodeBlockTab>
</CodeBlockTabs>

Restart your assistant. The skill activates when it finds a `components.json`
with the `@opsinjs` registry configured, or an opsinjs dependency in
`package.json`.

The skill is also just a directory. If you would rather not install anything
from a network, copy `skills/opsinjs/` out of this repository into your own
project. That directory is five markdown files and a JSON eval set, with no
build step and no runtime.

If your tool does not support skills, the rules are ordinary markdown. Read
[Rules for agents](./rules-for-agents.mdx) and paste it into your system prompt;
you lose the project detection and keep the rules.

## What it enforces [#what-it-enforces]

Four rule files, each one a prohibition with a check attached.

**`rules/tokens-not-values.md`** permits no hex, rgb, pixel radius or
millisecond duration in generated code. Every appearance decision resolves to a
token or to a utility that references one. The check is a regex over the diff: a
literal colour in a generated file is a failure.

**`rules/status-and-colour.md`** requires clinical urgency to be expressed as a
status level, never as a colour, and never as colour alone. Category and status
never colour the same element. The check is structural: a `status` prop plus a
colour class on the same element fails.

**`rules/never-invent.md`** holds that a component that is not in the catalogue
does not exist, and neither does a prop that is not in the component's source.
The rule binds in both directions, because the catalogue can hold two kinds of
row. For a `planned` name the correct answer is to describe the specification,
refuse to emit an import, and stop. No id sits there today, so that branch
guards the mechanism rather than any current id. For one of the sixty built ids
the correct answer is to
install it and say, in the same breath, that a `shipped` API can change in any
release and that nobody has reviewed it. A false refusal is the mirror image of
an invention, and the rule file treats it as the same class of mistake.

**`rules/registry.md`** says never to emit `add @opsinjs/<name>` without first
checking that `components.json` registers the namespace, and to offer the
one-line addition *before* the install command rather than as a footnote after
it. The failure it prevents is specific: an unresolvable namespace produces an
error that reads like a network problem, and the next thing that happens is
somebody hand-writes a component and calls it opsinjs. The rule also forbids
claiming an item has files when the registry says it has none.

## What it reads from your project [#what-it-reads-from-your-project]

The skill is project-aware, which is what makes it more useful than a pasted
prompt. On each activation it reads your configuration so that generated code
matches your project's conventions rather than the documentation's.
Configuration here means framework, aliases, icon library, base library,
configured registries, and which components you have already installed.

It reads. It does not write, and it does not send your source anywhere.

## What it deliberately does not do [#what-it-deliberately-does-not-do]

<SafetyCallout severity="watch" evidence="opinion">
  The skill does not review clinical correctness. It cannot tell you whether a
  threshold is right, whether a message is safe for the population you serve, or
  whether a screen should exist at all. It enforces mechanical rules that catch
  mechanical mistakes. A human clinical review is a separate step and the skill's
  presence is not evidence that one happened. See
  [Safety review checklist](../health/safety-review-checklist.mdx).
</SafetyCallout>

It also does not lint your existing code. It shapes generation. For enforcement
across a codebase, the lint rules described in
[Handbook tooling](../handbook/tooling/index.mdx) are the right instrument, and
they are specified rather than built.

## Verify it worked [#verify-it-worked]

<Steps>
  ### The assistant refuses to invent [#the-assistant-refuses-to-invent]

  Ask for a component that is not in the catalogue at all. A correct response says
  it does not exist and stops. A confident API means the skill did not load. Then
  ask for one of the built ids. A refusal there is the opposite failure, and it
  means the skill loaded against a stale idea of what is built.

  ### It reaches for tokens [#it-reaches-for-tokens]

  Ask for "a card with a warning colour". Correct output uses the status
  vocabulary and a token-backed class. Output containing `#f59e0b` means the
  tokens-not-values rule is not active.

  ### It knows your project [#it-knows-your-project]

  Ask what registries are configured. If it can answer, project detection is
  working; if it describes the documentation's setup instead of yours, it is
  running on general knowledge.
</Steps>

## Troubleshooting [#troubleshooting]

**The skill does not activate.** It looks for a `components.json`. A project
without one will not trigger it, whether that is a plain library or a monorepo
package. Add the file or paste the rules.

**It activates but the rules are ignored on long tasks.** Rules compete with a
long conversation for attention. Re-anchoring helps: ask the assistant to
restate the opsinjs rules before a generation step.

**The rules conflict with our house style.** Fork the skill. It is four markdown
files in this repository, and a fork that keeps the clinical rules while
changing the mechanical ones is a reasonable thing to maintain.

**It suggested code that does not compile.** Check which id and what shape.
There is no published package, so an import from `@opsinjs/react` is always
wrong and is a rule failure worth reporting as an eval case. A component copied
in from the registry that does not compile is a different bug: the usual cause
is a missing `@/lib/utils`, which `shadcn init` writes and a hand-made
`components.json` does not, and it belongs in the component's tracker rather
than the skill's.

## Next [#next]

* [Rules for agents](./rules-for-agents.mdx) has the rules in full, readable
  form.
* [Evals](./evals.mdx) shows how the skill's effect is measured rather than
  assumed.
* [Prompt recipes](./prompt-recipes.mdx) covers prompts written to work with the
  skill rather than against it.
