Skills & Market

Skills are reusable, named behaviors that run on any robot. They register with a decorator and are discovered via the ohho market CLI. A skill's tools are gated by the robot's capabilities — a skill that needs manipulation won't run on a robot without an arm.

Built-in skills

Skill Requires Description
patrol base.drive Drive a square patrol pattern
wave manipulation Wave the arm gripper
stop Emergency stop the robot
status Print telemetry and connection status

List and run skills

ohho market list
# patrol          v0.1.0  [base.drive]   tags: navigation, demo
#   Drive a square patrol pattern. Args: side (m), speed (m/s).
# wave            v0.1.0  [manipulation]  tags: arm, demo
#   Wave the arm gripper. Args: reps (count).
# stop            v0.1.0  []              tags: safety
#   Emergency stop the robot.
# status          v0.1.0  []              tags: diagnostics
#   Print the robot's telemetry and connection status.

ohho market run omnibot patrol
# skill 'patrol': patrol complete

ohho market run omnibot wave
# skill 'wave': waved 3 times

Use skills in Python

from ohho.market import run_skill, list_skills, get_skill

# List all registered skills
for s in list_skills():
    print(f"{s.name}: {s.description}")

# Run a skill
result = run_skill("patrol", bot, side=2.0, speed=0.15)

# Check if a skill can run on a robot
skill = get_skill("wave")
if skill.can_run(bot):
    skill.run(bot, reps=5)

Write your own skill

Use the @skill decorator to register a reusable behavior:

from ohho.market import skill

@skill("dance", "Make the robot dance in a circle", requires=["base.drive"])
def dance(robot, speed=0.2, turns=4):
    import time
    for _ in range(turns):
        robot.drive(vx=speed, w=0.8)
        time.sleep(3.14)
    robot.stop()
    return f"danced {turns} turns at {speed} m/s"

Then use it:

ohho market list          # "dance" now appears
ohho market run omnibot dance

Or in Python:

from ohho.market import run_skill
run_skill("dance", bot, speed=0.3, turns=2)

Capability gating

Skills declare which capabilities they requires. When you run a skill on a robot that lacks those capabilities, you get a clear error:

from ohho.market import run_skill, SkillRequirementsNotMet

try:
    run_skill("wave", dog)  # Go2 has no manipulation
except SkillRequirementsNotMet as e:
    print(e)
    # skill 'wave' requires capabilities: ['manipulation'].
    # Robot 'unitree-go2' has: ['base.drive', 'base.holonomic_drive', ...]

The Skill dataclass

from ohho.market import Skill, register_skill

custom = Skill(
    name="inspect",
    description="Drive forward and report obstacles",
    handler=lambda robot: robot.drive(vx=0.1),
    requires=["base.drive"],
    author="your-name",
    version="1.0.0",
    tags=["inspection", "safety"],
)
register_skill(custom)

Next