The robot learning data loop has always had a bandwidth problem. You record demonstrations, push them to storage, pull them back down for training, push checkpoints up, pull them back to hardware. Run that once and it works. Run it daily and you're paying for the same bytes over and over.
A new post from AWS and Hugging Face just walked through the solution: Hugging Face Storage Buckets as the mutable layer underneath LeRobot datasets, letting you stream training data straight from the Hub without a full download. Combined with Strands Agents—AWS's open-source SDK that wraps robot control, simulation, and the LeRobot stack into composable agent tools—you get a genuinely practical closed loop.
This is the second post in the Strands Robots series. The first covered deploying policies to hardware. This one runs the data the other direction: from recorded frame to trained checkpoint, all inside one agent.
What Storage Buckets Actually Do Here
Storage Buckets are a new repository type on Hugging Face, announced in March 2026. Unlike dataset repos—which version every commit and retain every revision—buckets give you mutable, non-versioned object storage in the same hf:// namespace.
The use case is obvious once you see it: working storage for data between recording and training. LeRobot writes datasets as a small number of large files that grow as you record. Push those into a versioned repo and every append becomes a commit. Push them into a bucket and you overwrite in place.
Buckets are backed by Xet, Hugging Face's content-addressed storage layer, which does byte-level deduplication. When you sync a LeRobot dataset that added 500 new episodes, only the new bytes transfer. The rest are already there.
The Four-Stage Loop in One Agent
The post walks through a complete data loop using Strands Robots' Robot() factory and the LeRobot dataset format. Here's what each stage does:
1. Record
You instantiate a Robot("so100") in simulation (the SO-100 is one of many supported embodiments—Strands maintains a registry of arms, humanoids, mobile bases, and hands). The agent records a demonstration from a natural-language prompt and writes a LeRobotDataset to disk.
The dataset stays in LeRobot's native format the whole way through. No conversion, no intermediate serialization. Over 90,000 datasets and models on the Hub already use this format, from more than 8,000 publishers.
2. Store
You sync the dataset to a Storage Bucket with sync_dataset_to_bucket(...). Because buckets use Xet's content-addressed backend, only changed bytes upload. Record 100 episodes Monday, sync them. Record 50 more Tuesday, sync again—only the 50 new episodes transfer.
This is the piece that makes continuous collection practical. Without it, you're re-uploading gigabytes every time you add a handful of demonstrations.
3. Train
Here's where it gets interesting. Instead of downloading the dataset and then training, you stream it straight from the Hub:
for batch in sim.stream_dataset(
"my-org/robot-fave/cube_pick",
repo_type="bucket"
).dataloader(batch_size=64):
...
The same Robot() instance that recorded the dataset now reads it back frame by frame, decoding camera video on the fly. No local copy. The dataset lives on the Hub; training pulls only what it needs, when it needs it.
This works because LeRobot's dataset format is designed for streaming. Camera frames are stored as compressed video. State-action telemetry is in efficient columnar formats. The dataloader decodes lazily.
4. Deploy
Once you have a trained checkpoint, deploying it to hardware is a one-argument change: Robot("so100", mode="real"). The demonstrations it records on the physical arm return to the same bucket, closing the loop.
The whole thing, in a handful of lines:
from strands import Agent
from strands_robots import Robot
sim = Robot("so100") # mode="sim" by default
agent = Agent(tools=[sim])
# Record and sync
agent("Record a pick-the-cube demo and sync it to my-org/robot-fave.")
# Stream back from the bucket to train
for batch in sim.stream_dataset(
"my-org/robot-fave/cube_pick",
repo_type="bucket"
).dataloader(batch_size=64):
...
Why This Matters
The robot learning stack has had most of these pieces for a while. LeRobot gave us a common dataset format. Hugging Face gave us Hub storage and model hosting. Simulation environments let you iterate without hardware.
What was missing was the connective tissue that makes the loop efficient. Byte-level deduplication means you're not paying bandwidth costs for data you already uploaded. Streaming means you're not waiting for multi-gigabyte downloads before training starts. Mutable buckets mean you're not versioning every incremental addition during active collection.
And wrapping it all in agent tools means the decisions—which episodes to keep, when to retrain, which checkpoint to deploy—can be made by the agent itself, in natural language, as part of the same process that controls the robot.
The Open Questions
Can you actually train production policies by streaming? The post uses a mock policy by default (the minimal setup runs entirely on a laptop). Training a real vision-language-action model at scale means GPU clusters reading from the Hub. The architecture supports it—LeRobot datasets are already streamed in production—but latency and throughput on your specific cluster setup matter.
How does this interact with dataset versioning? Buckets are explicitly non-versioned. That's the point during active collection. But once you've decided a dataset is "done" and you want reproducibility, you probably want to snapshot it into a versioned dataset repo. The post doesn't cover that transition, though the hf CLI supports copying between repo types.
What about multi-robot collection? The loop shown is one robot, one agent, one bucket. In practice, you're probably collecting from multiple robots in parallel, maybe with different embodiments. The post hints that the Robot() factory resolves embodiment names against a registry, but doesn't walk through coordinating data from heterogeneous sources.
What You Need to Run This
The minimal path (simulation only, mock policy) needs:
- Python 3.12+, Linux or macOS
- A Strands-compatible model provider (Bedrock, Anthropic, OpenAI, or Ollama)
uv pip install -U "strands-robots[sim-mujoco,lerobot]>=0.5.1"
That's it. The loop runs on a laptop.
For the full path (buckets, hardware, real policies):
- A Hugging Face account and token with write permission
huggingface-hub>=1.6.0andhf auth login- An SO-101 or other LeRobot-supported robot with calibration files
- An NVIDIA GPU for local VLA inference, or a cluster for training at scale
uv pip install "lerobot[training]"if you want to actually run training
The companion notebook is runnable end-to-end.
The Bigger Picture
Strands Robots is Apache 2.0. LeRobot is open. Storage Buckets are a Hugging Face platform feature, but the data format and agent architecture aren't locked in.
What's notable here isn't any single technical piece—it's that someone finally stitched them together into a workflow that doesn't require custom infrastructure. You can run the whole loop, from demonstration to deployed checkpoint, using open tools and commodity cloud storage.
That's the kind of thing that moves a research paradigm into production. Not because it unlocks a new capability, but because it removes enough friction that people actually do it.