Skip to content

Drive ~2 min read

Poses

A pose is where the arm rests, relative to its fold. strands-arm pose goto up tilts the head 30° from wherever autocal put home, walks there in the guard's ≤10° legs at 30°/s, and writes every leg to motion.log. Nothing here bypasses the guard.

Five built-ins

name what rel (servo deg from home)
home folded rest, torque off after all 0
attention head level, arm folded (home's angles, named so an agent can ask for it) all 0
look_around_left pan +40 5: +40
look_around_right pan −40 5: −40
up tilt +30 6: +30

Built-ins never touch the disk and cannot be deleted or overwritten. Whether up looks up or down on your head depends on the tilt servo's sign: try it once before an agent scripts it.

Save your own

strands-arm pose                         # the six angles now
strands-arm pose save peek --desc "head a hair right"
strands-arm pose list
strands-arm pose goto peek --i-know
strands-arm pose nudge 6 -5 --i-know     # one guarded step, at most 10 deg
strands-arm pose delete peek

save captures the current angles and stores two things in ~/.strands-arm/poses.json: deg (what the servos read) and rel (deg − the home of that moment). goto uses rel re-based on the current home, so a pose survives autocal moving home by a degree or two, and pan/tilt poses stay inside the head window the guard measures from the calibrated zero. deg is kept for you to read.

Refused, not clamped

A pose the guard would not accept — head outside its window, a joint outside its measured window, a target on the tick wrap — is refused before the first write, with the joint and the number in the message. GET /api/poses carries the same verdict as ok/why, and the dashboard greys the button with that reason. The step rule is not applied to the target: a body joint 40° away is walked in four legs; each leg re-reads the arm first (a hand may have moved it).

Who owns the bus

The dashboard owns the serial port when it runs. pose goto and nudge post to it (POST /api/control/pose, /api/control/joint) and the walk is a job: state.arm.job shows pose up, every other control answers 409 while it runs, and STOP (or /api/control/stop) aborts it mid-leg. Without a dashboard the tool opens the bus itself and drives a local Guard, so the same rules and the same log apply. seconds only slows a walk down, never speeds it past 30°/s.

The same tool is pose for an agent or an MCP client (strands-arm serve --mcp), and pose(action, name, …) inside the dashboard's chat. Motion needs the gate like everything else: i_know=true, STRANDS_ARM_I_KNOW=1, or ~/.strands-arm/bench.json with ok: true.