Skip to main content

What the OpenCastor ecosystem can do today, and what compliance it meets

14 min read By Craig Merry
opencastor robot-md RCAN RRF compliance EU AI Act FRIA post-quantum

If you want the full narrative on how this ecosystem came together — the architecture, the Anthropic-native bias, the three-tier UX — that’s in the April 29 ecosystem overview. This post is a companion to that one with a tighter lens: what the stack can actually do today, and what regulatory or cryptographic standards it concretely lines up with. I’ve been vague about this in past writing. A compliance engineer reading the site deserves more precision than “EU AI Act-aligned.”

What the stack can do today

Manifest layer

The robot-md CLI reads, writes, validates, and renders a ROBOT.md file. As of v1.4.0:

  • robot-md init — interactive wizard that scaffolds a ROBOT.md, prompts for every required field, explains the compliance-relevant ones (FRIA flag, IFU text, EU register flag), and produces a valid manifest without the operator ever hand-editing YAML.
  • robot-md init --yes — one-shot with sensible defaults; the operator gets a valid manifest in under a minute.
  • robot-md validate — schema-validates a manifest against the canonical JSON Schema, returns a summary of any errors.
  • robot-md render — canonicalizes the frontmatter YAML so downstream signing is deterministic.
  • robot-md autodetect — scans connected hardware (via lsusb, i2cdetect, serial ports) and auto-populates the drivers[] block.
  • robot-md compliance status ROBOT.md — runs a multi-section pre-flight readiness check (local state, compliance artifacts, RRF registry, submission readiness, first-motion readiness) and returns “no blockers — ready for submission” or a list of blockers.
  • Commands that produce signed JSON artifacts for the RCAN §22-26 attestation endpoints, plus the Article 11 technical-doc summary:
    • robot-md emit-fria ROBOT.md → a signed FRIA packet (RCAN §22 / EU AI Act Art. 27)
    • robot-md emit-benchmarks ROBOT.md → a signed safety-benchmark packet (RCAN §23)
    • robot-md emit-ifu ROBOT.md → a signed IFU packet (RCAN §24 / Art. 13(3))
    • robot-md incidents record … → a signed incident-report packet (RCAN §25 post-market monitoring)
    • robot-md emit-eu-register ROBOT.md → a signed EU-register packet (RCAN §26 / Art. 49)
    • robot-md emit-art11 ROBOT.md → a robot-md-art11-summary-v0 packet referencing the others (EU AI Act Art. 11 technical doc summary)

Running compliance status on bob today returns (excerpts; the full report is ~30 lines):

$ robot-md compliance status ROBOT.md

=== Compliance status for RRN-000000000002 (bob) ===

Local state
  manifest:           ROBOT.md (rcan_version 3.2)
  signing keypair:    ✓ /home/craigm26/.robot-md/keys/RRN-000000000002.signing.json
  apikey:             ✓ /home/craigm26/.robot-md/keys/RRN-000000000002.apikey
  audit chain:        ✓ 110 entries (valid)

Compliance artifacts (compliance/)
  ✓ rcan-fria-v1                  (signed, verified)
  ✓ rcan-ifu-v1                   (signed, verified)
  ✓ rcan-safety-benchmark-v1      (signed, verified)
  ✓ rcan-incidents-v1             (signed, verified)
  ✓ rcan-eu-register-v1           (signed, verified)
  ✓ robot-md-art11-summary-v0     (signed, verified)

RRF registry
  endpoint reachable: ✓ https://robotregistryfoundation.org
  RRN resolvable:     ✓
  rcan_version:       ✓ matches (3.2)

Submission readiness
  ✓ emit-fria               ready
  ✓ emit-ifu                ready
  ✓ emit-safety-benchmark   ready
  ✓ emit-incident-report    ready
  ✓ emit-eu-register        ready

✓ no blockers — ready for submission

(The actual run also dumps a “First-motion readiness” section — eleven checks covering HiTL gates, joint velocity caps, object descriptors, camera extrinsic, capability-namespace alignment, backend resolution, device availability, workspace bounds, kinematic completeness, solver block, and joint zero-sign — but that’s about getting the arm moving safely, not about §22-26 submission.)

Identity layer

Every robot that goes through the robot-md register flow gets two durable identifiers issued by the Robot Registry Foundation:

  • RRN (Robot Registration Number) — a public permanent identity, resolvable at robotregistryfoundation.org/v2/robots/<rrn>. Anchors every signed RCAN packet the robot produces. Bob is RRN-000000000002.
  • RMN (Robot Manifest Number) — identifies the specific ROBOT.md version submitted at registration time. Changes when the manifest changes materially.

The signing key lives at ~/.robot-md/keys/<rrn>.signing.json. It never leaves the device. It’s generated locally; only the public key goes to RRF at registration time. The key format is pqc-hybrid-v1: Ed25519 + ML-DSA-65 (NIST FIPS 204, formerly CRYSTALS-Dilithium3). Both signatures must pass on every RCAN packet. The hybrid scheme is the one I shipped in March across the full protocol stack: rcan-spec, rcan-py, rcan-ts, OpenCastor.

Key management also includes:

  • Rotation: robot-md rotate-key ROBOT.md re-generates the local keypair and posts the new public key to RRF.
  • Revocation: robot-md revoke-key ROBOT.md submits a signed revocation; peers polling M2M_TRUSTED will see the revocation before the next key rotation window.

Protocol layer

RCAN is the wire protocol. The stack currently supports three chapter groups that matter for operating bob:

  • §19 Invoke — capability invocation envelopes. When an agent calls execute_capability("pick_place", {...}), the MCP tool constructs and signs an RCAN §19 Invoke packet. The signature is verifiable by any RCAN-aware consumer.
  • §21 Registry — RRN resolution and REGISTRY_REGISTER / REGISTRY_RESOLVE. How robot-md register talks to RRF, and how two robots resolve each other’s identities for M2M communication.
  • §27 Spatial Eval — self-attested spatial-intelligence scores, with RRF counter-sign now live (RRF PR #73 merged earlier today; Cloudflare deploy succeeded). More on this below.

RCAN §22-26 are the compliance chapters. These cover FRIA submission (§22), safety benchmarks (§23), IFU delivery (§24), incident reporting (§25), and EU-register publication (§26). The five emit-* commands each produce a signed packet that matches the JSON schema those endpoints accept.

Agent surfaces

The MCP server is the bridge. One robot-md-mcp process, launched against a ROBOT.md, exposes the robot to any MCP-aware client:

  • Claude Code — the primary surface. The claude-code plugin wraps the MCP server with a skill and makes it zero-config to install. This is what I use when I’m at a terminal.
  • Gemini CLI — verified working with the same MCP server via gemini mcp add.
  • OpenAI Codex CLI — verified working; tools need --dangerously-bypass-approvals-and-sandbox until the sandbox relaxes.
  • ChatGPT — pre-release; the robot-md-http OpenAPI bridge maps the MCP tool surface to an OpenAPI schema ChatGPT can call.
  • Amazon Q CLI — aarch64-blocked (no aarch64 Linux build available as of writing).

For non-interactive dispatch — a cron job, a Slack bot, another agent — robot-md-dispatcher runs a Claude Agent SDK loop on the robot host and only lets goals and results cross the network.

Hardware

The OpenCastor stack carries ~21 hardware drivers under castor/drivers/; robot-md itself currently exposes three capability backends (feetech_depthai, lerobot, realsense) that compose with whatever drivers OpenCastor brings. A partial list of what’s been tested against real hardware or against a maintained test fixture:

  • Feetech SMS/STS series (SO-ARM101 servo bus) — feetech_driver driver, /dev/ttyACM0; bob runs this today through the feetech_depthai robot-md backend
  • Dynamixeldynamixel driver
  • ROS2ros2_driver driver; bridges to any ROS2 action/topic
  • GPIO (RPi)gpio_driver driver
  • ESP32 BLEesp32_ble_driver driver
  • OAK-D stereo camera — accessed via the feetech_depthai backend’s depthai vision pipeline (not a standalone driver); stereo depth works; note: matte objects and certain surfaces create holes in the point cloud the depth model can’t fill
  • Hailo-8 NPUcastor/hailo_vision.py module for on-device inference acceleration; detected at startup by castor/peripherals.py

v1.4.0’s hot-plug daemon (robot-md hotplug-daemon) watches the OS device-event stream and produces a hash-chained event log at ~/.robot-md/hotplug-events.jsonl. HIGH-confidence events (VID:PID matches a single known preset, one matching backend installed) auto-bind to ROBOT.md. MEDIUM/LOW events queue for operator confirmation.

Safety

The safety layer has several interlocking pieces:

  • HiTL gates — declared in ROBOT.md under safety.hitl_gates. Each gate has a scope and a require_auth flag. The scope name matches a capability namespace from the manifest — bob declares one gate covering arm (any motion); other robots might use manipulate, gripper, or whatever capability families they expose. Any capability invocation that matches a gate scope is blocked until an operator explicitly authorizes it.
  • NotifyDispatcher — when HiTLGate.notify fires, it fans out to configured channels. The wiring for WhatsApp, Telegram, and Discord notification (landed in OpenCastor #881) means bob can alert me on my phone when a gate fires, once the channel tokens are configured for his RPi. (The wiring is shipped; bob’s specific channel configuration is the manual smoke step still pending.)
  • Bounds checker — velocity, torque, and payload limits from the manifest are checked before execution.
  • Sensor monitor — configurable thresholds; triggers estop on out-of-range readings.
  • P66 manifest — a static declaration of the robot’s physical safety envelope, reviewed and signed at registration time.

Spatial intelligence

SP6’s Phase 1 (self-attested spatial eval) shipped in v1.4.0. Robots can run a two-track eval (probe + execute), produce a Score.json, and sign it with their RCAN apikey. The signature covers the canonical bytes of the score — with the rcan_signature field cleared before signing, so the loop closes cleanly without a self-reference bug.

Self-attested scores are valid for development, CI gating, and private benchmarking. Registry-attested scores — where RRF independently re-runs the held-out probe split and counter-signs — go through the §27 endpoint, which landed today at RRF (PR #73 merged, Cloudflare deploy succeeded). Bob has already completed the first end-to-end registry-attested submission (sub_8c686d6e-6e87-49ef-8bb5-0b51e5982de7); verify_tool against that score returns {"ok": true, "attestation": "registry-attested"}. A robot can now go from self-attested to registry-attested in one CLI call.


What compliance the stack meets

Standards we line up with by construction

The stack was designed with the EU AI Act in mind. Here’s what that means concretely:

Article 11 — Technical documentation. The ROBOT.md manifest is the technical documentation. It declares identity, physics, capabilities, safety envelope, driver stack, and registration status. robot-md validate checks it against a JSON Schema. robot-md render canonicalizes it for signing. The documentation isn’t a PDF you file once; it’s a versioned file in the robot’s repo, signed by the robot’s key.

Article 13 — Instructions for Use. robot-md emit-ifu ROBOT.md produces a signed IFU packet using the ifu_text field in the manifest. The packet is submitted to RRF’s §24 endpoint. What lands there is a signed artifact with a timestamp and the robot’s public key — not a Word document.

Article 14 — Human oversight. The HiTL gate system is the Article 14 implementation. High-risk actions require operator authorization before execution. The gate scopes are declared in the manifest under safety.hitl_gates[] — operator-defined, robot-specific. An operator who wants to understand why a gate fired can read the manifest — the reason is in the file.

Article 27 — Fundamental Rights Impact Assessment. robot-md emit-fria ROBOT.md produces a signed FRIA packet. The FRIA content is derived from the fria block in the manifest’s frontmatter — a structured declaration of what the robot does, what populations it might affect, and what mitigations are in place.

Article 49 — EU register. robot-md emit-eu-register ROBOT.md produces the signed EU-register packet. RRF’s §26 endpoint accepts it and gives back a registry URL.

Article 72 — Post-market monitoring. The incident reporting endpoint (RCAN §25, robot-md incidents record) is the substrate for post-market monitoring. You can submit an incident report with a structured JSON payload; RRF stores it, signed, with a timestamp. (Earlier drafts of the AI Act numbered this Art. 60; the final adopted text — Regulation (EU) 2024/1689 — uses Art. 72.)

These articles map to the §22-26 RRF endpoints and the corresponding robot-md commands. The correspondence is deliberate, not accidental — the spec, the CLI, and the registry endpoints were designed against each other.

GDPR-aligned key management. Private keys never leave the device. Public keys are posted to RRF at registration time; that’s the only personal-data-adjacent record. Key rotation and revocation are self-serve. No third party ever holds a private key.

OWASP-like security posture. RCAN packets carry the pqc-hybrid-v1 two-signature envelope — Ed25519 (the classical half) and ML-DSA-65 (the PQC half) — described above; both must pass independently. JWT auth is scope-bound: read tier and actuate tier are distinct. The dispatcher uses a default-deny allowlist for read-tier callers — estop is not on the read-safe list; a read-tier token cannot trigger an actuation.

Cryptographic assurances

The pqc-hybrid-v1 profile means every signed artifact carries two independent signatures:

  • Ed25519 — classical, auditable by any standard tooling today
  • ML-DSA-65 — NIST FIPS 204 post-quantum; quantum-resistant

Both must pass. A verifier cannot accept one and ignore the other. The hybrid gives continuity with existing infrastructure while providing forward security against quantum adversaries.

RCAN packets also carry a commitment chain: each packet includes a prev_hash that chains it to the prior packet from the same robot identity. This makes tampering with a historical packet detectable — you’d have to re-sign the entire subsequent chain. The chain is validated during RCAN §21 resolution.

Signed revocation (via M2M_TRUSTED) means a compromised key can be invalidated without waiting for a rotation cycle. Peers polling the revocation list will see the revocation before they’d next accept a packet from that identity.

What “ready for submission” actually means

When robot-md compliance status returns “no blockers — ready for submission,” this is what that means:

  1. The manifest is schema-valid.
  2. The robot has an RRN.
  3. A signing keypair exists on disk.
  4. The FRIA flag is set in the manifest.
  5. The EU-register flag is set in the manifest.

Running robot-md emit-eu-register ROBOT.md --submit at that point produces a JSON packet that matches the schema RRF’s §26 endpoint accepts and POSTs it to https://robotregistryfoundation.org/v2/models/<rmn>/eu-register (note: §26 is keyed by RMN — Robot Manifest Number — because each material manifest revision gets its own register entry; the other §22-25 endpoints use /v2/robots/<rrn>/<kind>). RRF validates the signature, stores the packet, and returns a registry URL.

Bob has been through this flow in development. The compliance bundle lives at ~/bob/compliance/ — six files: art11.json (a robot-md-art11-summary-v0 packet referencing the other five — system identity, hardware provenance, cross-references; not the raw manifest), fria.json, safety-benchmark.json, ifu.json, incidents.json, and eu-register.json. The §22-25 endpoints use Bearer auth via the robot’s apikey; §26 (eu-register) uses signed-body auth without a bearer header — the source of truth is the pqc-hybrid-v1 signature on the packet itself, since RMN-keyed routes don’t have apikey-binding semantics. A skeleton of what eu-register.json looks like:

{
  "schema_version": "1.0",
  "rrn": "RRN-000000000002",
  "robot_name": "bob",
  "registration_timestamp": "2026-04-28T...",
  "rcan_signature": "pqc-hybrid-v1.<ed25519_b64url>.<ml_dsa_b64url>",
  "manifest_hash": "<sha256 of canonical ROBOT.md>",
  "eu_register_fields": {
    "system_type": "arm_manipulator",
    "intended_use": "research and demonstration",
    "deployment_context": "indoor, supervised",
    "operator_contact": "...",
    "fria_reference": "RRN-000000000002/fria/2026-04-28"
  }
}

The rcan_signature field is the pqc-hybrid-v1 signature over the canonical bytes of the packet (with the rcan_signature field cleared before signing, per the same pattern that landed in the SP6 fix in v1.4.0).

What we are NOT claiming

This matters enough to say explicitly.

We are not a notified body. No third party has audited the compliance artifacts, the protocol, or the CLI. The EU AI Act’s Article 43 conformity assessment process — the one that ends with a CE mark — is not something this tooling does.

We are not certified. The safety benchmark (emit-benchmarks) is a self-attested score: the robot runs the eval, signs the results, and submits them. RRF stores them. Neither the eval methodology nor the scores have been reviewed by a certification body.

We are not attested by a third party. The cryptographic attestation is between the robot and RRF — the robot’s key signs the artifact; RRF verifies the signature and stores it. That’s meaningful provenance, but it is not the same thing as an independent safety audit.

What the founder-authored-protocol credibility means: I wrote the RCAN spec. The compliance endpoints in the RRF API were designed to accept the artifacts the emit-* commands produce. The schemas match because I wrote both sides. That’s a real advantage for users — the tooling actually produces what the registry accepts — but it is not a substitute for third-party review.

The right framing is: this stack is aligned with EU AI Act requirements by construction, and ready for submission to a registry that accepts the right artifact shapes. Whether those artifacts satisfy the actual regulatory process in a given EU member state is a question for a compliance engineer or notified body, not for this blog.


Roadmap

RRF §27 (the spatial-eval counter-sign endpoint) landed today — PR #73 merged against the RRF backend, Cloudflare deploy succeeded. spatial_eval_submit_to_rrf is now wired against a live endpoint, lifting spatial-eval scores from self-attested to registry-attested in a single CLI call. A Compliance-bot Managed Agent — a hosted surface that takes a robot repo, runs all five emit commands, and returns a bundle URL — is in design; see the companion post on this blog for where that’s headed. Notified-body integration is years out; it requires a certification partner and a submission process that doesn’t exist yet for software-based robotics stacks.


The compliance live status page for the ecosystem is at robotmd.dev/compliance/. What’s on that page is kept in sync with what the tooling actually does, not what we’re planning.