Static verification engine for URML — Universal Robot Language
Project description
A small, opinionated, human-readable language for describing robot intent.
Validator
Status: Phase 1 in flight. Schemas + four-pass validator + urml CLI + JSON Schema export landed at 0.1.0a1 (pre-alpha). Variable-binding type checking and the LLM bridge are the next milestones.
What this is
The static verification engine for URML. Given a URML program, a Layer-1 capability manifest for the target robot, and the active safety envelope, the validator returns one of two outcomes:
- Accepted — the program is statically valid; the runtime may execute it.
- Rejected with a structured error — the program fails one or more checks; the error is a machine-readable object that a calling tool (often the LLM bridge) can use to revise the program.
The validator is the safety boundary. Per MANIFESTO.md §Design Principles and CLAUDE.md §What Claude Should Never Do:
URML programs are executed only after static verification against the target's capability manifest and active safety envelope. Any "fast path" that skips verification is rejected on review.
Bypassing the validator is structurally hard because the validator and the runtimes are separate processes. A runtime that wanted to skip validation would have to be modified, not merely flagged.
What the validator checks
When fully implemented, the validator runs these checks against every URML program:
Layer-3 (composition) checks
- The program parses as valid URML against the layer-3 grammar.
- Every composition operator is well-formed (no empty parallel, no retry with negative bound, no
on_error: substitutereferencing an undefined behavior). - Every
$variablereference resolves to a priorstore_as. - Types match across producer/consumer primitives.
Layer-2 (primitive) checks
- Every primitive is in the spec (or in a profile the program declares).
- Every primitive's required arguments are present and well-typed.
- Profile-specific argument constraints are honored (e.g., drone-profile
move_todeclares altitude).
Layer-1 (capability) checks
- The robot's manifest declares every capability the program needs (mobility, manipulation, perception, declared frames, declared locations).
- Every named location in the program resolves in the manifest or the world model the manifest references.
Safety-envelope checks
- Every declared limit is honored: max velocity, max payload, max force, max altitude, geofence, force ceilings, no-go zones, link-loss policy.
- Profile-specific envelope checks (drone people-occupancy, industrial cell perimeter, home people-only zones) are applied for whichever profiles the program declares.
What the validator does NOT do
- It does not execute the program. That is the runtime's job.
- It does not parse natural language. That is the LLM bridge's job.
- It does not generate the URML program. That is an LLM's job, via the LLM bridge.
- It does not monitor runtime state. Run-time safety (an unexpected obstacle, a sudden wind gust, a person walking into the cell) is the substrate's job. The validator is static; the substrate is dynamic. Both are required for safety.
Language
- Python, primary implementation.
mypy --strict. Public API fully type-annotated. - A long-running validator service (e.g., as a sidecar to multiple runtimes in production) may eventually be backed by Rust for deployment ergonomics; the Python implementation remains the reference.
API (sketch)
from urml.validator import validate, ValidationResult
result: ValidationResult = validate(
program=program_yaml, # str or parsed dict
manifest=manifest_yaml, # str or parsed dict
envelope=envelope_yaml, # str or parsed dict
profiles=("home",), # which profiles the program declares
spec_versions={
"layer-1-hal": "0.1.0",
"layer-2-primitives": "0.1.0",
"layer-3-behavior": "0.1.0",
},
)
if result.accepted:
runtime.execute(result.program)
else:
# result.errors is a list of structured errors,
# designed to be readable by an LLM and used for revision.
llm_bridge.revise(program_yaml, result.errors)
Core Commitment
The validator is part of the Core Commitment. It will always be Apache 2.0. The safety guarantees of URML flow through this component; gating it behind a license would forfeit them.
Quickstart (current pre-alpha)
cd reference/validator
python -m venv .venv && . .venv/bin/activate # Windows: .venv\Scripts\activate
pip install -e ".[dev]"
pytest
The 22 tests confirm: the red-mug example parses against the schemas; every primitive accepts its minimal valid form; cross-field rules (e.g. move_to requires exactly one of location/pose, capture(media: video) requires duration, release(mode: place) requires at) fire correctly.
What works now at this pre-alpha milestone:
-
Pydantic v2 schemas for Layer-1 (capability manifest), Layer-2 (all 12 RFC-0002 primitives), Layer-3 (composition), the safety envelope, and the top-level
URMLProgram. -
The Step / BehaviorOrStep tagged union accepts the YAML surface (
{move_to: {...}}) and the recursive composition forms. -
The four-pass validator —
urml_validator.validate(program, manifest, envelope, profiles)runs argument, capability, envelope, and binding checks and returns aValidationResultwith structuredValidationErrors. Error codes are stable and namespaced (argument.*,capability.*,envelope.*,binding.*); the LLM bridge will consume this format. -
Example:
from urml_validator import validate result = validate(program, manifest, envelope, profiles=("home",)) if result.accepted: runtime.execute(program) else: for err in result.errors: print(err.render())
urml CLI
After pip install -e . the urml console script is on PATH:
urml validate examples/home/red-mug.urml.yaml \
--manifest reference/validator/tests/fixtures/manifests/turtlebot4_home.yaml \
--envelope reference/validator/tests/fixtures/envelopes/home_default.yaml \
--profile home
Exit codes: 0 accepted, 1 validation failed, 2 usage error (missing file, bad YAML), 64 internal error.
Add --json to emit the raw ValidationResult for machine consumers (LLM bridge revision flow, CI checks).
JSON Schema export
# Print one schema to stdout (suitable for piping into an LLM prompt fixture).
urml schema --name program
# Write all three schemas to a directory.
urml schema --all --out-dir build/schemas/
Produces Draft 2020-12 schemas for URMLProgram, CapabilityManifest, and SafetyEnvelope. The LLM bridge consumes the program schema as the structured-output contract; robot makers consume the manifest schema when writing manifests by hand.
The Python API mirrors the CLI:
from urml_validator import export_schema, write_schemas
schema = export_schema("program") # dict
write_schemas(Path("build/schemas/")) # writes urml-{program,manifest,envelope}.schema.json
What's not in this milestone (lands next):
- Variable-binding type checking across primitives (e.g., that
grasp(target: $foo)requires$footo be an Object-typed binding, not a Measurement). - Geometric geofence containment (polygon-vertex math).
- The LLM bridge (
reference/llm-bridge/).
Related documents
/spec/layer-1-hal/— manifest schema./spec/layer-2-primitives/— primitive contracts./spec/layer-3-behavior/— composition grammar./reference/llm-bridge/— the primary consumer of structured validation errors./conformance/— uses the validator as part of its end-to-end tests.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file urml_validator-0.1.0.tar.gz.
File metadata
- Download URL: urml_validator-0.1.0.tar.gz
- Upload date:
- Size: 106.9 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.11.9
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
87fba6ea932be1f79ecee9fe6e0a778b9945951f78376e205ba2445ae67da835
|
|
| MD5 |
a1c9470b67a27d38cf62bfebe9ad039f
|
|
| BLAKE2b-256 |
e695e01a8e579ed480a018384bb5a52a5d2e967f893052fa16f04d673c5b779a
|
File details
Details for the file urml_validator-0.1.0-py3-none-any.whl.
File metadata
- Download URL: urml_validator-0.1.0-py3-none-any.whl
- Upload date:
- Size: 70.4 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.11.9
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
108f6f2089559284f5a94f0d9b812378a495f9606c85b8c81390ca68bb3bad13
|
|
| MD5 |
a98c0f2e21731514787aee6949706d55
|
|
| BLAKE2b-256 |
99c5eca6180326267e682c81a568b8fdb2e728c877c66ea7558a1d269c37c22f
|