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 →# 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()