Message Type Reference
The RCAN protocol defines a canonical set of message types covering discovery, control, safety, invocation, registry operations, consent, fleet, and EU AI Act compliance. All messages share a common envelope; the type field selects semantics and routing behaviour. See the live compatibility matrix for the canonical message-type table for each revision.
- Type 9 (DISCOVER): Response payload gains
supported_transportsfield (Β§19 constrained transport negotiation). See Β§19. - Type 10 (TRAINING_DATA): JSON-only binary in
payloaddeprecated. Image/video/audio MUST usemedia_chunks[]. See Β§5.4. - Type 12 (FEDERATION_SYNC): Full payload spec defined β
{source_registry, target_registry, sync_type, payload, signature}. See Β§18.
Β§3 β Envelope
Every RCAN message uses the same JSON envelope regardless of type:
{
"id": "uuid-v4", // msg_id β unique per message
"type": 3, // MessageType integer (canonical v1.5)
"priority": 1, // 0=LOW 1=NORMAL 2=HIGH 3=SAFETY
"source": "rcan://...", // Sender RURI
"target": "rcan://...", // Recipient RURI (wildcards allowed)
"payload": { ... }, // Type-specific data
"timestamp": 1741000000.0, // Unix epoch (seconds, required)
"ttl": 0, // Seconds until expiry (0 = no expiry)
"reply_to": null, // ID of message being replied to
"scope": ["control"], // Required RBAC scopes
"rcan_version": "1.6", // MUST be present; validated first
"qos": 1, // 0=fire-and-forget 1=at-least-once 2=exactly-once
"sender_type": "human", // "human"|"robot"|"cloud_function"|"system"
"key_id": "kid-abc123" // Optional: signing key identifier (GAP-09)
} Β§3.5 β Protocol Version Compatibility v1.5
RCAN version strings follow semantic versioning (MAJOR.MINOR). The rcan_version field MUST be the first field validated on any incoming message, before any other processing.
Compatibility Rules
| Situation | Action |
|---|---|
| Receiver MAJOR == Sender MAJOR, Receiver MINOR β₯ Sender MINOR | β Accept β standard case |
| Receiver MAJOR == Sender MAJOR, Receiver MINOR < Sender MINOR | β Accept β ignore unknown fields; apply defaults for missing required fields |
| Receiver MAJOR β Sender MAJOR | β Reject with VERSION_INCOMPATIBLE error |
rcan_version field missing | β οΈ Accept with default "1.0"; log warning at NOTICE level |
Field Defaults for Missing v1.5 Fields
When a v1.5 receiver processes a v1.4 message missing new fields:
delegation_chainmissing β treat as no delegation (flat command)qosmissing β default to0(fire-and-forget)sender_typemissing β default to"human"key_idmissing β validate against current (only) key in trust set
Version Negotiation (DISCOVER / STATUS)
DISCOVER and STATUS messages MUST include rcan_version in their payload. Peers record each other's protocol version on first contact and apply the lower version's rules for the session.
// DISCOVER payload (v1.5)
{
"rcan_version": "1.5",
"capabilities": ["control", "safety", "training"],
"p66_conformance_pct": 87.0
} Β§4 β Canonical MessageType Table (v1.5+)
This table is authoritative for v1.5 and v1.6. All SDKs MUST use these integer values. Integer values are listed for interop reference only β implementations MUST use named enum constants in code.
| Type | Name | Description | Priority | Min QoS |
|---|---|---|---|---|
1 | COMMAND | Motor, action, or behavior command. Requires control scope. | NORMAL/HIGH | 0 |
2 | RESPONSE | Generic response to a prior message. reply_to links to original. | NORMAL | 0 |
3 | STATUS | Telemetry / state snapshot β position, battery, mode, health. | NORMAL | 0 |
4 | HEARTBEAT | Periodic liveness ping. No payload required. | LOW | 0 |
5 | CONFIG | Configuration update. See Β§9.2 CONFIG_UPDATE for required payload schema and authorization rules. | NORMAL | 1 |
6 | SAFETY | STOP / ESTOP / RESUME β safety-critical. Bypasses all queues. Cannot be overridden by AI. ESTOP MUST use QoS 2. | SAFETY | 1 (ESTOP=2) |
7 | SENSOR_DATA | Sensor readings (proximity, IMU, temperature, etc.). | NORMAL | 0 |
8 | AUDIT | Audit trail event β commitment record, chain hash, tamper evidence. | NORMAL | 0 |
9 | DISCOVER | mDNS / peer discovery probe. Responders reply with RURI, capabilities, rcan_version, and (v1.6) supported_transports. See Β§19 Transport Negotiation. | NORMAL | 0 |
10 | TRAINING_DATA | Training data submission. MUST carry consent_token for biometric/audio/visual data. v1.6: JSON-only binary in payload is deprecated β use media_chunks[] for image/video/audio. See Training Consent, Β§5.4 Multi-Modal Payloads. | NORMAL | 0 |
11 | TRANSPARENCY | EU AI Act Art. 13 disclosure β robot announces AI nature, capabilities, operator identity to humans. Required for EU deployment from August 2026. | NORMAL | 0 |
12 | FEDERATION_SYNC | Cross-registry federation synchronization. Β§18 full protocol defined in v1.6. Payload: {source_registry, target_registry, sync_type: "consent"|"revocation"|"key", payload, signature}. | NORMAL | 1 |
13 | ALERT | Asynchronous alert to operator β battery critical, geofence breach, etc. | HIGH | 1 |
14 | TELEOP | Real-time teleoperation stream frames. MUST use QoS 0 (fire-and-forget); stale frames are discarded. | NORMAL | 0 |
15 | CHAT | Natural language conversation turn. Requires chat scope. | NORMAL | 0 |
16 | ERROR | Error response. Payload: {"code": "...", "detail": "..."}. See Error Codes. | NORMAL | 0 |
17 | COMMAND_ACK | Acknowledgement for QoS β₯ 1. Must be sent within 500ms. Links via reply_to. | HIGH | 0 |
18 | COMMAND_COMMIT | Second phase of QoS 2 exactly-once delivery. Receiver sends after processing. See QoS. | HIGH | 0 |
19 | ROBOT_REVOCATION | Registry broadcast: robot identity revoked. Peers MUST invalidate cached keys and consent. See Revocation. | HIGH | 1 |
20 | CONSENT_REQUEST | Request cross-robot access from target robot's owner. See Consent. | NORMAL | 1 |
21 | CONSENT_GRANT | Owner grants requested cross-robot access. Signed by owner JWT. | NORMAL | 1 |
22 | CONSENT_DENY | Owner denies access request. Signed by owner JWT. | NORMAL | 0 |
23 | FLEET_COMMAND | Broadcast command to a robot group. See Β§15. Fleet ESTOP MUST reach β€100 robots in 500ms. | HIGH | 1 |
24 | SUBSCRIBE | Subscribe to a telemetry stream (observer scope). See Β§8.8. | NORMAL | 0 |
25 | UNSUBSCRIBE | Cancel an active telemetry subscription. | NORMAL | 0 |
26 | FAULT_REPORT | Structured robot fault report. Safety-affecting faults update Protocol 66 manifest. See Β§16. | HIGH | 1 |
27 | KEY_ROTATION | Announce new signing key and JWKS update. See Key Rotation. | NORMAL | 1 |
28 | TRAINING_CONSENT_REQUEST | Request consent for training data collection from a subject. See Training Consent. | NORMAL | 1 |
29 | TRAINING_CONSENT_GRANT | Subject grants training data consent. Signed by subject JWT. | NORMAL | 1 |
30 | TRAINING_CONSENT_DENY | Subject denies training data consent. | NORMAL | 0 |
31 | COMMAND_NACK | Negative acknowledgement β command received but rejected (reason in payload). See QoS. | HIGH | 0 |
Priority Levels
| Value | Name | Behaviour |
|---|---|---|
0 | LOW | Processed after NORMAL; background telemetry. |
1 | NORMAL | Standard queue ordering. Default. |
2 | HIGH | Jumps ahead of NORMAL in dispatch queue. |
3 | SAFETY | Bypasses all queues (Β§6 Invariant 2). Exclusively for SAFETY (type 6) messages. |
Β§9.2 β CONFIG_UPDATE Wire Protocol v1.5
Gap: GAP-07 β MessageType CONFIG (5) existed with no payload schema. Any token holder could send arbitrary config payloads.
Required Payload Schema
All CONFIG (type 5) messages MUST include these fields:
{
"config_hash": "sha256:abc123...", // SHA-256 of payload_b64 decoded
"config_version": "1.2.0", // Semver of config being applied
"diff_only": false, // true = payload is a diff patch only
"payload_b64": "eyJ...", // Base64-encoded config JSON
"requires_restart": false, // Robot must restart to apply
"safety_overrides": false // true = modifies safety envelope params
} Authorization Rules
| Change Type | Minimum JWT Role | Notes |
|---|---|---|
| Standard config fields | control | Normal update flow |
safety_overrides: false | owner | Owner-only config changes |
safety_overrides: true | creator | Modifies safety envelope; creator role required |
Fields: brain.provider, safety.* | creator | Always require creator; safety_overrides ignored |
confidence_gate.*) are compile-time constants in the robot runtime. They CANNOT be modified via CONFIG_UPDATE regardless of JWT role. Any CONFIG payload containing these fields MUST be rejected.
Validation Sequence
- Validate
rcan_version(before any other field) - Verify JWT role meets minimum for the config change type
- Decode
payload_b64 - Compute SHA-256 of decoded bytes; compare to
config_hash - If hash mismatch β reject with
CONFIG_HASH_MISMATCHerror; write audit event - Check for forbidden fields (confidence gates); reject if found
- Store current config as rollback snapshot (retain for
rollback_grace_s, default 300s) - Apply config; write audit event with
config_hashandconfig_version
CONFIG_ROLLBACK
Send a CONFIG message with payload_b64: "ROLLBACK" and no config_hash to restore the previous snapshot. Requires same JWT role as the update being rolled back. Rollback is unavailable after rollback_grace_s has elapsed.
Β§15 β Fleet Broadcast / Group Commands v1.5 SHOULD
Gap: GAP-13 β No RCAN message type for fleet broadcast; sequential HTTP calls take O(n) time for fleet ESTOP.
FLEET_COMMAND Payload
{
"group_id": "floor-3-bots", // Fleet group identifier
"rrn_list": ["RRN-001", "RRN-002"], // Explicit member list (optional override)
"command": "ESTOP", // Command name
"params": {}, // Command parameters
"require_ack_all": true, // Wait for ACK from all members
"fleet_token": "eyJ..." // JWT with fleet claim listing target RRNs
} Addressing
- Local network: UDP multicast on
239.255.66.0/24port6600 - Fallback: TCP unicast to each robot in
rrn_list - Cloud: POST to
/api/v1/fleets/{fleet_id}/commandwhich fans out
Fleet ESTOP SLA
Fleet ESTOP MUST reach all members of a β€100 robot fleet within 500ms on a local network. Implementations that cannot meet this SLA MUST fall back to individual unicast ESTOP messages in parallel.
Fleet JWT Claims
{
"sub": "human-uuid",
"aud": "rcan://fleet/floor-3-bots",
"fleet": ["RRN-000001", "RRN-000002"], // Robots this JWT authorizes
"scope": ["control"],
"exp": 1741003600
} Β§8.8 β Observer Mode v1.5 SHOULD
Gap: GAP-15 β No read-only streaming; observers had to poll individual status endpoints.
Observer JWT Scope
The observer scope is read-only and MUST NOT be combined with any control scope (control, safety, training) in the same JWT. Servers MUST reject any write operation from an observer-scoped token, regardless of payload.
SUBSCRIBE / UNSUBSCRIBE
// SUBSCRIBE payload
{
"stream": "status", // "status" | "telemetry" | "audit"
"filter": {"rrn": "RRN-001"} // Optional filter
}
// Server responds with COMMAND_ACK containing subscription ID
// Then delivers matching events as server-sent events or WebSocket frames Streaming Endpoints
GET /api/stream/statusβ robot status updates (SSE)GET /api/stream/telemetryβ sensor data stream (SSE / WebSocket)GET /api/stream/auditβ audit events (SSE, requires audit scope)
Observer connections are terminated when the JWT expires. The server MUST close the SSE connection and return HTTP 401.
Β§16 β Structured Fault Reporting v1.5 SHOULD
Gap: GAP-20 β Only a generic ERROR type existed; no fault taxonomy or safety manifest integration.
FAULT_REPORT Payload
{
"fault_code": "SENSOR_PROXIMITY_FAILURE", // See taxonomy below
"severity": "critical", // "info"|"warning"|"error"|"critical"
"subsystem": "sensor", // subsystem prefix
"description": "Left IR sensor not responding",
"affects_safety": true, // Degrades P66 invariant?
"safe_to_continue": false // Robot should halt?
} Standard Fault Code Taxonomy
| Prefix | Example Codes |
|---|---|
SENSOR_ | SENSOR_PROXIMITY_FAILURE, SENSOR_IMU_DRIFT, SENSOR_CAMERA_OFFLINE |
MOTOR_ | MOTOR_OVERCURRENT, MOTOR_ENCODER_FAULT, MOTOR_THERMAL |
BATTERY_ | BATTERY_CRITICAL, BATTERY_CELL_FAULT, BATTERY_CHARGING_FAULT |
NETWORK_ | NETWORK_REGISTRY_UNREACHABLE, NETWORK_PEER_TIMEOUT |
SAFETY_ | SAFETY_WATCHDOG_EXPIRED, SAFETY_ESTOP_STUCK |
AUTH_ | AUTH_KEY_EXPIRED, AUTH_TOKEN_REVOKED |
CONFIG_ | CONFIG_HASH_MISMATCH, CONFIG_VERSION_DOWNGRADE |
Safety Manifest Integration
Faults with affects_safety: true MUST update the Protocol 66 manifest with an active_faults list. The manifest's safe_to_continue aggregate is false if any active fault has safe_to_continue: false. Operators receive a push notification for severity: "critical" faults.
Migration from v1.4
msg.type == 1 (DISCOVER in old spec) must be updated. Always use named enum constants β MessageType.DISCOVER β never hardcoded integers.
Old spec integers that changed:
- DISCOVER: was
1β now9 - STATUS: was
2β now3 - COMMAND: was
3β now1 - TRANSPARENCY: was
18β now11 - HANDOFF: was
19(reserved) β removed (deferred to v1.6)
rcan-py's internal enum (COMMAND=1, STATUS=3) was already closer to the v1.5 canonical table; only minor renaming is needed there (AUTHβSENSOR_DATA, AUTHORIZEβAUDIT). See docs/v1.5-tracking.md for SDK migration checklist.
Python Usage
from rcan.message import MessageType, RCANMessage, SPEC_VERSION
# Create a COMMAND message (type 1)
msg = RCANMessage.command(
source="rcan://rcan.dev/acme/arm/v1/unit-001",
target="rcan://rcan.dev/acme/arm/v1/unit-001",
payload={"cmd": "move_forward", "speed": 0.5},
)
# SPEC_VERSION is the single source of truth β do not hardcode version strings
print(SPEC_VERSION) # "1.10" See Also
- Safety Conformance β ESTOP, Protocol 66, time sync, audit export
- QoS & Delivery Guarantees β retry semantics, ESTOP exactly-once
- Consent Wire Protocol β CONSENT_REQUEST / GRANT / DENY flows
- Replay Attack Prevention β msg_id seen-set, replay window
- Robot Identity Revocation β ROBOT_REVOCATION broadcast
- Command Delegation Chain β R2R command provenance
- Key Rotation β JWKS, key_id, grace period
- Offline Operation β cached keys, restricted mode
- Cloud Relay Identity β sender_type, cloud_provider
- Training Data Consent β EU AI Act Article 10
- Error Codes β full error code reference