Specification · section 4

The device package

A device is described the way an Agent Skill is: a folder whose contents load in three levels, each only when the agent needs it. This is the same progressive disclosure that lets a harness hold hundreds of skills at about a hundred tokens each, applied to hardware.

thermocycler-01/
├── DEVICE.md          Level 1: YAML frontmatter, the card            (always cheap)Level 2: Markdown body, operating instructions (when the device is chosen)
├── descriptor.yaml    Level 3: full machine-readable spec: limits, params, examples
├── driver.py          Level 3: code, a Driver subclass or an adapter's DEVICE object
├── references/        Level 3: manual excerpts, SOPs, calibration tables
└── scripts/           Level 3: ready-made orchestration scripts for mhp_run
LevelContentServed byLoaded when
1frontmatter: id, class, make, model, location, tags, descriptiondevice/describe {detail: "card"}, directory/searchsearch results; about 40 tokens per device
2DEVICE.md body: how to operate it, what to check, what never to dodevice/describe {detail: "summary"} with a slim capability tablethe agent picks this device; under 1k tokens
3descriptor items, references, scripts, driverdevice/describe {select}, resources/list, resources/read {path}the agent needs that item; none until asked

4.1 DEVICE.md

The frontmatter is the card. description is what a directory ranks and what an agent matches its task against, so it must say both what the device is and when to pick it, in under 1,024 characters. The body is written for the agent that has just chosen the device: an operating procedure, what to watch, and pointers to the resources it may need.

---
mhp: "2026-09-09"
id: thermocycler-01
class: thermocycler
make: SimBio
model: TC-96
location: bay 3, bench 3
tags: [pcr, heating, 96-well]
description: 96-well PCR thermocycler with heated lid, 4 to 105 degC block. Use for PCR,
  denaturation, ligation holds and any timed temperature program on a 96-well SBS plate.
  Not for tubes, not for cooling below 4 degC.
driver: driver.py:SimThermocycler
---

# Thermocycler-01

Sits on bench 3 in bay 3, left of the liquid handler; the plate arm reaches it at `thermocycler`.
The block ramps about 4 °C/s. Turn `lid_heater` on ~40 s before loading to avoid condensation.

## Operating procedure
1. Confirm `lid_closed` is true; `run_protocol` refuses otherwise.
2. Set `lid_heater` true; wait for `lid_temperature` above 100 °C.
3. Invoke `run_protocol`; poll the job. 30 cycles of three steps take ~75 minutes.
4. Write `target_temperature` 4 to hold. Open the lid only below 60 °C (needs a human).

## Resources
- `references/protocols.md`: standard programs per polymerase.
- `scripts/pcr.py`: complete run through `mhp_run`, including the 4 °C hold.

4.2 descriptor.yaml

The machine-readable part. Identity fields live in the frontmatter and are merged in; everything below is enforced or served by the driver.

device:
  notes: >
    96-well block on bench 3, left of the liquid handler. Lid must be closed
    before any run. Block ramps ~4 °C/s; lid heater takes ~40 s to reach 105 °C.

physical:                        # anything the agent cannot infer from code
  mass_kg: 12.5
  footprint_mm: [331, 461, 251]
  power_w: 851
  notes: Bench-mounted, do not relocate while running. Hot lid surface up to 110 °C.

signals:                         # READ
  - name: block_temperature
    type: number
    unit: degC
    notes: Measured at block centre; edge wells lag by ~0.5 °C.
  - name: lid_closed
    type: boolean
    notes: True when the lid latch is engaged.

settings:                        # WRITE
  - name: target_temperature
    type: number
    unit: degC
    limits: {min: 5, max: 106}   # enforced by the driver
    approval: auto               # auto | confirm | forbid
    notes: Below 4 °C condensation forms; above 105 °C the seal fails.

actions:                         # INVOKE -> job
  - name: run_protocol
    duration: long               # short | long
    approval: auto
    interlocks: [lid_closed]     # signals that must be truthy
    params:
      steps: array of {temp: degC, hold_s: number}
      cycles: integer
    notes: Runs a cycling program; steps are repeated `cycles` times.
    examples:                    # what normal usage looks like, §3.5
      - {steps: [{temp: 95, hold_s: 30}, {temp: 58, hold_s: 30}, {temp: 72, hold_s: 45}], cycles: 30}
  - name: open_lid
    duration: short
    approval: confirm            # a human must confirm each invocation
    notes: Lid may be hot; a human should be present.

safety:
  estop: true                    # driver implements safety/estop
  interlocks: [lid_closed]
  watchdog_s: 11                 # driver fails safe if no ping within this window
  notes: E-stop cuts block and lid heaters; the block cools passively.

4.3 Resources

resources/list returns the relative paths of every file in the package except DEVICE.md. resources/read {path} returns a text file's contents, capped, and MUST refuse paths outside the package. Scripts under scripts/ are written for mhp_run and see lab: an agent reads one, adapts the constants, and runs it, so the device owner's tested procedure is what executes.

4.4 Field rules

FieldRule
device.idMUST be unique within a host's set of devices. class is an open string; §13 lists the initial vocabulary.
device.descriptionFrontmatter. SHOULD state what the device is and when to pick it, at most 1,024 characters. It is the ranking text for directories and the card text for agents.
notesAny object may carry one. Notes are natural language for the agent, the mechanism by which tacit knowledge enters the protocol. Drivers MUST pass them through unchanged.
type, unitnumber | integer | boolean | string | object | array. Units SHOULD be UCUM codes or common spellings (degC, mm, percent, N, rpm).
limits (setting){min, max} for numbers, {enum: [...]} for strings. The driver MUST refuse writes outside limits with LimitViolation.
limits (action)A map from parameter name to [min, max]. Drivers SHOULD enforce these inside the action.
approvalauto: the agent may act. confirm: each call needs approved: true, which the host may set only after human confirmation. forbid: never agent-operable; listed so the agent knows the capability exists and why it is off-limits.
interlocksBoolean signals that MUST read truthy at the moment of the write or invoke; otherwise InterlockOpen.
durationshort actions finish within seconds and hosts MAY block on them. long actions run as jobs; the host SHOULD poll or subscribe.
location, tags, examplesOptional but SHOULD be set. Location and tags are what a directory filters on; examples on an action is an array of parameter objects.
unknown keysPermitted at top level (for example locations on a robot arm) and MUST be preserved by adapters and bridges.