Concepts
OpenHAL is an open protocol between agents and hardware. This page defines the protocol's parts.
Hub
The Hub is one process on your computer or a Raspberry Pi, and the hub owns every device. Clients talk to the hub with JSON-RPC 2.0 messages over a WebSocket or stdio, or through the MCP server, which maps onto the same methods.
Device files
Each device has a Device File that lists what can be read, what can be changed, the limits on every change and the safe state.
openhal: "0.1"
device: Klipper 3D printer
id: printer
match:
mdns: _moonraker._tcp
moonraker: { hostname: "printer*" }
connect: { moonraker: printer.local, port: 7125, timeout: 5 s }
read:
state: { type: enum, values: [standby, printing, paused, complete, cancelled, error], every: 1 s }
extruder_temp: { unit: degC, every: 1 s, range: [0, 320] }
bed_temp: { unit: degC, every: 1 s, range: [0, 130] }
progress: { unit: percent, every: 5 s }
write:
extruder_target: { unit: degC, min: 0, max: 260, max_change_per_s: 50 }
bed_target: { unit: degC, min: 0, max: 110, max_change_per_s: 20 }
actions:
pause:
description: Pause the print. Klipper parks the nozzle and keeps the heaters on.
require: ["state == printing"]
resume:
description: Resume a paused print.
require: ["state == paused"]
cancel:
description: Cancel the print. It can't be resumed afterwards.
confirm: confirm-each-time
safe_state:
- { extruder_target: 0, bed_target: 0 }
interlocks:
- if: "extruder_target > 0 degC"
require: "state != error"
message: "Clear the printer error before heating."
watchdog: { heartbeat: 5 s, on_loss: hold }
hazard: medium
notes: "A print keeps running if the hub goes away, so the watchdog holds the printer's state instead of stopping the print. Klipper's own heater checks stay on either way."
provenance: { source: hand-written, by: openhal print babysitter example, at: 2026-10-24 }
confirmed: { by: owner, at: 2026-10-24, sha256: 43396b8f02a70481b9653275f22cc58f96b060ad2e31f4d80214acb26e51af1a }A file is read-only until a person confirms its limits. A limit a tool suggests stays a suggestion until a person confirms the limit.
Safety kernel
The Safety Kernel evaluates every command, from every client, in a fixed order. The kernel checks units, range, step, rate of change, interlocks, the token's scope and confirmation, and stops at the first failure. The kernel is plain code with no model in it, and an unknown value, such as a stale reading, counts as unsafe.
Drivers and grants
A Driver speaks one protocol, such as SCPI or Moonraker. A driver changes hardware only with a Grant, a single-use permission the kernel issues for one exact command.
Errors
A refused command returns a JSON-RPC error with a stable code and name.
| Code | Name | Meaning |
|---|---|---|
| -32010 | LIMIT_EXCEEDED | Outside the confirmed limits |
| -32011 | RATE_LIMITED | Faster than the rate limit allows right now |
| -32012 | INTERLOCK_BLOCKED | An interlock doesn't hold |
| -32013 | CONFIRMATION_REQUIRED | Waiting for a person |
| -32014 | STOPPED | The hub is stopped |
| -32015 | UNVERIFIED_LIMITS | The device file isn't confirmed |
The specification lists every code.
Principals and hazard classes
Every request comes from a principal. A person uses the human token, and an agent uses an agent token with a scope of read, control_low or control_medium. A device file sets its hazard class to low, medium or high, and every change to a high hazard device waits for a person.
Conformance levels
Hubs and drivers declare a Conformance Level. Core covers discovery and reads, Control adds changes and stop, and Full adds actions, routines and confirmations.
What OpenHAL doesn't do
OpenHAL leaves firmware in charge of each device and doesn't replace e-stops, enclosures or interlocks wired in hardware.