Talk to your robot. It answers in motion.
OpenCastor is the open source runtime that connects AI brains to robot bodies. Speak or type one sentence, a local model drafts a bounded plan, you sign it, and the wheels turn.
You said: Do a 1 meter creep drive
You said: signed
One pass of the loop, set as type. Your sentence, the plan drafted from it, the receipt it left, and the line its screen showed while it moved. The robot has no line of dialogue here because its answer was the motion. The bench video is the proof.
pip install "opencastor>=3.1" castor up
Python 3.10 to 3.13. The >=3.1 matters: a bare
pip install opencastor resolves an older CalVer wheel
with no castor up in it. castor up takes
a bare host to a paired robot printing its pairing QR, on
simulated wheels.
Public beta, and we mean beta. Builds change most weeks, some things are rough, and the release notes tell you which.
Apache 2.0. Live on the bench this week, on a real RC car.
Stop always wins.
Say stop and the word goes straight to the wheels. It does not wait for a model to finish thinking. It does not wait for you to finish the sentence. Motion needs a budget, a window, and a speed cap you approved. If commands stop arriving, the robot stops about a second later. Every action leaves a receipt you can verify offline.
You are not operating a machine. You are asking someone in the room to do one small thing, and being told what it did.
- spoken stop bypasses every model in the stack
- human-approved budget, window, speed cap
- deadman stops the robot about 1 s after commands stop
A plan is inert until signed.
Your sentence becomes a plan, and the plan is a small, boring object: one tool, three arguments, and the limits it has to live inside. It cannot move anything. It moves when a signature lands on it. You sign it from your phone, or a standing owner grant you wrote in advance signs it for you, on terms you set.
Anatomy of a receipt.
Every action leaves one of these behind. The tool name, the arguments it actually ran with, the result, and an Ed25519 signature over the whole envelope. You can check it on a laptop with no network, months from now. There is no account to log into and no server in the loop.
One command, no network, months later:
git clone https://github.com/RobotRegistryFoundation/robot-md-gateway python robot-md-gateway/scripts/verify_receipt.py --receipt r.json --pubkey gw.pub
The verifier lives with the gateway, not with the runtime, and that is the point: it is stdlib and one crypto library, it imports neither the runtime nor the protocol package, and a third party checking your robot should not have to trust either one. It also flips one byte and proves the signature fails, so a run that reports success has asserted both directions.
{
"v": "rcan-action-trace/1",
"rrn": "RRN-000000000012",
"ruri": "rcan://RRN-000000000012/drive.set",
"invoke": {
"type": "rcan/v1/invoke",
"tool_name": "drive.set",
"scope": "MANIPULATE",
"tool_args": {
"throttle": 0.2,
"steering": 0,
"duration_s": 2
}
},
"outcome": {
"status": "ok",
"duration_ms": 1,
"started_at": "2026-08-04T01:37:57.302051+00:00",
"ended_at": "2026-08-04T01:37:57.303164+00:00",
"telemetry_sha256": ,
"envelope_signature": {
"alg": "Ed25519",
"kid": "rover-gw-attest-2026",
"sig":
}
}
} Ten minutes, on the clock.
It is the goal we design against, and the command times itself so the number is yours to check.
Ten minutes is the goal we design against. The timed run that fills the column on the right is the one the flashable Pi image produces when it clears hardware verification, and until that capture exists this page prints ink bars instead of numbers. It is not a certification and we will not dress it up as one.
One command does the work. castor up detects your
hardware, writes and signs a ROBOT.md manifest, issues its tokens,
starts the services, and prints a pairing QR. It timestamps every
step as it goes, so you can check the arithmetic yourself.
- [s]
- detected:
- [s]
- archetype: rc-car
- [s]
- identity: (local — `castor register` upgrades it)
- [s]
- ROBOT.md written and signed (kid rover-manifest-2026)
- [s]
- bearers: tokens generated (actuate + read)
- [s]
- actuator: noop — the rc-car actuator is not installed — `pip install rc-car-actuator`, then rerun `castor up`
- [s]
- attestation: rover-gw-attest-2026
- [s]
- brain: ollama qwen3.5:2b
- [s]
- services written: rover-gateway.service, rover-castor.service, rover-console.service, rover-discovery.service
- [s]
- services started
- [s]
- pairing QR: /pair-qr.png
- [s]
- gaps: 1 noted in gaps.json (missing-package)
The scan.
Scan that QR with the app. Your robot has a face now, and on a vehicle, an eye.
If you would rather never open a terminal.
There is a flashable Pi image: blank SD card to pairing QR. The first build is downloadable now, with hardware verification in progress, so early flashers are exactly that. It ships in two parts under GitHub's file limit; the release notes carry the one-line reassembly, the sha256, and the flashing steps.
Local brains, long memory.
The brain runs on the robot. Ollama with qwen for language, gemma-vision for what the camera sees, and cloud brains available when you want them, optional by design. The robot also keeps a long term memory of its own bench history, and it recalls relevantly.
- brain: ollama qwen3.5:2b
- vision: gemma-vision, on the robot
- cloud brains: optional, per robot, never required
You asked: why won't it move at low throttle?
The question is verbatim. The answer is the robot's own recalled memory, and it goes here once the bench transcript is captured. We are not going to write a plausible one.
The face, and on vehicles the eye.
The iOS app is the robot's face, and on a vehicle it is also its eye. Wake word, per robot brain assignment, and an autonomy grant you hand over on purpose. Autonomy is tiered by what the camera can actually see: with LiDAR it runs full, with sparse depth it creeps only, and blind it refuses and tells you why.
Get the iOS app on the App Store
Public beta, and we mean beta. Builds change most weeks, some things are rough, and the release notes tell you which.
Bodies.
Three bodies, three honest labels. A Raspberry Pi 5 RC car, driving today. An SO-ARM101 six degree of freedom arm, on the bench with its wrist camera unplugged. An ESP32-C6, groundwork toward six dollar class robots that show their own pairing QR on their own screen, and on the bench tonight it does exactly that.
SO-ARM101 arm
on the bench SO-ARM101 six degree of freedom · Feetech STS3215 servos, sixESP32-C6
groundwork ESP32-C6 rev v0.2 · 16 MB flash · toward six dollar class robotsOpenCastor C6 alive chip model : ESP32-C6 (rev v0.2) flash size : 16777216 bytes (16 MB) physical i2c total : 5 devices on the shared bus OpenCastor C6 heartbeat #1 tag=ALPHA uptime=2s free_heap=456464
That board paints its own pairing QR on its panel now, and the QR encodes opencastor.com/pair?demo=esp32c6. Scan it off the bench, or open the page and read what a real pairing QR carries.
The world it plugs into.
ROBOT.md manifests at robotmd.dev. The RCAN protocol at rcan.dev. The code at github.com/craigm26/OpenCastor. The documentation lives at docs.opencastor.com, behind the one Docs link in the header. The older pages of this site, the changelog, the tutorials, the beginner path, the hardware guides, the hub, the config explorer, the blog and the about page, all still work, and every one of them is in the footer below.
- robotmd.dev ROBOT.md, the single-file robot manifest
- rcan.dev the RCAN protocol these envelopes speak
- github.com/craigm26/OpenCastor the runtime itself
- Apache 2.0 the whole runtime, and every line of it is yours to read
- Docs the one door, and it opens on docs.opencastor.com
Start talking.
pip install "opencastor>=3.1" castor up
Python 3.10 to 3.13. The >=3.1 matters: a bare
pip install opencastor resolves an older CalVer wheel
with no castor up in it. castor up takes a
bare host to a paired robot printing its pairing QR, on simulated
wheels.
Public beta, and we mean beta. Builds change most weeks, some things are rough, and the release notes tell you which.