Repository navigation
strands-robots v0.5.3
Release date: 2026-10-05 Previous release: v0.5.2 (2026-09-17)
621 pull requests in eighteen days - the robots this library can drive doubled, and where a
fleet can live did too. A robot anywhere on the internet is oneMesh.sendaway over AWS IoT
Core Direct Messaging; an Isaac Lab run trains on thousands of GPU worlds, exports, and
walks on MuJoCo throughcreate_policy("rl"); mjlab steps 4,096 MuJoCo worlds in one Warp
launch; the native drivers are the hardware default and nine more robots have one; the
registry grows 75 → 157 with every robot_descriptions URDF; holosoma, wbc_latent and
π0.5-DROID join the policy providers; any robot streams to Foxglove. 431 fixes keep the
theme of the last release: refuse, don't guess.groot(the hand-rolled provider),
lerobot_asyncand the Dynamixel driver stub leave.
strands-robots is the robot-control library for Strands Agents:
one Robot object for a simulated or physical arm, humanoid, quadruped or mobile base; policy
inference, teleoperation, recording, training and fleets behind one agent-callable tool surface;
and a real robot that does not move until an operator says yes.
Highlights
-
AWS IoT Core direct messaging, and a fleet that is not on your LAN. On the
iotand
bridgemesh backendsMesh.senddelivers a command to the one connected client it names as an
AWS IoT Core direct message
(QoS 1, the robot's PUBACK is the confirmation) and the robot answers on theresponseTopicit
was handed, after checking it is exactlystrands/<sender>/response(#4242). Provisioning
generates the private key on the robot and has AWS sign a CSR (CN=<thing>); the key never
leaves the machine (#4242). A robot certificate obeys fleet stops and cannot originate
one unless designated (allow_estop_publish, #4317); a retained safety message is never read as a
live stop (#4326); a peer re-subscribes after every reconnect, so a robot that dropped its MQTT
session no longer goes deaf to the fleet e-stop - measured 0/3 stops heard before the fix, 3/3
after (#4370); child peers get their own policy (strands-robot-children) so a sim robot on
iotno longer lives in a 150 ms connect/disconnect loop (#4346); operators receive their direct
replies (first reply 450 ms, 226 ms steady, #4371); the pureiotbackend starts without the
permissive-ACL opt-in the docs forbid (#4351); e-stop and resume cross the bridge to the MQTT
leg (#4098, #3965). The dashboard shows a robot reached over IoT as a full card next to the
LAN peers - joints, cameras (S3 reference resolved server side, presigned URL never reaches the
browser), safety state, run/stop/reset through the same gates (#4348).from strands_robots.mesh import init_mesh # STRANDS_MESH_BACKEND=iot on both ends mesh = init_mesh(robot, peer_id="operator-1", peer_type="operator") mesh.send("so101-arm-01", {"action": "status"}) # one direct message -> one client -> PUBACK
Left: pub/sub fan-out vs one direct message (the docs' own drawing, #4242). Right: IoT-reached
robots (IOT chip) beside a LAN sim peer on the Fleet tab (#4348).
-
Isaac Lab: train on thousands of worlds, export, deploy on MuJoCo, record a dataset.
create_trainer("isaaclab")/train_policy(provider="isaaclab")launchespython -m isaaclab trainin the interpreterISAACLAB_PYTHONnames - Isaac Lab is never imported and adds no
dependency - and answersstatus(job_id)from the run's log: latest iteration, first/latest/
best reward,steps_per_s, the rsl_rl run directory (#4227 / fragment 866). The run can be
played back on video and exported (#4287); export records the deploy contract - joint
order,offset + scale * action, the run's PD gains - so a published Go2 rough-terrain policy
no longer commands joints 1.73 rad from where Isaac Lab would (#4402, #4453);create_policy("rl")
builds the observation from a strands robot's state and runs the run's PD on MuJoCo torque
motors (#4402), and loads an rsl_rl run directory, onemodel_<n>.ptor a Hub repo id (#4440).
rl_library="skrl"(AMP humanoids, MAPPO/IPPO, #4436) and"rl_games"(Factory, Forge,
AutoMate, #4436) train beside rsl_rl; an operator's own task packages register through
$STRANDS_ISAACLAB_TASK_PACKAGES(#4410);train_policy(action="record")rolls the newest
checkpoint out in parallel environments and writes a LeRobotDataset (#4437); a job stops at its
timeout_swith nobody polling (#4436); CNN and recurrent actors are refused at export instead
of shipped without their encoder (#4373). Every RL trainer now leaves a curve,metrics.jsonl
(#4427).train_policy(action="train", provider="isaaclab", steps=1500, output_dir="runs", extra={"task": "Isaac-Velocity-Flat-G1", "num_envs": 4096}) # -> job_id train_policy(action="export", provider="isaaclab", job_id=JOB_ID, output_dir="g1_flat") Robot("unitree_g1").run_policy(policy_provider="rl", policy_config={"checkpoint_dir": "g1_flat"}, duration=10)
Go2 rough-terrain training in Isaac Lab (4 of the worlds, #4227) · the exported actor standing
on strands' MuJoCo Go2 through create_policy("rl") (#4402).
-
Isaac Sim is an AgentTool, and a 41-PR parity pass.
Agent(tools=[Robot("so101", backend="isaac")])works:IsaacSimulationpublishes the shared simulation schema narrowed to
the 43 of 77 actions it implements, andrun_agentdrives an agent on it (#4361).IsaacConfig
forwards Kit settings, caps Kit's task threads and bounds a hung start-up - 3 of 6 processes on
one 32-core host were still booting after 240 s before (#4379). Then the user-visible fixes:
cameras show the state the simulation is in and a recorded episode no longer opens on a black
frame (#4409, #4358, #4353);render()returns the size it was asked (#4288); the Panda gripper
works (#4341); MJCF robots spawn where asked, as fixed-base arms, without a second floor
(#4359), keep their servo gains and joint names (#4271, #4272), and an MJCF motor is driven as a
torque (#4345);replicategives every environment its own grid cell (#4292);reset()leaves
the scene at rest with the clock at zero (#4350);apply_forcespins the right way (#4421);
aerial robots fly (#4420); a robot that converts to several articulations loads every arm
(#4382); the sim clock tracks physics (#4110);remove_robotdeletes the prim (#4111); a floor
renders clean instead of streak noise (#4424); Isaac Sim 6.1 robots load with their physics
(#4268). The earlier Isaac audit closed 38 findings in one PR (#3343). -
Native drivers are the default, and nine more robots have one.
Robot(name, mode="real")
with nodriver=builds the native driver registered for the robot and falls back to lerobot
only where this package has none; a registryhardware.driverdeclaration anddriver="lerobot"
still pin that path. An SO-101 on a fresh install connects without the[lerobot]extra and
reads the calibration lerobot already wrote (#4460). New drivers: Boston Dynamics Spot
overbosdyn-client(#4500), KUKA LBR iiwa 14 over FRI (#4525), Kinova Gen3 over
kortex_api(#4519), UFactory xArm 7 (#4478), Hello Robot Stretch 3 overstretch_body
(#4480), Rainbow RB-Y1 overrby1-sdk(#4479), Unitree H1, H1-2 and B2 on the
Go2/G1 wires (#4502, #4510, #4531), Yahboom ROSMASTER M3 Pro over its ROS 2 graph (#3941),
and a real Dynamixel bus soRobot("koch", driver="strands")reads, moves and runs a policy
(#4122).URDriverserves every e-Series and UR-Series arm at each model's own joint speeds
(#4513). The Feetech SO arms run a policy on the loop the UR already had (#3963), take a leader
arm throughattach_teleop(#4279), and drive their MuJoCo twins over the same bus (#3944).
Reachy Mini and Microduck expose their whole operator vocabulary on the native driver (#3867,
#3872). Robots a native driver builds: 25 → 40 (list_native_drivers()).arm = Robot("so101", mode="real", port="/dev/ttyACM0") # FeetechDriver, no lerobot needed spot = Robot("spot", mode="real", port="192.168.80.3") # SpotDriver over bosdyn-client
The UR family in MuJoCo, one driver (#4513).
- mjlab: GPU-vectorized MuJoCo (MuJoCo-Warp) as a first-party backend (
[sim-mjlab], #4229).
create_simulation("mjlab", num_envs=N)compiles the MuJoCo backend's MJCF once and steps N
worlds in one Warp launch; world 0 speaks the single-world contract, soRobot("so101", backend="mjlab")behaves likemujoco, andget_observation_batch/send_action_batch/
randomize(seed=)move(N, …)tensors on the GPU.train_policy(provider="rsl_rl")runs
mjlab's PPO in-process and exports ONNX with a dynamic batch axis;rsl_rl_onnxloads it on
mujoco,mjlabor hardware. Parity: so101 joints agree with the MuJoCo backend to 8e-5 rad
over 2 s (#4229). Measured for these notes on one L40S, so101,torch.cuda.synchronize()before
the clock stops: 3,520 env-steps/s at N=1 → 9.0 M at N=4096.
- Registry 75 → 157: every robot_descriptions URDF loads in MuJoCo (#4211,
[sim-urdf]).
strands_robots.assets.urdfcompiles a URDF on first use into a Menagerie-shaped asset: mesh
URIs resolved, Collada converted, the inertials and zero-size geoms MuJoCo refuses repaired, one
position actuator per joint sized from the URDF effort, a free joint for floating bases, the root
lifted onto the floor. 23 xacro-only descriptions render through xacrodoc.list_robots()
reports them withsource: "urdf". 79 of the 80 build -eve_r3is listed with the reason its
upstream repository no longer exists - and this is all 79, rendered from this release:
Robot(name, mode="sim").render() for each of the 79, headless EGL on an L40S.
- Policies: holosoma, wbc_latent, π0.5-DROID, FLUX 3 Action.
create_policy("holosoma")
runs Amazon FAR's released G1 locomotion checkpoints (fastsacdefault orppo) in process with
ONNX Runtime - the 100-wide observation, the two-foot gait clock at 50 Hz, PD gains read from the
checkpoint's own metadata; weights come from the Hub mirror at a pinned commit, sha256-checked,
nothing bundled (#4249,[holosoma]).wbc_latentdecodes a VLA's 64 SONIC motion tokens into
29 G1 joint targets, the recipe of "Bringing Humanoids to LeRobot" (#4251). An embodiment can
speak DROID - joint-velocity actions integrated ataction_dtand a gripper fraction - so
lerobot/pi05_droidruns onpanda_droidwithout an adapter (#4428).flux3_actionwraps
Black Forest Labs' FLUX 3 Action with its SO-101 checkpoint, owning the unit frame between the
model and the robot (#4199).lerobot_localkeeps a pi0 / pi0.5 checkpoint's own processor
pipeline, runs on the GPU, normalizes with supplied stats, and refuses an unknownembodiment=
before any download (#4404, #4403, #4406, #4366).
Unitree G1 under holosoma fastsac_g1_29dof.onnx at 0.5 m/s: 3.1 m in 8 s, pelvis at
0.79 m, no NaN (rendered on an L40S for these notes; mp4).
- Foxglove live view and MCAP export for any robot (
[foxglove], #4277).Robot(name, foxglove=True)serves a sim or real robot overfoxglove.sdk.v1:/tfand the robot's own
MuJoCo meshes for the 3D panel (no URDF), joint states, JPEG cameras, log and event channels.
foxglove_mcap=pathrecords the same channels;export_episodeturns one LeRobot v3 episode
into a seekable MCAP;mcap_inforeads any MCAP back. A stopped bridge has released its port
whenshutdown()returns (#4461).
- The dashboard is the fleet on the mesh, on a phone too. The agent console drives mesh peers
only - in-process sim tools are gone (#4338) - and knows which policies each robot on the mesh
can run (#4342); every card has a Reset button through the same gate as run and stop
(#4344); a 3D twin drawn from the compiled model follows a real arm, reading the bus and never
writing it (#3739, #3892); the Agent tab puts a consent card before anything that moves (#3879);
the whole operator workflow - live fleet, devices, record, train, calibrate, voice - is wired
(#4102), the voice console runs onstrands.bidi(#4456), and the layout works on a phone and a
tablet (#4459). It wears the docs' design tokens (#4218) and a Hub checkpoint type-ahead that
knows the robot (#4226).
Fleet tab from this release: two sim SO-101s, Reset just pressed on the left card, the IoT
registry line below; the same page at 390 px.
Also new
- Mesh. A peer advertises the tool it serves and
callinvokes it;sim_callcarries the
whole simulation tool over the mesh andset_jointsis a simulation-only action (#4255, #4220);
a second command inside 50 ms is answered, not dropped, and camera frames keep their colours
(#4255). A mesh command that moves real hardware passes the operator gate on the robot host
(#4313); a motion grant is bound to the calibration it was approved under and expires with its
peer (#4320, #4325); a command key the peer does not read is refused (#4397); a peer's refusal
crosses the wire with its code and grant (#4380); the embodiment travels with a wire policy
command so a degrees-trained checkpoint is not applied in radians (#4368); a remote resume
clears the whole fleet (#4364); an early e-stop still stops (#4377); replies are attributed to
the Zenoh session that sent them (#4303).robot_meshhands the agent the peer's whole reply
(#4375) and its headless refusal names what pre-approves the call (#4386). - Simulation.
SimEngine.capabilities()names what a backend supports (#4177) and
actuator_ranges()what it can command (#4096);ManipulationOptionalfor backends without
manipulation (#4270);register_robotregisters a robot with no asset (#4232); a rollout that
stalls against contact says so insaturated_step_rate(#4472); a diverged MuJoCo world is
reported, not stepped through as a success (#4399);move_tosays when what the fingers held
was left behind (#4400); a teleoperated MuJoCo session keeps sim time and records a demonstration
(#4446); Newton poses a robot withset_joint_positionsand draws its floor (#4429). - Registry.
yahboom_m3pro(sim + real, #3927, #3941),mujoco_humanoid, andgen3,
iiwa14,iiwa,tiago,tiago_ppresolve by name (#4202);lekiwi_simembodiment drives
the simulated LeKiwi (#4491);lekiwiandspotare mobile manipulators (#4395); the robot
catalog publishes the driver coverage join, generated at build (#4071). - Training.
base_modelis a Hub reference or a checkpoint inside a known home (#4310); a
Hub dataset push is private unless you ask for public (#4521);create_trainer()names the
closest trainer for a near miss (#4497). - Whole-body teleoperation seam and driver composition, designed and proved in simulation
(#4253); a humanoid's G1 verbs are consolidated - oneg1_sensor, oneg1_task, four reference
lookups (#3999, #4007, #4011). - Typo-tolerant refusals.
create_policy,add_object,add_robot, keyframes, cameras,
predicates, episode labels andRobot(**kwargs)now answer a near miss with "did you mean"
(#4252, #4405, #4499, #4528, #4524, #4530, #4495, #4509, #4484, #4533, #4536). - Packaging.
strands_robots.__version__reports the installed version (#4244); the package
shipspy.typed(#4175); the test suite runs distributed and a PR's required check with it
(#3992);[dev]gainspytest-xdist.
Breaking changes
- Removed: the hand-rolled
grootpolicy provider, its ZMQ toolgr00t_inference, the
Isaac-GR00T trainer and thegroot-serviceextra - about 6,600 lines of source; GR00T N1.7 is
lerobot 0.6's nativegrootpolicy type behind the new[groot]extra, and a GPU box runs
PolicyServerfor theremoteprovider (#4256). Thelerobot_asyncprovider and
[lerobot-async]extra - lerobot shipspolicy_server/robot_clientitself (#4091). The
Dynamixel driver stub, sodriver="strands"refuses a Dynamixel robot it cannot move instead
of building one that cannot read or move a joint;kochnow has a real native bus (#4097,
#4122),aloha/vx300s/wx250s/trossen_wxai/dynamixel_2rgo through lerobot. - The native driver is the hardware default (#4460).
Robot(name, mode="real")without
driver=builds the strands driver where one exists. Pindriver="lerobot"to keep the old
path;earthroverkeeps lerobot by registry declaration. - The dashboard agent console drives mesh peers only; the in-process sim tools, the Sim tab's
direct sessions and their routes are gone (#4338). Spawn a sim peer instead. - Moved:
resolve_dataset_dir,local_dataset_dir,load_lerobot_episode→
strands_robots.dataset_source(#3908);sync_dataset_to_bucket→
strands_robots.dataset_transfer(#3916); the ROS 2 mobile basesstrands_robots.mesh→
strands_robots.drivers.ros(#4140); the Reachy daemon link →drivers.reachy_transport
(#4117); loop pacing →strands_robots._pacing(#4114);BUCKET_STREAMING_MIN_LEROBOT→
strands_robots.utils. - Deprecated, with a warning now:
curobo,moveit2,kimodo,protomotionsand in-process
GR00T are removed in 0.7 (#4123); Device Connect (Robot(...).run(),strands_robots.device_connect,
robot_mesh'srpcaction,[device-connect]) is removed in 0.7 (#4132); a driver's
start_task(policy_provider=)is removed in 0.8 - build the policy and passpolicy_object=
(#4127). - Floors:
strands-agents>=1.57.2(the dashboard voice console drivesstrands.bidi),
Pillow>=12.3.0,websockets>=17.1,boto3/botocore>=1.43.17;uvicorn[standard];
[dashboard]now pullspyserial,opencv-python-headless,huggingface_hub.[voice]
conflicts with[mesh-iot]/[all],[sim-mjlab]with[inference]/[cosmos3-service]/[all]
(declared intool.uv.conflicts; see Upgrade). IsaacSimulationrefusesreset(env_ids=...)it cannot perform, a joint write outside the
joint's range, and a scene PhysX's tensor view no longer covers (#3343, #4343);send_action
refuses a batch with an unknown key whole, before anything moves (#4486);Robot(mode="sim")
refuses every hardware keyword (#4485); a pre-builtpolicy_objectbesidepolicy_provideris
refused (#4523).
New robots, drivers and policies
Registry 75 → 157 (list_robots()): +80 robot_descriptions URDF robots (#4211, 79 build),
yahboom_m3pro (#3927), mujoco_humanoid (#4202), lekiwi_sim (#4491). Categories now: arm 63 ·
humanoid 37 · mobile 18 · mobile_manip 16 · hand 11 · bimanual 9 · aerial 2 · expressive 1;
145 with a simulation asset.
Native drivers (strands_robots.drivers): 25 → 40 robots. New: spot (#4500) · kuka_iiwa
(#4525) · kinova_gen3 (#4519) · xarm7 (#4478) · stretch, stretch3 (#4480) · rby1 (#4479)
· unitree_h1, unitree_h1_2, b2 (#4502, #4510, #4531) · yahboom_m3pro (#3941) · koch on a
real Dynamixel bus (#4122) · ur3e ur7e ur8long ur12e ur15 ur16e ur18 ur20 ur30 beside ur5e/
ur10e (#4513). Gone: the Dynamixel stub's five (#4097). list_driver_coverage() is generated
into the docs catalog (#4071).
Policy providers (16; +4 −2):
| Provider | Extra | What |
|---|---|---|
holosoma |
[holosoma] |
Amazon FAR G1 locomotion, fastsac/ppo ONNX, weights from the Hub mirror (#4249) |
wbc_latent |
[wbc] |
SONIC motion tokens from a VLA → 29 G1 joint targets (#4251) |
rsl_rl_onnx |
[sim-mjlab] / core onnxruntime |
an rsl_rl actor exported from mjlab, on mujoco, mjlab or hardware (#4229) |
flux3_action (f3a) |
[flux3] (empty; installs from GitHub) |
Black Forest Labs FLUX 3 Action, SO-101 checkpoint (#4199) |
Removed groot (#4256), lerobot_async (#4091). rl loads rsl_rl runs and Hub ids (#4440);
lerobot_local gains the groot policy type through [groot] (#4256), the raw pi0/pi05 path
(#4203), panda_droid velocity actions (#4428).
Simulation backends: mjlab joins mujoco, newton, isaac (#4229); the Isaac backend is
an AgentTool (#4361) and imports MJCF (#3343).
Trainers: isaaclab (rsl_rl / skrl / rl_games) (#4227, #4436), rsl_rl on mjlab
(#4229); metrics.jsonl on every RL trainer (#4427).
Security
- The lockfile clears 47 of the 49 open Dependabot advisories (#4093) and the last torch /
transformers / setuptools three (#4185);urllib3>=2.8.0closes GHSA-8988-9cw3-xx77,
GHSA-vxq7-64xx-v4gw and GHSA-gh4c-6fx4-qh6g (#4447);Pillow>=12.3.0clears eleven HIGH
advisories (core floor). - CodeQL scans the package, not the test suites (#4135), and every alert it raised under
dashboard(23 + 8 frontend advisories, #4136, #4208),mesh(29, #4137),simulation(#4139),
dataset_recorder/assets/registry/policies(#4138, #4184) is closed. - Dashboard session and origin. The passkey session lives only in the
HttpOnlycookie and
every response carries a Content-Security-Policy (#4308); a?token=in the URL is redeemed
against the backend, never believed (#4302), and a?backend=never carries the token to a new
host (#4297); a WebSocket handshake is admitted by its Origin before any credential is read
(#4311); removing a passkey ends its sessions (#4309); a settings write cannot plant the standing
bearer (#4301); a fresh install's open posture needs the bootstrap proof (#4298); the env view
masks by allowlist (#4307); thumbnails live in a private directory and the route never follows a
link (#4306); a dashboard-spawned real arm never starts without wire auth (#4312). - Mesh. An ACL subject bound to
interfaces: ["*"]reads as wide open (#3964); an ACL glob over
the command or safety plane reads as permissive to the refuse-to-start gate (#4327); a retained
command is refused, not executed at every boot (#4374); the resume proof is no longer an offline
oracle for the override code (#4321); a peer id is a command target only if it passes the
inbound charset rule (#4324); a mesh RPC reply is attributed to the session that sent it (#4303). - IoT. Robot certificates obey fleet stops and originate none unless designated (#4317);
the private key is generated on the robot and never leaves it (#4242); child peers have their
own policy (#4346).
Dependency floors
| Dependency | v0.5.2 | v0.5.3 | Reason |
|---|---|---|---|
strands-agents |
>=1.13.0,<2 |
>=1.57.2,<2 |
strands.bidi (dashboard voice console, #4456) |
Pillow |
>=8.0.0,<13 |
>=12.3.0,<13 |
eleven HIGH advisories cleared at 12.3.0 |
websockets ([inference], [cosmos3-service]) |
>=17.0 |
>=17.1 |
legacy=True on sync.client.connect (#4205) |
boto3 / botocore |
>=1.34.0,<2 |
>=1.43.17,<2 |
IoT Direct Messaging API (#4242) |
uvicorn ([dashboard]) |
>=0.27,<1 |
uvicorn[standard]>=0.27,<1 |
WebSocket speedups |
| new extras | - | [sim-mjlab] mjlab >=1.6,<2, mujoco/mujoco-warp >=3.11,<3.12, warp-lang >=1.14 · [sim-urdf] trimesh >=4,<6, pycollada, xacrodoc · [foxglove] foxglove-sdk >=0.25.1,<0.28, mcap >=1.5 · [holosoma] onnxruntime, huggingface_hub >=1.5 · [groot] lerobot[groot] · [voice] strands-agents[bidi] · [spot] bosdyn-client >=5,<6 · [rby1] rby1-sdk >=0.10,<0.11 · [xarm] xarm-python-sdk >=1.18,<2 · [flux3] (empty) |
#4229, #4211, #4277, #4249, #4256, #4456, #4500, #4479, #4478, #4199 |
[dashboard] adds |
- | pyserial>=3.5, opencv-python-headless>=4.8, huggingface_hub>=1.5 |
devices tab, cameras, Hub search (#4426) |
[dev] adds |
- | pytest-xdist>=3,<4 |
distributed suite (#3992) |
| removed extras | groot-service (pyzmq, msgpack), lerobot-async |
- | #4256, #4091 |
constraint floors (tool.uv.constraint-dependencies) |
- | urllib3>=2.8.0, cryptography>=50, aiohttp>=3.14.3, mcp>=1.28.1, setuptools>=83, torch>=2.13, transformers>=5.10, torchvision>=0.28, torchcodec>=0.13, anyio>=4.14.2, gitpython>=3.1.59, autobahn>=26.7.1 |
Dependabot relock (#4093, #4185, #4447) |
| build | hatchling |
hatchling<1.32 |
1.32 emits Metadata-Version 2.5, which the PyPI publisher's twine rejected on the v0.5.2 publish |
requires-python stays >=3.12. [sim-mjlab] stays out of [all] (mjlab needs torch>=2.14,
[lerobot] caps torch<2.12) and conflicts with [inference]/[cosmos3-service] (mjlab's viser
pins websockets<17); [voice] conflicts with [mesh-iot] and [all].
Fixed
431 Fixed fragments in changelog.d/ (381 fix: PRs). The theme holds - refuse, don't
guess - and this release adds its corollary: when the library refuses, it names the spelling you
meant. The user-visible ones:
- Isaac. Cameras show the state the simulation is in, a recorded episode is the rollout that
ran and no episode opens on a black frame (#4409, #4358, #4353);render()honours its size
(#4288); the Panda gripper works (#4341); MJCF robots spawn where asked without a second floor,
keep gains, joint names and damping, and their motors are torques (#4359, #4271, #4272, #4345);
replicatebuilds the fleet it reports, one grid cell each (#3343, #4292);reset()leaves the
scene at rest,reset(env_ids=)is refused rather than resetting everything (#4350, #3343);
afterremove_robot/remove_objectcalls say "reset() first" instead of crashing (#4290,
#4281); joint writes outside range are refused and success stops once physics diverged (#4343);
apply_forcespins the right way (#4421); cameras see objects closer than 1 m, mount on a link
withparent_body, and warm up without logging errors (#4222, #4407, #4237);fovis vertical
like MuJoCo (#4113); the floor is clean (#4424); aerial robots fly and multi-articulation robots
load every arm (#4420, #4382);is_available()needs no torch,cuda:0is not claimed while
PhysX solves on the CPU, a failedcreate_worldleaves no live World, a NaN delta-EEF never
reaches PhysX (#3343); the unit suite never boots Kit (#4241); the sim-isaac extra installs the
IK stack (#4245); two concurrent MJCF conversions get their own staging (#3973); headless render
says its frames are blank and a refused recording names the reason (#4274, #4276). - Isaac Lab / RL. Export records the deploy contract or refuses (#4402, #4453, #4373); jobs
stop attimeout_s, a relative jobs dir works, export takes the asked-for task (#4436); every
TrainSpec field is forwarded or refused (#4436); a run says why it failed and whether it solved
its task (#4287);rlpolicies no longer truncate an observation (#4373); FastSAC/FastTD3/PPO
keep a curve (#4427). - Policies / inference.
lerobot_local: pi0/pi0.5 keep their processor pipeline, run on the
GPU withtorch.compileoff unless asked, normalize with supplied stats, and pi0-FAST loads with
its own (#4404, #4403, #4406); the raw obs/action path for pi0/pi05 (#4203); a one-camera robot
reaches a one-view checkpoint and a mixed observation routes the camera (#4065, #3920); an unknown
embodiment=is refused before any download, a wider action head drives underdim_policywith
the width judged first, actions far outside the checkpoint's range are flagged, a degree-trained
SO-arm checkpoint no longer drives a sim arm into its limits, andstate_units/action_units
are refused as constructor keywords naming where they go (#4366, #4376, #4439, #4372);
unit frames an embodiment cannot convert are refused and a child inherits its parent's (#3937,
#3949, #3934, #3981).cosmos3declares the chunk it serves, binds joint state from the
observation, refuses before dialling a configuration no actuator would receive, and survives a
dead socket (#4383, #3898, #4385, #4197).wbcrefuses a wrong-family checkpoint where it is
opened, a SONIC stack before downloading it, builds from a Hub id, andwbc_gaitnames the
gait-clock weights it needs (#3888, #4355, #4369, #4260).remotereports an unusable remote
instead of raising past its envelope and refuses a listening port that does not speak WebSocket
(#4492, #3917). A provider's constructor verdict is astatus=errorenvelope on every rollout
surface (#4362), therun_policytool judges the policy before it wipesdataset_root(#4360),
a multi-episode run resets the policy every episode (#4199), a chunk policy without RTC runs
synchronously by default (#4408),run_multi_policysteps one control period (#4398), and every
"does not read the instruction" note describes your policy, not the mock (#3912, #3932, #3940,
#4223). Planners plan from the robot's own observation (#3876, #3885); cuRobo refuses a pose goal
beside a joint goal (#3901). - Drivers / hardware. Every hardware rollout entry point runs one preflight before it builds
the policy (#4108, #3967, #3972); a stop pressed betweenstart_taskand the rollout is honoured
(#4104); a serial arm with no usable port is refused at construction on both drivers (#4258); a
native driver refuses a keyword it never read (#3957);statusanswers one envelope on every
driver (#4230); the real-arm tool refuses an input outside its schema and takespolicy_config
(#4389, #4141); a Go2 partial action enables the joints it omits (#3887); an H1 refusal names the
H1's mode (#4505); Feetech torque sweeps pairLockwithTorque_Enable,Present_Position
carries its sign on the pose tool, and degree scale comes from the arm's calibration (#3858,
#3863, #3868); the Crazyflie receives telemetry after connect (#3427); EarthRover's default SDK
port and timedmove(#3828, #3857); a Wireless Reachy Mini connects (#3852); a motion grant is
bound to the calibration the operator approved it under (#4320); a lerobot arm's connect from
the dashboard no longer fails "Port is in use!" and the spawn actually connects (#4457); the
Unitree SDK refusal installs the DDS binding (#3844); a real arm's render saves the colour the
camera saw (#3830). - Mesh / IoT. See Highlights for #4326 #4346 #4351 #4370 #4371 #4317 #4098 #3965. Also: a mesh
command key the peer does not read is refused (#4397); a stop acknowledged by a locked peer does
not paint its card clear (#4328); a safety envelope with a non-finitetdoes not break the
fleet view (#4330); a connect-only peer joins under the default mTLS posture and the shipped ACL
templates let operator and robot discover each other (#4462, #4463);Robot(mesh=True)without
[mesh]names the dependency (#4239);robot_meshrefuses an unknown action before it touches
the mesh (#3874); the dashboard files a sample under the peer that published it (#4304), reports
the camera rate the mesh publishes (#3205), and no wire knob is writable from its env editor
(#4305);doctorlists all sixteen probes including IoT Direct and does not fail it for a
running operator (#4296, #4352); a Git LFS pointer is not a mesh and LFS meshes download without
git-lfs (#3984, #4422). - Simulation (MuJoCo / Newton). A diverged world is reported (#4399);
move_tosays when the
grasp was left behind and no longer spends the solve on a slide/hinge base (#4400, #3928);
set_joint_positionswrites back the pose the simulator settled at a limit (#4451);add_robot
names a robot that starts inside the ground, is refused while a recording is open, and
keyframes carry the robot's namespace (#4467, #4015, #4009); a floating base on terrain is seated
by measurement (#3922); a rollout no longer reads a transposedobservation.stateand
joint-keyed actions are unmeasured coverage, not an undriven robot (#3851, #3913);send_action
takes a registry joint label and LeKiwi's arm takes SO-100 labels (#4283, #4535); frame
timestamps follow sim time, a closed recorder refuses a frame, a refusedstart_recordingpoints
at no dataset,get_recording_statusreports saved episodes (#4401, #4318, #4481, #3902);
inverse_dynamicsreports one force per DOF (#3958); the mock clips to the range that holds its
command and the out-of-range warning reads that range (#3956, #3953);grasped'sgripper_prefix
names the gripper body (#4475); a colour channel outside 0..1 is refused (#4504);open_viewer()
on macOS namesmjpython(#4378);list_robots(mode="sim")lists only robotsRobot(name)can
spawn (#4468); the sim ROS 2 bridge publishes only the cameras a robot carries (#4473); Newton
keeps its contact budget on a rendered rollout, carries joint velocity, keeps MJCF servo gains,
and a floating base drives the joints its actions name (#3904, #3895, #3862, #4476); Go2
benchmarks score a folded stance as the fall it is (#3918, #3970). - Dashboard. The tab the address names is the tab shown (#3909); one Fleet card per spawned
robot and a confirmed resume clears the badge (#4142); the sim e-stop no longer claims it locked
the fleet and the e-stop route is not reported dark (#4144, #4143); a recorder failure arrives as
a reason, never exception text (#4208); USB auto-spawn proposes a remembered real arm instead of
starting it (#4316);/api/collectforwards only apolicy_configthe wire accepts (#4314); a
consent answer is the JSON boolean or a refusal (#4315); the tool factory and motion gate read one
precedence, metal first (#4333); Hub search works on the documented install (#4426); the local
address banner never offers an address the dashboard is not listening on (#4458); voice console
on strands-agents 1.57.2 (#4456). - Registry / assets. Two concurrent fetches no longer corrupt one cache (#3995); a
download_assetsthat fetched nothing is not a success (#3997);STRANDS_BASE_DIRtakes the
asset cache with it (#4073);register_robotrefuses a built-in's name unlessoverwrite=True
and names what it collides with (#4483, #4526); an unknown robot says whenuser_robots.jsonis
broken and a key no lookup reaches is refused (#4511, #4176); a description short name loads the
curated robot (#4334);open_duck_mininames the model file upstream has (#4417); a simulated
robot's registryjointsis the countget_robot_statereports (#4363). - Tools / packaging / doctor.
Robot()refuses a non-string name with the promised
ValueErrorand an unknown keyword names the one you meant (#4221, #4484); a positive-number
refusal names the whole domain (#4347);verify-datasettells a wrong path from an unfinished
recording (#4507);stream_dataset(episodes=)streams what it was asked (#4027); the detached
lerobot launchers run this interpreter (#4259);lerobot_train's dtype pin follows the installed
lerobot (#4477);doctorfails a lerobot below 0.6.1, is not fooled by a directory named
lerobot, and keeps Warp's banner out of its report (#4293, #4019, #4416); reading the pose
library or importing a session tool creates no directory in your cwd (#4045, #4037); the PyPI
publish can be re-run against a tag (#3832).
Docs & CI
- The site is written again from the tree (#4112) and then teaches the architecture, not
the API (#4435): eight nav sections and a landing page that shows the robot (#3833, #4003,
#4092), one product look - a 199-line stylesheet, paper and true dark (#3836), a MuJoCo viewer on
every robot page (#4112, #4209, #4207), the robot pages generated with chips, footer, action keys
and a first fence that spawns the robot resting on the ground (#4125, #4130, #4178, #4517, #4518),
the agent tool reference generated from the tool functions (#3835), the driver coverage matrix
generated at build (#4071), ten runnable recipes with their output (#4094), learned policies on
real robots said where readers look (#4234), the 10,542-word simulation reference split into five
table-first pages (#3834), and a docs sweep that makes the Start, Learn and Reference pages say
what the code does (#4286, #4289, #4291). The README redraws its three figures in the
strandsagents.com design and its quickstart puts the red cube in the scene (#4186, #4498). - Docs graders. The word budget grades the whole site, zero slack (#4063); every python and
bash fence underdocs/is checked statically (#4282) and fences the site does not run render as
plain Python without a chip (#4455); Hub ids on pages resolve (#4367); content images are lazy in
the HTML (#4079). - CI. The test suite runs distributed (
pytest -n logical) and a PR's required check with it
(#3992, #4006); whole-tree graders parse each package file once per process (#4332, #4425,
#3884); CodeQL scans the package only (#4135); the publish workflow grants the reusable job what
it asks and can re-run against a tag (#3832);hatchling<1.32so the PyPI publisher's twine
accepts the metadata; the test session leaves everySTRANDS_*variable as it found it (#4225)
and a passed test'stmp_pathis removed at teardown (#4062).
Upgrade
uv venv --python 3.12 && source .venv/bin/activate
uv pip install -U "strands-robots==0.5.3"
uv pip install -U "strands-robots[sim-mujoco,sim-urdf]==0.5.3" # 157 robots in MuJoCo
uv pip install -U "strands-robots[dashboard,mesh]==0.5.3" # python -m strands_robots dashboard
uv pip install -U "strands-robots[mesh-iot]==0.5.3" # AWS IoT Core direct messaging
uv pip install -U "strands-robots[holosoma,wbc]==0.5.3" # G1 locomotion providers
uv pip install -U "strands-robots[foxglove]==0.5.3" # Robot(name, foxglove=True)
uv pip install "strands-robots[sim-mjlab]==0.5.3" # OWN venv: torch>=2.14, out of [all]Before upgrading, check for: create_policy("groot", …) / gr00t_inference / Gr00tTrainer /
[groot-service] (use lerobot_local with policy_type="groot" behind [groot], or remote);
lerobot_async (lerobot's own policy_server); Robot(mode="real") calls that relied on the
lerobot default - they now build the native driver, add driver="lerobot" to keep the old path;
driver="strands" on aloha/vx300s/wx250s/trossen_wxai/dynamixel_2r (the stub is gone,
use lerobot); dashboard scripts that used the in-process Sim tab or its routes (spawn a sim peer);
imports from strands_robots.streaming_dataset, strands_robots.mesh (ROS 2 bases) or the old
Reachy transport path; and DeprecationWarnings from curobo/moveit2/kimodo/protomotions,
Device Connect and start_task(policy_provider=) - each names its replacement. One screen of this:
UPGRADE.md. A fork still builds as 0.1.dev… until git fetch upstream --tags (unchanged since v0.5.2).
Contributors
@cagataycali, @shipitfast, @Vivek0712, @rmncardoso, @dimwael, @tmoreton, @pgrayy - and
@yinsong1986, who reviewed every one of the 621.










