Release History
Changelog
What's new in OpenCastor — features, fixes, and breaking changes.
Ask the robot to paint a picture, from the phone
- A paint job on the console —
POST /eval/paintstarts onecastor bench sacpaint runon the robot from the operator’spaint.jsonprofile;GET /eval/paintreports strokes, misses, model calls and finally the score;POST /eval/paint/stopends it. One job at a time: the arm is one arm, and every stroke still goes through the gateway with a signed receipt. - A picture of your own —
POST /eval/picturetakes a JPEG and traces its edges into a scoring skeleton (castor bench sacpaint new --auto-trace), so the paint is still scored. - Watch it grow — the OpenCastor body posts its canvas to the console after every move (
-E canvas_post_url) and writes a small progress file (-E progress_path). - iOS 1.3 (build 78, TestFlight) — a Paint a picture card on every paired robot’s page: the photograph of Sacramento by default, a photo picker, one button, the live canvas, and a plain-language reading of the score.
- Measured — Opus through the owner’s subscription painted Sacramento on an SO-ARM101’s virtual easel in 31 minutes, 52 looks, 147 moves, composite 0.35; the oracle trace scores 0.82 on the same rig.
Sacramento PaintBench is a castor bench benchmark
castor bench sacpaint— the standalonesacpaintpackage moves into the runtime ascastor.bench.sacpaint. A robot with a pen must reproduce a photograph of Sacramento from camera feedback; any photo of the finished sheet scores offline withcastor bench sacpaint score PHOTO. Install the eval stack withpip install "opencastor[paintbench]"; a plain install pulls no eval framework.- The reference is the photograph — the model sees the original picture; the scorers read a stroke skeleton traced over its landmarks, and every EvalLog carries both hashes.
- Media as categories — every score carries
medium(pen,virtual,sim), each ranked on its own.-E medium=virtual -E calibration=easelruns an arm with no paper and no pen: the canvas is inked from where the arm measured its tip. First real-arm run, an SO-ARM101 on 2026-09-09: 649 moves, 62 minutes, composite 0.82. - The runtime’s first Python gateway client — RCAN envelopes to
/v1/invokewith signed receipts kept as JSONL, a deny raised as a safety abort with the driver’s sub-code, a reach that ran but missed told apart from a fault. - Console —
/eval/reference.pngserves the packaged photograph; the 3.2.0/eval/*routes for the phone’s frames and corners are now in the changelog too.
The Microduck is the reference robot, and the ten-minute goal is a command
castor bench ten-minutes --robot microduck— seven timestamped checkpoints from “package installed” to “robot.stop observed after silence, naming which deadman fired”, a JSON record with versions, shas, duck identity and every wire line, an EvalLog export thatinspect-robotsreads back byte for byte, and three targets: a mock robotd, Pollen’s own simulator running the realrobotd, and a real duck. Today the sim passes C1 to C6 in 3.5 seconds; nothing has touched a physical duck yet, and the record says so.- Five wire faults fixed —
castor duckhad never been run against a real robotd. Four keys read from the wrong struct, androbot.subscribehad never once succeeded. Two independent runs against the live daemon found the same fifth fault. castor up --archetype microduck— six units including the bridge asduckbridge.service, one token the phone and OpenCastor share, port 7788 agreed in four places.transport: webrtc— drive a duck overmediad’s own network transport with no SSH key, norobotgroup and no reboot (pip install "opencastor[microduck-webrtc]"). The guide now states plainly thatmediadis unauthenticated on0.0.0.0.castor doctorknows ducks and calls a mock driver a failure; the duck’s LLM tools finally register;castor duckwrites a manifestcastor runaccepts, never prints “Duck ready.” for a duck that did not answer, and says its speed envelope out loud.- RC car —
castor doctorreads the PCA9685 back and reports a chip that forgets its configuration, found on the first hardware contact; the bring-up checklist gained that step.
Box to driving in under ten minutes, and the Microduck
Published on PyPI as 1!3.1.0: install with pip install "opencastor>=3.1". The epoch is what makes pip prefer this line over ninety-seven older date-versioned releases that had no castor up in them.
- Real wheels are one question away —
castor upasks, with the wheels-off-the-ground warning, when it detects a PCA9685;rc-car-actuatoris a core dependency; the template’s channels match every reference vehicle; the manifest can no longer draft a stop (duration_shas no default). - Discovery ships — a fifth unit advertises
_opencastor._tcpwith rrn, ports, name and manifest path;castor discovery checkproves it from the wire. castor doctorreads the robot it provisioned — real ports,/dev/i2c-1, simulated wheels, mDNS, USB current versus a streaming camera, every capability gap, each with a pasteable fix and a non-zero exit when the car cannot move.- The Pi image enables I2C at first boot and ships as one file; the install and port docs agree with the code;
castor initasks the robot’s shape first.
The Microduck, and one command from bare host to paired robot
- Pollen Microduck support — a 25 cm walking biped whose motion comes from RL policies executed by its own
robotddaemon at 50 Hz. OpenCastor is an intent client over robotd's JSON-RPC 2.0 NDJSON socket; robotd keeps exclusive ownership of the motor bus. Hardware guide → castor duck— one command from a duck on the desk to a duck under an LLM: find it, prove we can reach it, ask robotd how it feels, write the config. Discovery tries five things (local socket, hostnames,duckctl ipover Bluetooth, mDNS, ARP with--deep) because Pollen's own docs admit mDNS “resolves when it feels like it”. The two things that can block you — SSH access androbotgroup membership — each get their exact fix printed.- The whole vocabulary — reading
duck-ipc-prototurned up twenty-tworobot.*methods against the eleven the driver knew.robot.donow carries the five scripted skills (ground_pick, both kicks,sit_toggle,roulade);robot.soundcarries the seven-sound voice bank including the heldwheee;robot.mouthandrobot.posejoin the twist as continuous intents. - Choreography —
robot.doruns exactly one skill, so there is no way to say “walk to the ball, line up, knock it toward the couch, then celebrate”. Every verb exists; the sentence does not. Thirteen primitives now carry how long a move occupies the duck and whether it holds the robot exclusively, and thirteen routines compose them —fetch,greet,patrol,nudge,celebrate,settle.castor duck do "greet me, then patrol the room". castor up— the ten-minute contract as a command: detect hardware → pick archetype → generate the robot home (signed ROBOT.md, rcan.yaml, bearers, policy, keys, runtime) → start the systemd units → detect a brain → write the pairing QR. Non-interactive and idempotent throughout: every question it could ask is one it can answer by looking at the machine.- Universal-link pairing — the QR is a link any camera understands, with the server half to match. The QR states what this robot can do, so a car stops arriving as an arm.
- DuckKit — the duck's brain as a zero-dependency Swift package, so a phone runs the real trained policy with no robot in the room. github.com/craigm26/duckkit
- Fixed —
rc-car-actuatorwas a hard requirement that brokepip install opencastorfor weeks; it is now the[rc-car]extra. The peripheral scanner could not see a board that had just been plugged in. Two tools shared one file and disagreed about its shape, and--forceate a live key.
A plan is a proposal. The choreographer computes no permission — every motion goes out through the driver and the SafetyLayer, the duck's own limits apply on top and come back in robot.state.limited_by, and steps abort on a fall or a flat battery. robotd remains the only thing that decides what a servo does.
Auto-detection must never offer a LoRa radio as a servo bus
- Detection put a green tick next to
/dev/ttyACM0— an ESP32 LoRa radio — labelled “controller board”, andcastor arm verifytherefore defaulted to it. A denylist is now checked before any allowlist match: Espressif/Adafruit/Arduino VIDs plus product-string matches onheltec|lora|meshtastic|meshcore|esp32|rak|t-beam. - The ordering matters: pyserial asserts DTR and RTS on open, which is esptool's reset-into-download-mode sequence on an ESP32-S3 native-USB CDC. Probing such a board does not merely fail — it can knock it out of operation.
Conformance re-verified against the frozen spec
- All 195 tests across the conformance, compliance and RCAN 3 compliance suites pass against the post-freeze rcan-spec. No code changes — the release memorializes the verification outcome with a signed version-tuple envelope.
Two CLI gaps caught while recording the peer-runtime demo
castor initnow matches the v3.0 wizard. The argparse registration was still the legacy shape and did not hit the wizard's expected attribute names.castor validate ROBOT.mdnow works. The old handler always fed the target throughyaml.safe_load, which errored on any ROBOT.md because the frontmatter-markdown format contains two---documents.
ROBOT.md-native, full RCAN 3.x peer runtime
- Version scheme change — CalVer (2026.4.23.0) → SemVer (3.0.0). The major signals peer-runtime alignment with rcan-spec 3.2, rcan-py 3.3 and rcan-ts 3.4.
- Legacy
.rcan.yamlinput removed — runtime, register and compliance commands read ROBOT.md (v3.2 frontmatter) as the canonical source. The 2.x config path is rejected at ingress with acastor migratehint. castor/rcan3/— the peer-runtime integration package: ROBOT.md reader with runtime selection, ML-DSA-65 + Ed25519 hybrid identity (private keys written0o600atomically, no chmod race), dict-level signer, async RRF client, the §22–26 compliance facade, and the Harness Protocol.- Removed —
castor.config_validation(superseded by rcan-py'srcan.validate) and five legacycastor rrfsubcommands.
RCAN v2.2 — Post-Quantum Primary • Dual-Brain • LLMFit • Hardware Stats
- RCAN v2.2 — ML-DSA-65 primary — Ed25519 fully removed (not sunset-dated, removed).
signature.alg = "ml-dsa-65"is the sole wire format. Legacypq_sigfield removed. Q-Day timeline accelerated from 2028 to 2026. - rcan-py v1.2.1 — 675 tests,
MLDSAKeyPair,sign_message()/verify_message()withrequire_pq=Truedefault.KeyPairstub redirects toMLDSAKeyPairwithDeprecationWarning. - rcan-ts v1.2.1 — 545 tests,
SignatureBlock.algnarrowed to literal"ml-dsa-65",pqSigremoved fromRCANMessageData. - Dual-brain architecture —
brain_reactive(VLA/SLM, fast) +brain_planning(Claude/GPT, slow). Confidence gate at 0.60 — below escalates to planning brain. Wire field:brainadded to action dict. - Production data wipe + re-registration — Firestore
robotscollection + RRF KV cleared. Bob (RRN-000000000001) re-registered with new ML-DSA-65 key, dual-brain configured. - castor conformance L5 — Full RCAN v2.2 compliance report across 6 domains. Score formula:
max(0, 100 − failed×10 − warned×3). Bob scores 100/100.GET /api/conformanceendpoint added. - castor iso-check — ISO 13482, ISO 10218-2, ISO 42001, EU AI Act Art. 12/13/14/15/16j self-assessment. Bob: COMPLIANT (self-declared). EU AI Act deadline: August 2, 2026.
- castor llmfit — Model-fit checker: BF16 weight estimate + KV cache + overhead vs device RAM. TurboQuant 2.6× compression. MoE-aware.
psutil-optional with/proc/meminfofallback. - castor/system_info.py — Real hardware stats in
/api/status: RAM, disk, CPU temp, NPU detection (Hailo-8/8L, Coral TPU, Qualcomm HTP), GPU, active model size, context window, llmfit headroom, tok/s. Auto-flows to Firestore via 30s telemetry push. - opencastor-client hardware stats — Robot detail screen shows live RAM, disk, CPU °C, NPU+TOPS, GPU, model+size, TurboQuant KV status, llmfit headroom, and tok/s as pill chips.
- DISCOVER iso_conformance block — RCAN DISCOVER (msg_type=1) now includes
iso_conformanceblock.rcan_versionbumped to"2.2"in all gateway endpoints. - OpenCastor gateway:
GET /api/attest,POST /api/attest/verify,GET /api/sbom,GET /api/sbom/download,GET /api/conformance. - opencastor-client:
AttestationCard+ compliance report button on robot detail./robot/:rrn/attestationalias route.
Competition Engine — Sprint, Threshold Race & Bracket Seasons
- Sprint format — time-boxed competitions with announced prize pools, tiered payout (50/30/20), anti-snipe 1h lock (
castor/competitions/sprint.py) - Threshold Race — jackpot mechanic, first robot to hit target score wins, 3× independent verification re-run with 2% tolerance (
castor/competitions/threshold_race.py) - Model×Hardware Bracket Seasons — monthly seasons, 5 hardware×model classes, class champions (2000/1000 credits), grand champion bonus 5000 credits (
castor/competitions/bracket_season.py) - Competition API endpoints: GET/POST
/api/competitions,/api/competitions/races,/api/seasons/current - Gemini 2.5 migration — all Gemini 2.0/1.5 model strings updated ahead of June 2026 deprecation
- Contribute 10× throughput — Firestore client and queue state now cached; fetch latency 4.6s → 14ms
- Auto-start contribute on gateway startup via
agent.contributeconfig
castor contribute — Idle Compute for Distributed Science
castor contribute start|stop|status|projectsCLI — donate idle NPU/CPU cycles to climate modeling, biodiversity monitoring, protein folding, and humanitarian AI- BOINC, Folding@home, and OpenCastor coordinator support with configurable project allowlists
- P66-safe: any incoming command preempts contribute work within 100ms via
ContributeCancel - Hardware-aware work unit matching: Hailo-8L HEF models, CPU fallback, optional camera/microphone sensor projects
- Power-capped (
max_power_w) and CPU-throttled (max_cpu_pct) to respect thermal/battery budgets GET /api/contributeendpoint — live status, stats, and hardware profile- Fleet dashboard integration: per-robot contribution stats, active project indicator, enable/disable toggle
- Privacy mode respected — contribute auto-pauses when
castor privacy onis active
Harness autoresearch live · editor UX overhaul · hardware-profile optimization
- Autoresearch pipeline live — Gemini 2.0 Flash generates harness candidates nightly; winner pushes directly to
main(no PRs). First champion:lower_cost(cost_gate_usd 0.05→0.01, score 0.9101) - Harness editor overhaul — smart type-aware block placement; zoom controls (+/−/fit); drag-to-connect edges; block info overlay (ℹ️); auto-connect on add; list↔flow graph sync
- Connector type picker — tap any edge midpoint to label it YES/NO/loop/error/timeout/data/fallback or delete it
- Capabilities screen fix — crash on gray screen resolved (safe Map→List cast); Cloud Function 403 resolved (firebase_uid ownership check)
- Hardware-profile harness optimization — roadmap: contribute fleet runs tier-specific evals; per-profile champions for Pi5+Hailo, Pi4, Waveshare, Unitree, server. Blog post
- castor provider CLI —
castor provider auth/list/statusfor gated model providers - Harness per-layer provider routing — specify
model: provider/nameper layer;get_provider_for_layer()resolves with fallback - PyPI v2026.3.20.4 published via OIDC Trusted Publisher; RCAN schema relaxed (40/40 configs pass)
RCAN v1.10 — Competition Protocol (types 37–40)
- RCAN v1.10 canonical MessageType table — 40 message types. Added COMPETITION_ENTER (37), COMPETITION_SCORE (38), SEASON_STANDING (39), PERSONAL_RESEARCH_RESULT (40).
- Competition protocol — robots can announce competition entry, publish verified scores, receive fleet-broadcast season standings, and log private personal research results.
- rcan-py v0.9.0 —
rcan/competition.py, 32 new tests, 663 total. SPEC_VERSION 1.10.0. - rcan-ts v0.9.0 —
src/competition.ts, 28 new tests, 499 total. SPEC_VERSION 1.10.0. - rcan-spec —
competitions.astrospec page with full protocol, payload schemas, and wire examples. - OpenCastor runtime accepts
rcan_version: "1.10" / "1.10.0"in robot configs.
RCAN v1.8 — Canonical MessageType & Idle Compute Contribution
- RCAN v1.8 canonical MessageType table — 36 message types with fixed integer assignments. Single source of truth across spec, rcan-py, and rcan-ts. Zero drift.
- castor contribute — donate idle NPU/GPU/CPU compute to distributed science. BOINC coordinator, NPU-optimized runner (Hailo-8L), fleet coordination, thermal throttling, P66 preemption.
- CLI:
castor contribute start/stop/status/history,castor peer-testwith transport comparison - API:
/api/contribute/start,/api/contribute/stop,/api/contribute/history - RCAN-MQTT transport wired into runtime —
rcan/{rrn}/in,rcan/{rrn}/out,rcan/estoptopics - Software attestation — pip RECORD hash check, config SHA256 baseline, git cleanliness; systemd service template
- Security fixes — RCAN-Signature bypass, None-principal scope skip, WebSocket JWT bypass, SSRF, LoA default hardening
- rcan-py v0.7.0 (609 tests), rcan-ts v0.7.0 (447 tests), opencastor-client v1.1.0+2
- Fleet contribution dashboard, history timeline, project selection UI in Flutter client
- Blog: "From Robot Runtime to Climate Sensor"
RCAN v1.6 — Federation, Constrained Transports, Multi-Modal, Identity LoA
- GAP-16: Registry Federation Protocol — FEDERATION_SYNC wire format, cross-registry JWT trust chains, 3-tier registry hierarchy (root/authoritative/community), DNSSEC trust anchor discovery
- GAP-17: Bandwidth-constrained transports — RCAN-Minimal (32-byte ESTOP for LoRa/BLE), RCAN-Compact (CBOR, <200 bytes ESTOP), BLE L2CAP framing
- GAP-18: Multi-modal payloads — media_chunks[] field, SHA-256 audit trail, streaming mode, TRAINING_DATA now requires media payload
- GAP-14: Human identity LoA 1/2/3 — FIDO2 binding, registry trust tiers, min_loa_for_control in P66 manifest
- All 22 original security/safety audit gaps addressed
- castor setup wizard: interactive onboarding with inline QR codes, castor bridge setup, castor fleet-link
- rcan-py v0.6.0 (587 tests), rcan-ts v0.6.0 (405 tests)
RCAN v1.5 — Production Safety Hardening (18 gaps addressed)
- GAP-03: Replay attack prevention — 30s sliding window seen-set, 10s for safety messages
- GAP-02: Robot identity revocation — ROBOT_REVOCATION broadcast, 1h TTL cache
- GAP-01: Command delegation chains — 4-hop max, Ed25519-signed, audit trail
- GAP-05: Consent wire protocol — CONSENT_REQUEST/GRANT/DENY on-wire format
- GAP-11: ESTOP QoS exactly-once delivery — retry until ACK, SafetyHaltError on timeout
- GAP-06: Offline operation mode — 300s grace, ESTOP always allowed
- GAP-10: Training data consent — EU AI Act Art.10, DataCategory enum
- GAP-08: Cloud relay identity audit — sender_type: cloud_function
- Protocol 66 conformance: 87% → 94%
- rcan-py v0.5.0 (430 tests), rcan-ts v0.5.0 (311 tests)
- Fixed castor doctor crash (#672)
- Migrated 18 hardware drivers to _move() for automatic SafetyLayer routing (#673)
- Fixed waveshare_alpha.rcan.yaml schema validation
- DriverBase.move() accepts dict and linear_x/angular_z kwargs (backward compat)
- 736 tests passing, 7 skipped
- SensorMonitor now wires to
SafetyLayer.estop()— thermal/electrical critical events halt motors - SO-ARM101
safety_bridge.py— all arm commands route through SafetyLayer (bounds, estop, rate limits, anti-subversion, full audit) - Per-scope RCAN §16.2 confidence gates: CONTROL=0.75, CONFIG=0.65, TRAINING=0.60, STATUS=0.0
- Session expiry → controlled stop for CONTROL-scoped principals (RCAN §6)
- Remote RCAN commands tagged
source=rcanin every audit log entry - 11 adversarial P66 invariant tests proving all 5 invariants hold
GET /api/safety/manifestendpoint — live conformance report- DriverBase SafetyLayer integration — hardware drivers opt in via
_move() hardware_safetyfield in rcan-config.json schema (physical_estop, SIL level, etc.)- 6 new conformance checker safety checks (P66 conformance %, local_safety_wins, watchdog, etc.)
- Fixed 13 BoundsStatus type errors, p66_manifest typing, pca9685 None guards
ws_telemetrycomplexity reduced from 26 to 3 (extracted_build_telemetry_payload)- rcan-py 0.4.1: safety message helpers (
make_estop/stop/resume,validate_safety_message)
- RCAN schema:
local_safety_winsis now a required field (RCAN §6 invariant) - All 5 RRF robot entries have
hardware_safetycapability declarations castor initgenerates complete safety block by default- rcan.dev/docs/safety — new safety conformance documentation page
CLAUDE.md: complete rewrite for RCAN v1.4 — MessageType 16/17, RRN URI format, TieredBrain routing, JS SDK §19/§21 examplesrcan_versionin all config examples updated to"1.4"- README updated for v1.4 spec alignment
- rcan-py: v0.3.1 → v0.4.0 (SPEC_VERSION 1.4)
- rcan-spec: v1.3 → v1.4 (§1–§16 dedicated section pages)
castor/rcan/registry.py:_validate_rrn()now accepts numericRRN-XXXXXXformat alongside URI format; type-check for non-string input raisesValueErrornotAttributeErrorcastor/rcan/registry.py:RegistryRegisterResult.from_message()enforcesrrnrequired on success,errorrequired on failurecastor/rcan/registry.py:RegistryResolveResult.from_message()enforcesrurirequired whenstatus="found"castor/rcan/registry.py:RegistryResolveResponse.to_message()emits correct wire typeREGISTRY_RESOLVE_RESULT(17), notREGISTRY_RESOLVE(14)castor/tiered_brain.py:sensor_pollfast-only guarantee enforced — interpretershould_escalatecan no longer override planner suppressioncastor/rcan/sdk_compat.py: handle rcan ≥ 0.3.0ValidationResultobject return fromvalidate_config()bob.rcan.yaml: addedrrn,rrn_uri,task_routingblock; updated to v2026.3.13.11
- 15 new validation tests in
tests/test_rcan_registry.pycovering Copilot-flagged validation paths; 105 total passing
castor/fleet/group_policy.py:FleetManager.from_confignow emitslogger.warningon malformed group entries instead of silently dropping them (#641)
tests/test_fleet_group_policy.py: 28 tests coveringGroupPolicy.matches,FleetManager,resolve_config, and_deep_merge(#640)
castor/providers/task_router.py: addopenrouterto all task categories in_DEFAULT_ROUTING— was unreachable (#639)tests/test_task_router.py: 3 new tests validating openrouter reachability, local-provider priority for SENSOR_POLL, cloud-fallback for REASONING
Task-Aware Model Routing
castor/providers/task_router.py: selects provider by task category (SENSOR_POLL, NAVIGATION, REASONING, CODE, SEARCH, VISION, SAFETY). SAFETY tier never downgrades. (#612)
OpenRouter Provider Test Coverage
tests/test_openrouter_provider.py: test_model_name_defaults_when_not_configured pins _DEFAULT_MODEL to anthropic/claude-3.5-sonnet; regressions caught by CI. (#637)
Ruff Import Cleanup
Unused imports removed and blank lines normalized across multiple test files.
OpenRouter Default Model Updated
castor/providers/openrouter_provider.py: _DEFAULT_MODEL updated from anthropic/claude-3.5-haiku to anthropic/claude-3.5-sonnet to align with the current ecosystem-standard model. (#635)
RCAN Dependency Constraint Tightened
pyproject.toml: rcan dependency constraint tightened from >=0.1.0 to >=0.3.0,<1.0. Aligns with minimum SDK version required for RCAN v1.3 §17/§19 features (INVOKE_CANCEL, Ed25519 signing). Applies to core deps and [rcan] extras group. (#634)
RCAN §21 MessageType Additions
castor/rcan/message.py: add REGISTRY_REGISTER_RESULT (wire value 16) and REGISTRY_RESOLVE_RESULT (wire value 17) to MessageType enum per RCAN spec §21. (#631)
SDK Compatibility Version Bump
castor/rcan/sdk_compat.py: minimum rcan-py version check bumped from >=0.2.0 to >=0.3.0. tests/test_compliance.py: fixture updated from "0.1.0" to "0.3.0". (#630 #632)
Deploy Workflow Self-Trigger Fix
.github/workflows/deploy-pages.yml: workflow file added to path filter so wrangler-action SHA bumps self-trigger a deploy. (#625)
Sitemap & robots.txt
site/sitemap.xml and site/robots.txt added; sitemap covers all 8 top-level pages with change-frequency and priority hints for search crawler discovery. (#627)
OG & Twitter Meta Tags
Open Graph and Twitter Card meta tags added to about.html, docs.html, changelog.html, hardware.html, beginners.html, and tutorials.html. Unblocks social link previews. (#626)
RCAN v1.3 Migration Chain
castor/migrate.py: implements full migration chain 1.0.0-alpha → 1.1 → 1.2 → 1.3; configs can now be fully upgraded to CURRENT_VERSION without hitting an empty path. (#619)
Config Template & Conformance Fixes
castor/setup_service.py default new config template now generates rcan_version: "1.3". castor/conformance.py fix-hint messages updated to reference v1.3. Hardware doc YAML examples (lerobot-kits.md, reachy.md) updated. (#620 #621)
INVOKE_CANCEL + ParallelSkillExecutor
InvokeCancelRequest dataclass for INVOKE_CANCEL wire messages (§19.4). InvokeResult.status adds "cancelled" variant. SkillRegistry.cancel(msg_id) with threading.Event tracking for best-effort in-flight cancellation. New ParallelSkillExecutor with fan-out and race semantics. (#609 #610 #616)
TestInvokeFamily Suite
9 tests covering INVOKE routing, INVOKE_CANCEL (found / not-found / missing-msg-id), no-registry error, INVOKE_RESULT type, and routed counter increment. (#611)
INVOKE_CANCEL MessageType + Timeout Enforcement
MessageType.INVOKE_CANCEL = 15 added to RCAN v1.3 §19 compliance. SkillRegistry.invoke() now executes in a ThreadPoolExecutor and enforces timeout_ms via future.result(timeout=...), returning status="timeout" immediately on deadline expiry. (#607 #608)
Concurrent + Timeout Invoke Tests
TestTimeoutEnforcement and TestConcurrentInvoke suites added to tests/test_rcan_invoke.py. (#605)
Episodic Memory + Rolling Compression
SQLite-backed episodic memory with recall and inject_context(). Shared-context ThreadContextBus. Rolling context compression for 24/7 continuous operation (configurable token budget, summary injection). (#613 #614 #615)
RCAN v1.3 Spec Alignment
SPEC_VERSION updated to "1.3". rcan_version references in CLI, registry, and conformance output updated. Generated config template bumped to "1.3.0". Health probe exceptions promoted to WARNING level. (#603 #606)
castor scan / doctor / upgrade / stop
castor scan CLI subcommand prints full hardware scan with --json, --refresh, --preset-only flags. castor doctor now warns on missing optional packages for detected devices (depthai, reachy2-sdk, etc.). castor upgrade does git pull + pip install + service restart in one command with --check and --venv PATH flags. castor stop reads ~/.opencastor/gateway.pid and sends SIGTERM for clean shutdown.
Gateway Hardening + Venv-Agnostic Systemd
Gateway writes a PID file to ~/.opencastor/gateway.pid and detects port-in-use on startup. Systemd service templates now use python -m castor.cli gateway and python -m streamlit run instead of binary paths — survives venv migrations. Services include KillMode=control-group, TimeoutStopSec=15, SendSIGKILL=yes, and ExecStartPre port cleanup. detect_hardware() gets a 30-second TTL cache with invalidate_hardware_cache().
Bug Fixes
scservo-sdk renamed to feetech-servo-sdk in [lerobot] extras — package now exists on PyPI. OAK-D SR (VID/PID 03e7:f63b) lsusb output now normalized to lowercase before model name lookup — no longer misdetected as bootloader/lite. LIBCAMERA_LOG_LEVELS=*:FATAL set at import time to suppress noisy libcamera stderr during scans.
Upgrade Guide
New docs/install/upgrade.md covering Pi OS PEP 668, --system-site-packages venv setup, systemd service migration, and troubleshooting common install errors.
Plug-and-Play Hardware Auto-Detection
castor scan now identifies 12+ hardware types by USB VID/PID, I2C address, PCIe, and mDNS network discovery: Intel RealSense D4xx/L515, Luxonis OAK-D family, ODrive v3/Pro/S1, VESC, Hailo-8 NPU, Google Coral USB/M.2, Arduino (official + CH340/FTDI clones), Adafruit CircuitPython, Dynamixel U2D2, RPLidar, Raspberry Pi AI Camera (IMX500), and Pollen Robotics Reachy. I2C address lookup for 10+ common sensors. USB descriptors memoized — lsusb called once per scan. Hot-plug support via invalidate_usb_descriptors_cache().
Feetech STS3215 Driver + LeRobot Profiles
New FeetechDriver for Feetech SCS/STS serial bus servos used in SO-ARM100/101 and LeRobot kits. port: auto detects the CH340 USB adapter automatically. Pre-built RCAN profiles: lerobot/so-arm101-follower, lerobot/so-arm101-leader, lerobot/so-arm101-bimanual, lerobot/koch-arm (Dynamixel XL430/XL330 via U2D2), lerobot/aloha (bimanual). Install: pip install opencastor[lerobot]. Fixes CH340 clone misrouting to Arduino Nano.
Pollen Robotics Reachy Driver
New ReachyDriver for Reachy 2 and Reachy Mini via reachy2-sdk (gRPC). host: auto uses concurrent mDNS hostname probes (reachy.local / reachy-mini.local) with no blocking getaddrinfo calls. Profiles: pollen/reachy2.yaml, pollen/reachy-mini.yaml. Install: pip install opencastor[reachy].
Bug Fixes
detect_feetech_usb() no longer misroutes Arduino Nano CH340 clones to LeRobot SO-ARM101 profile. _auto_detect_vesc_port() ODrive-USB fallback removed (prevented ODrive port being opened as VESC serial). print_scan_results() now includes all detected categories. suggest_preset() correctly distinguishes Reachy Mini from Reachy 2.
EmbeddingInterpreter — Local Semantic Memory
New EmbeddingInterpreter subsystem gives robots semantic memory via local CLIP embeddings (512-dim, no API key required). Three-tier backend: CLIP (free, default) → ImageBind (6-modality, experimental) → Gemini Embedding 2 (3072-dim MRL, premium). Episode store with RAG context injection into every brain tick. Configure with a single RCAN block under perception.embeddings. Zero config to start.
HLabs ACB v2.0 — BLDC Motor Controller Driver
First-class driver for HLaboratories' open-source Actuator Control Board. STM32G474 MCU, 12V–30V, 40A max, CAN Bus at 1Mbit/s. Auto-detects via USB VID/PID, runs full calibration sequences, streams 50Hz encoder telemetry to the dashboard. Pre-built profiles for single actuator, 3-DOF arm, and 6-DOF biped. Firmware flash via DFU. Install: pip install opencastor[hlabs]. RCAN protocol: hlabs_acb.
EpisodeStore FIFO Cap
Episode memory is now capped at 10,000 entries with automatic FIFO eviction. Prevents unbounded disk growth on long-running robots.
ApplyStage Deduplication
The SisyphusLoop ApplyStage now deduplicates patches before writing, preventing redundant writes in tight improvement cycles.
Timezone-Aware Datetimes
All timestamps in the episode store, usage tracker, and audit log are now timezone-aware UTC. Fixes comparison warnings with Python 3.12+.
Robot Face with Closed Captions
Dashboard robot face now renders live closed captions of the robot's speech output. Font size and display duration configurable via RCAN.
Gamepad Page
New /gamepad dashboard page for manual control via browser-connected gamepads. Maps standard buttons to move/stop/grip actions.
Brain Model Visibility
Active brain model name now shown in the dashboard status bar and in the /api/status response under brain.model.
Dashboard UX Improvements
Consolidated telemetry panel, faster chart rendering, improved mobile layout, and sticky header in the thought history view.
RCAN-Swarm Safety
New swarm safety layer enforces RCAN §16 AI Accountability across all swarm nodes. Commands carry model identity, confidence gates, and HITL authorization tokens. Nodes reject commands that fail the safety manifest.
castor node CLI
New castor node command group for managing individual swarm nodes: castor node status, castor node logs, castor node restart.
castor register --dry-run
castor register now accepts --dry-run to validate RCAN config and registration payload without actually registering the node. Useful in CI/CD pipelines.