Let a robot operate any appliance — pull a verified operation package and execute it safely.
Project description
OPERANDI SDK — let your robot operate any appliance
Your robot can walk, see, and grasp. It still can't operate the microwave, the washing machine, the oven, the coffee machine — because it doesn't know how. OPERANDI is that missing layer. This SDK is the module you drop into your robot's software to access appliances that were previously inaccessible.
from operandi_sdk import OperandiClient, execute
from my_robot import MyRobotAdapter # you implement ~6 primitive skills
client = OperandiClient("https://api.operandi.cc", api_key="ok_live_…")
match = client.identify("Bosch Series 6 dishwasher SMS6ZCI00G") # what your camera read
pkg = client.operate(match.slug, robot_profile="so101") # verified operation package
result = execute(pkg, robot=MyRobotAdapter()) # SDK runs it, safely
print(result.summary()) # COMPLETED · 7 steps · package=sim_validated
What you get vs what you implement
| OPERANDI provides | You implement |
|---|---|
| The knowledge: every control + its physical interaction | Actuation — your ~6 primitive skills |
Grounding — where: each control's OCR text_targets, region, shape primitive; localize() returns a bbox per control from a panel photo |
a camera + OCR (or your own detector) |
Grounding — did it work: each step's signal + expected reading expect; evaluate() decides pass/fail |
read_sensors() — raw readings (display text, door, lamps…) |
| The plan: ordered procedures as a behaviour tree | — |
| The safety envelope: force limits, never-do, interlocks | (the SDK attaches the force limit to every call) |
| Orchestration: sequencing, retries, safe abort | — |
The package no longer hands you prose like "pad labelled START" and "display shows
5:00" — it hands you the exact OCR string to find (text_targets: ["START"]) and
the machine-checkable expectation (signal: "display", expect: "5:00"). So your
adapter is small:
from operandi_sdk import RobotAdapter, SensorPerceptionMixin, SkillCall, Observation, localize
class MyRobotAdapter(SensorPerceptionMixin, RobotAdapter):
def execute_skill(self, call: SkillCall) -> bool:
# call.anchor carries: text_targets (OCR strings), region, primitive (shape), spatial
# call.force_limit: the safety cap, e.g. "<=8N" (respect it)
boxes = localize(self.camera.ocr(), [call.anchor]) # OCR-grounded bbox per control
pose = self.depth.pose(boxes.get(call.control_id)) # your 2D->3D (or use the detector)
return self.arm.actuate(call.skill, pose, max_force=call.force_limit, **call.params)
def read_sensors(self, predicate) -> Observation: # implement ONCE; verifies every step
return Observation(display_text=self.camera.read_display(),
door=self.camera.door_state(),
moving=self.camera.motion())
# the SDK evaluates predicate.expect against these — no per-appliance check code
Prefer full control? Implement observe(predicate_id, predicate) yourself instead of
the mixin, or override per-kind check_display_change / check_door_state (see
PerceptionMixin). The mixin is just the fast path.
Try it with no hardware
pip install -e .
python example.py # identify -> operate -> execute, against a fixture
python example_grounding.py # PROVES grounding: localize controls from a panel photo,
# then verify every step against (simulated) sensor readings
Safety contract
- Every actuation carries a
force_limitderived from the appliance's safety envelope — respect it (the manual's interlocks become your hard limits). - Verification is closed-loop: each step's success-signal is polled over its
timeout, and if it still doesn't appear the SDK re-actuates the step (a press
that didn't register → press again) up to
verify_retriestimes — implement the optionalon_verify_retry(call, predicate, attempt)hook to adapt between tries. If it ultimately can't verify (or a skill faults), the SDK aborts the whole procedure and callson_safety_abort()so you can e-stop / retract. - A package's
validation_tier(auto→sim_validated→robot_cleared) tells you how much trust it has earned. Gate hardware execution on your own policy.
Zero dependencies
Stdlib only — no requests, no heavy ML — so it fits constrained on-robot runtimes.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file operandi_sdk-0.1.0.tar.gz.
File metadata
- Download URL: operandi_sdk-0.1.0.tar.gz
- Upload date:
- Size: 43.8 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
44fddde58eaa7709311605dbfc2be8a995124c157a74be30d597b16c8e59b360
|
|
| MD5 |
bb1e5ac8f0b381b8288a42af5ba41911
|
|
| BLAKE2b-256 |
2e9f1c9964d43f854b9e9dcd85ca602ea789118c5ef9544ed1bb5c4228de55d0
|
File details
Details for the file operandi_sdk-0.1.0-py3-none-any.whl.
File metadata
- Download URL: operandi_sdk-0.1.0-py3-none-any.whl
- Upload date:
- Size: 28.6 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
d3144e1d34a09ab508a06d12d3470bc541fd4164067eea1b7f692c147d1f8d4a
|
|
| MD5 |
1b0889cd03f8ab9d37e9e52878e1d49a
|
|
| BLAKE2b-256 |
d302bc47f8a7334bc0c3ba9b4d65d9590a4dd92d46e79a128077cbf461882de3
|