v1.0.0 Draft Specification

The protocol for
intelligent robotics

Address, authenticate, and coordinate robotic agents across local networks and the global internet with a federated, offline-first standard.

Why RCAN?

The internet has DNS and ICANN. IoT has Matter. Robotics has nothing.

As millions of robots are manufactured and deployed—from warehouse arms to delivery bots to humanoids—there is no standard way to:

  • Target Address a robot uniquely and globally
  • Auth Authenticate who is allowed to control it
  • Swarm Coordinate fleets and swarms across manufacturers
  • Safety Ensure safety when networks fail

RCAN is an open protocol specification designed to solve these problems with a federated, offline-resilient architecture.

Key Features

Built to handle the complexity of real-world robotics.

Robot URI (RURI)

Globally unique identifiers for every robot, similar to URLs for websites.

rcan://continuon.cloud/continuon/companion-v1/d3a4b5c6

Role-Based Access

Five-level hierarchy: Guest → User → Leasee → Owner → Creator. Each role has explicit permissions.

Local Discovery

mDNS/DNS-SD discovery via _rcan._tcp.local. Works offline when cloud is unreachable.

Safety Invariants

Local safety always wins. Network loss triggers safe-stop. All commands are audited.

Federated Registries

Like email servers, anyone can run an RCAN registry. No single point of control.

Fleet Coordination

Choreographed multi-robot commands, swarm discovery, and conflict resolution.

Built for Developers

RCAN is designed to be easy to implement. It provides standard SDKs for Python, TypeScript, C++, and Rust (coming soon).

Connect to robots just like you connect to databases.

Read the Quick Start Guide
control_robot.py
# Connect to a robot via RCAN
from rcan import RURI, RCANClient, Role

# Parse the robot's address
ruri = RURI.parse("rcan://continuon.cloud/continuon/companion-v1/d3a4b5c6")

# Connect and authenticate
client = RCANClient(client_id="my-app")
await client.connect(ruri)
token = await client.claim(Role.USER, credential="my-key")

# Send a command
result = await client.command("/arm", "move", {x: 0.5, y: 0.2})

# Clean up
await client.release()

Documentation