A small, opinionated, human-readable language for describing robot intent.
Status: Drafted. The normative specification is v0.2.0.md — the capability-manifest schema (frames, locations, events, mobility, manipulation, perception, docking, outputs) plus the provenance: (RFC-0004) and connectivity: (RFC-0006) blocks, and (v0.2.0) the fleet roster, frame transforms, and operational clearance (RFC-0286/0290/0291). The Pass-5 compliance policy is specified in policy.md. This README is the orientation; v0.2.0.md is what a runtime must implement. The prior v0.1.0.md is retained for history.
Layer 1 defines how a robot declares what it can do. A URML-compatible robot ships a capability manifest — a small, machine-readable document describing its mobility, manipulation, perception, declared coordinate frames, declared physical limits, and the safety envelope it operates within. The validator uses this manifest to decide whether a given URML program can be executed by this robot before any actuator moves.
Layer 1 is intentionally a thin layer on top of existing standards. URDF and SDF already describe kinematic and geometric structure; URML reuses them rather than reinventing. The Layer-1 contribution is the capability layer above URDF — the abstraction that lets a URML program ask "can this robot grasp?" without parsing kinematics.
Layer 1 must not assume:
- A specific underlying robot operating system. The manifest is substrate-agnostic; a robot running ROS 2, PX4, AUTOSAR, OPC UA Robotics, or a vendor SDK can all declare the same capabilities the same way.
- That a robot's capabilities are static at runtime. The manifest declares baseline capabilities; runtime extensions (e.g., a gripper picks up a tool that extends its reach) are a separate concern, addressed at most by a small runtime-state extension.
- Sensor data, runtime state, or world-model contents. Those flow through the substrate, not the manifest.
Layer 1 must also not absorb concerns from adjacent layers:
- From Layer 2: what a primitive does. Layer 1 says the robot has a gripper; Layer 2 defines
grasp(...). - From Layer 3: composition. Manifests describe atomic capability, not behavior.
v0.2.0.md carries the manifest schema in full; the items below were the original drafting checklist (see v0.2.0.md §5 for the two — URDF cross-reference, envelope-schema folding — that the shipped schema deliberately does not implement):
- The capability manifest schema (YAML canonical; JSON-LD for tooling). Sections: mobility, manipulation, perception, frames, limits, safety envelope.
- The safety-envelope schema: declared maximums (velocity, payload, force), declared forbidden zones, declared required preconditions.
- Hardware provenance (see Provenance and Compliance below).
- The relationship to URDF/SDF: how a Layer-1 manifest references the URDF that describes the robot's structure.
- A worked example: the capability manifest for the v0.1 demo robot (likely a TurtleBot 4; see
docs/open-questions.mdQuestion 5).
Added by RFC-0004. The capability manifest carries an optional provenance: block declaring per-component hardware origin facts. The validator's Pass 5 evaluates a pluggable compliance policy against this block before any program is accepted for execution. The policy file format is specified in policy.md.
Provenance is optional on the manifest. A manifest without a provenance: block triggers no Pass 5 errors — policy enforcement is opt-in. URML's posture per RFC-0003: the default validator ships with US federal procurement rules active, but a manifest that does not opt into provenance is silently exempt. Deployments that need to prove compliance must declare provenance; deployments that don't have a regulatory frame may omit it.
provenance:
manifest_attestation: self_declared # self_declared | third_party_audited | cryptographically_signed
attestation_uri: null # optional URI to a signed attestation document
components:
- id: drive_controller # ISO-style snake_case identifier
role: critical # critical | non_critical | informational
vendor: example_drive_vendor # free-form machine-readable identifier
country_of_origin: US # ISO 3166-1 alpha-2; "unknown" allowed and meaningful
country_of_final_assembly: US # often differs from manufacture
hbom_ref: # optional
format: cyclonedx-1.7 # recommended; free string
uri: ./hbom/drive_controller.cdx.json
sha256: "<64-hex-char-integrity-hash>"Field-by-field:
| Field | Type | Notes |
|---|---|---|
manifest_attestation |
enum | Who asserts the provenance is true. Policies may require a minimum level; the default US-federal policy warns on self_declared in v0.1 and is scheduled to error in v0.2. |
attestation_uri |
string | null | Optional pointer to a signed attestation document. URML does not fetch this; it records the URI. |
components |
list | One entry per declared component. Empty list is allowed and means "nothing critical to attest." |
components[].id |
identifier | Snake_case identifier scoped to this manifest. |
components[].role |
enum | critical / non_critical / informational. The load-bearing selector for policies. |
components[].vendor |
string | Free string in v0.1. Future RFCs may add a registered-identifier dimension (DUNS, ROR). |
components[].country_of_origin |
string | ISO 3166-1 alpha-2 country code. The literal unknown is accepted and policies may treat it as failing or warn. |
components[].country_of_final_assembly |
string | Same shape; often differs from country_of_origin. NDAA-style rules check both. |
components[].hbom_ref |
object | null | Reference to a Hardware Bill of Materials document. Opaque in v0.1 — URML records the URI and a SHA-256 integrity hash but does not parse SBOM content. |
- URML does not fetch the HBOM document. The validator records what the manifest declares.
- URML does not verify the integrity hash. A future RFC may add this; v0.1 treats the hash as a deployer-controlled commitment, not a check.
- URML does not certify the provenance. The
manifest_attestationfield surfaces the strength of the claim; the correctness of the claim is the declarer's responsibility, not URML's. - The default policy file shipped with the validator is not legal advice. See
policy.mdandCORE_COMMITMENT.mdfor the certified-policy commercial surface.
The provenance: block is part of the v0.1 schema (manifest_version: "0.1") and is fully implemented in the reference validator. The accompanying policy enforcement specification is in policy.md; the strategic and technical decision history is in RFC-0003 and RFC-0004.
Added by RFC-0006. The capability manifest carries an optional connectivity: block declaring the abstract link roles the robot supports. Like provenance:, it is opt-in: a manifest without a connectivity: block, paired with an envelope that declares no link-loss rule, triggers no connectivity errors.
A link role is an abstraction — command_link (operator/supervisor → robot control), telemetry_link (robot → operator status), peer_link (robot ↔ robot; declared now, no behavioural semantics until a future multi-robot RFC), payload_link (bulk mission/sensor data). The transport medium that carries a role — WiFi, 5G, LTE, RF, fibre — is Layer 0 and is deliberately not modelled by URML. This is a hard boundary, not an omission: a manifest that named a radio would fail the substrate-neutrality acid test.
Each declared link carries abstract properties only: required_for_operation, autonomous_when_lost, an optional declared max_outage_seconds tolerance, and an ordered assurance_class (best_effort < monitored < assured < safety_critical). assurance_class is the reconciliation of "express the communications requirement as intent" without coupling to a medium: intent may depend on a link's assurance, never on its radio. The ordering is deliberate so a future regulatory rule (e.g. a beyond-visual-line-of-sight command-and-control assurance floor) can require >= assured additively; RFC-0006 itself ships no such rule.
The deployment-time counterpart — what the robot must do when a declared link is lost — lives in the safety envelope's link_loss_policy, not here. The validator (Pass 2 and Pass 3) statically rejects a policy whose action the manifest cannot satisfy; see RFC-0006 §Detailed design.
RFC-0286 adds the multi-robot analogue of the capability manifest: a roster. A roster gives each robot in a fleet a short, English-callable handle and points at that robot's existing, unchanged per-robot manifest:
roster_version: "0.1"
members:
- { name: courier, manifest: husky_amr }
- { name: arm, manifest: kawasaki_rs }The roster does not nest or alter a manifest — it binds N already-valid manifests by name. The handle declared here (courier, arm) is what a Layer-3 on: scope and a barrier: node address. The roster is optional infrastructure: a single-robot program needs none. A fleet mission file is two YAML documents — the roster, then the program — and the multi-robot validator (validate_fleet) checks each member's program subtree against that member's manifest, plus the cross-robot rules (collision-free concurrency, peer_link for barriers). The roster activates the peer_link role this layer reserved under Connectivity above.
RFC-0291 makes the cross-robot collision check geometric, modeled on UTM (FAA/NASA Unmanned Traffic Management; ASTM F3548). Two things make a target a UTM-style operational volume:
- The roster declares
shared_frames— the frame names that mean one common physical reference across members. The deconfliction check only compares targets whose frame is in this list, so each robot's own local frame (e.g. a privatefloor) is never compared against another's. This is what lets three robots each move to their ownwaypoint_awithout a false collision. - A manifest's
mobilitymay declareclearance(radius_mlateral +vertical_mvertical): the robot's operational-volume buffer. The vertical band is an altitude band for aerial robots (z>0) and a depth band for underwater robots (z<0), via the signed-z convention; ground robots sit near z≈0. The operating medium is derived fromdrive_type— air and water never share space.
Both are optional and additive. A member with no clearance falls back to declared-location-name comparison, still gated by a shared frame.
RFC-0290 lets spatial checks compare poses across frames, not only by string-equal name. It activates the previously dormant Frame.parent: a Frame may declare a transform (a full SE(3) rigid transform — translation + roll/pitch/yaw) giving its pose in its parent, so a manifest's frames form a tree and any pose resolves into any connected frame. For fleets, a roster declares a world_frame and per-member anchors (each member's frame placed in that world — the deployment's site survey), connecting the per-robot trees into one graph. With that, a drone's agl target and a rover's site target resolve into one world and are compared; single-robot geofences and occupancy zones in one frame govern targets named in another.
It is strictly additive: a Frame with a parent but no transform is not numerically related to it, so any check that would need the relation abstains — exactly the pre-RFC-0290 behavior. The frame graph must be acyclic with declared parents.
The conformance suite (/conformance/fixtures/) tests:
- Every required field is present.
- Declared limits are internally consistent (e.g., declared
max_velocityis non-negative and finite). - The manifest's frame declarations are consistent with the referenced URDF.
- The validator correctly rejects programs that exceed declared capability or violate the safety envelope.
/docs/architecture.md§Layer 1./docs/glossary.md— capability manifest, frame, safety envelope./spec/profiles/— each profile may declare additional manifest fields it requires.