ADR-0008: Auto-provisioning — python/detect/ as a new top-level package
- Status: Accepted
- Date: 2026-05-24
- Amended: 2026-05-24 (see Amendments below)
Context
Today, bringing up a fresh robot host is hand-rolled: ral init
produces a 3-field stub robot.yaml and the operator hand-authors the
full RobotDescription (joints, sensors, intrinsics, capabilities,
safety envelope, compute) before any skill will load. The schema-level
match function rSkill.check_compatibility already exists in
python/rskill/src/openral_rskill/loader.py:454-480 but is never
invoked during provisioning.
We want a single openral detect command that probes the host (USB / DDS /
GPU / V4L2 / RealSense / network), assembles a complete
RobotDescription with real sensor attributes pulled from the
sensor catalog and real GPU caps so the matcher can evaluate skill
runtime / quantization compatibility, and a sibling ral skill check
that prints the resulting compatibility table.
Adding a new top-level Python workspace package is flagged by CLAUDE.md §12 ("Add a new top-level package — STOP. Propose it in a discussion or ADR first."). This ADR is that proposal.
Decision
Introduce python/detect/ (openral-detect) as a new
top-level workspace member that owns the auto-provisioning machinery:
- Probes (
probes/{usb,dds,gpu,cameras,realsense,network}.py) — pure functions, never raise, return empty + typed warning on missing hardware or missing optional deps. - Schema (
report.py) — PydanticDetectionReportwith sub-models rich enough for the assembler to populate every newRobotCapabilitiesGPU field (commit 2). - Assembler (
assemble.py) — identify-then-enrich: load the canonicalrobots/<name>/robot.yamlfor known rigs, splice catalog-built sensor specs, promote GPU caps ontoRobotCapabilities. - Compatibility report (
compatibility.py) — wrapsrSkill.check_compatibilityand therSkill.list_installedregistry; supports--skills-dirfor in-tree CI walks. - Two new CLI commands:
openral detectandral skill check.ral initis removed entirely in the same release (no backward-compat).
openral-detect depends on openral-core,
openral-sensors, openral-rskill, openral-cli, and
openral-observability. No runtime layer (HAL, World State,
Skill, Reasoner, Safety) depends on it. It is bootstrap-only and
does not appear in the runtime data-flow strip.
Alternatives considered
- Fold into
openral-cli. Rejected:cli/startup must not importpyrealsense2/pynvml/jetson-stats; the optional probes belong behind a real package boundary so the CLI's import-time cost stays small. - Fold into
openral-sensors. Rejected: that package is a static catalog by charter (no live device probing). Mixing live discovery into it would erase the boundary that letsopenral sensor listwork offline. - Skip the package; emit only a JSON detection report and let operators hand-edit the robot.yaml. Rejected: it does not solve the "complete RobotDescription" requirement and forces every operator to learn the schema.
Consequences
- Adds a workspace member;
pyproject.tomlregisters it under[tool.uv.sources]. RobotCapabilitiesgains six GPU/runtime/dtype fields (commit 2). Lands on the pre-publish baseline (schema_version: "0.1"); every committedrobots/<name>/robot.yamland HAL static description gets back-filled with safe defaults in the same commit, and Pydantic defaults make the new fields opt-in for hand-edited custom manifests.rSkill.check_capabilitiesgains runtime + quantization matchers (commit 3). Empty robot lists keep the matcher in the "unknown — skip" branch so legacy manifests behave unchanged.SensorCatalogEntrygains an opt-insignatures: tuple[ SensorSignature, ...] = ()field (commit 5) so probes can reverse-look up devices to the canonical catalog id.- Optional extras
[nvidia],[jetson],[realsense]keep the default install lean.
No layer-boundary crossing in the runtime sense; CLAUDE.md §6.1's eight
layers stay as-is. openral_detect reads openral_hal's
public surface (the canonical robots/<name>/robot.yaml files and the
HAL adapters' static descriptions) without any reverse dependency.