Every machine listed on the {doc}/user_guide/machines page comes from a single JSON file,
docs/_static/devices.json. Two directives read it: device-table renders a searchable table of
devices, device-card renders a single device as a card. Adding a machine to the docs means adding
one object to that file.
Append an object to docs/_static/devices.json:
{
"id": "curiox-ht2000",
"vendor": "Curiox",
"name": "HT2000",
"kind": "plate washer",
"capabilities": ["plate washing"],
"status": "mostly",
"api": "pylabrobot.curiox.CurioxHT2000",
"api_version": "v1",
"code_slug": "curiox",
"doc_slug": "curiox/curiox-ht2000/hello-world",
"manager": "https://discuss.pylabrobot.org/u/rickwierenga",
"oem": "https://curiox.com/"
}| Field | Required | Meaning |
|---|---|---|
id |
yes | Unique kebab-case identifier. Used by device-card and as the HTML anchor (#device-<id>). |
vendor |
yes | Manufacturer, as users would search for it. |
name |
yes | Model name, without the vendor. |
kind |
yes | Device type, e.g. plate reader, sealer, arm. Must be one of KINDS in docs/_exts/plr_devices/data.py. |
status |
yes | One of wip, basic, mostly, full. See {doc}/user_guide/machines for what each level means. |
capabilities |
no | Core functions, e.g. ["heating", "shaking"]. Must come from CAPABILITIES in docs/_exts/plr_devices/data.py. These drive the badges and the capability filter. |
api |
no | Import path of the driver class, e.g. pylabrobot.curiox.CurioxHT2000. |
api_version |
no | v1, or v0 for drivers still under pylabrobot.legacy. |
doc_slug |
no | The machine's own page, relative to docs/user_guide/ and without the extension. Links the device name and builds the docs link; verified at build time. |
code_slug |
no | The driver's module or package, relative to pylabrobot/. Builds the code link to the source on GitHub; verified at build time. |
manager |
no | Forum profile of whoever looks after this driver, e.g. https://discuss.pylabrobot.org/u/rickwierenga. Shown as their handle, and who to ask about the device. |
oem |
no | Manufacturer product page. |
notes |
no | One line about which models the entry covers, or what is missing. |
The registry is validated when the docs build starts: unknown fields, duplicate ids and unknown
statuses fail the build, as do doc_slug and code_slug values that do not point at a real page
or a real module.
kind and capabilities are controlled vocabularies, listed as KINDS and CAPABILITIES in
docs/_exts/plr_devices/data.py. A machine that needs a genuinely new term gets it added there in
the same change — the point is that "sealer" and "heat sealer" cannot quietly become two different
filter chips. Terms that nothing uses are removed, and a test enforces both directions.
The two slugs exist so entries stay short and the prefixes stay in one place. doc_slug is
resolved against plr_devices_doc_prefix, and code_slug against plr_devices_code_root and the
repository and branch in html_context — the same ones the theme's "edit this page" links use.
If a device already has a registry object, update that object rather than appending another one:
- Set
doc_slugto the guide's path relative todocs/user_guide/, without.mdor.ipynb. - Add the guide to its manufacturer's
{toctree}. - Put a
{device-card}directive in the guide using the registry object'sid.
For example, a notebook at docs/user_guide/agilent/vspin/hello-world.ipynb uses:
"doc_slug": "agilent/vspin/hello-world"and its card is:
```{device-card} agilent-vspin
```Validate registry changes with:
python -m pytest docs/_exts/plr_devices/registry_tests.pyA bare device-table renders every device, with a search box and filter chips:
```{device-table}
```Options narrow it down:
```{device-table}
:vendor: QInstruments
:search: false
:filters: false
```capabilities, vendor, kind and status each take one value and filter the rows. search and
filters take false to hide the search box or the chips, which is useful for a short,
pre-filtered list on a vendor page.
device-card renders one device. It works anywhere MyST is parsed, including markdown cells in the
notebooks under docs/user_guide — put one at the top of a machine's hello-world notebook so the
page carries the same vendor, support level, capabilities and links as the table.
```{device-card} curiox-ht2000
```A directive is rendered when Sphinx builds the docs. In a notebook opened in an editor it shows as a literal code block instead, so a card on a notebook page only appears on the published version.
The markup is generated by docs/_exts/plr_devices, and styled by docs/_static/plr_devices.css.
Search and filtering are handled by docs/_static/plr_devices.js. Capability badge colors are
derived from a hash of the capability name, so a new capability gets a stable color without a CSS
change.