Model or dataset
galilai-group/stable-worldmodel avatar
galilai-group/stable-worldmodel

stable-worldmodel: a shared harness for the collect, train, plan loop

A platform for reproducible world model research and evaluation

2,195 stars271 forksPythonMIT

At a glance

What is it?
The project wraps dataset collection, world model training and model-predictive control evaluation behind one Python interface, with a format registry that lets you swap LanceDB for HDF5, MP4 or LeRobot. The interface is the product here, and it is still moving.
Who is it for?
Adopt it if you are comparing world models or planning solvers and want the data and evaluation plumbing to be someone else's problem: the format registry, the CEMSolver and PlanConfig split, and the two reference training scripts in scripts/train give you a working starting point. Do not adopt it if you need a frozen API or a long-term-stable dependency surface, because the README states that APIs may change between minor versions and the project has not reached 0.2.0.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 7 days ago.
What is it written in?
Mainly Python, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on September 15, 2026, and from our analysis. They are not legal advice.

DEEP OPEN-SOURCE ANALYSIS

What stable-worldmodel actually replaces

World model papers tend to ship as a model file plus a training script, and the evaluation is a separate repository written by whoever needed the number first. stable-worldmodel targets that seam. The README describes it as providing a single, unified interface for three stages: collecting data, training, and evaluating with model-predictive control, across a suite of standardized environments. It also ships reference implementations of baselines and planning solvers.

The intended user is a researcher who wants to spend effort on the model and the objective rather than on the loader. If you are comparing two world models, or one model against two planners, the value is that the dataset, the environment and the evaluation loop stay fixed while you swap one component. If you are building a single model for a single task and never intend to run a comparison, the abstraction is overhead you will pay for in indirection.

The three objects: World, dataset, policy

The quick start shows the data flow in three moves. First, swm.World("swm/PushT-v1", num_envs=8) constructs an environment wrapper, you attach an expert policy with world.set_policy, and world.collect("data/pusht_demo.lance", episodes=100, seed=0) writes episodes to disk. Second, swm.data.load_dataset("data/pusht_demo.lance", num_steps=16) returns a dataset object, with the format autodetected from the path. Third, you build a solver, wrap it in a policy, and call world.evaluate(episodes=50), which returns a dict containing at least success_rate.

The split between solver and policy is the part worth noting. CEMSolver(model=world_model, num_samples=300) owns the sampling and scoring of candidate action sequences. WorldModelPolicy(solver=solver, config=PlanConfig(horizon=10, receding_horizon=5)) owns the planning configuration and the receding-horizon bookkeeping. That means you can change the planner without touching the policy, and change the horizon without touching the solver. The horizon and receding_horizon are separate keys rather than one number, so the amount of plan executed before replanning is explicit.

One thing the README does not show is how the world model plugs into the solver. The quick start writes world_model = ... # your model, so the interface a model must satisfy is not visible in the material available here. Check the documentation before assuming an arbitrary PyTorch module will drop in.

The format registry is the real design decision

Recording, loading and conversion all route through a registry, and the README lists five backends with different on-disk layouts. lance stores an episode-contiguous flat table in LanceDB and is the default. hdf5 writes a single .h5 file with one dataset per column. folder writes .npz columns plus one JPEG per step, which the README recommends for inspection and partial-key streaming. video writes .npz columns plus one MP4 per episode decoded with decord, aimed at long episodes and compact image storage. lerobot is a read-only adapter addressed as lerobot://<repo_id>.

The migration path is a single call: swm.data.convert("data/pusht.lance", "data/pusht_video", dest_format="video", fps=30). That is a real convenience, because it means the format choice is not a commitment. You can collect into the append-friendly default and move to MP4 later if image storage becomes the constraint.

Every writer accepts a mode kwarg with values 'append' (the default), 'overwrite', and 'error'. The README notes that re-running world.collect extends the existing dataset rather than failing. That default is friendly for long collection runs and slightly dangerous for anyone who assumes a rerun is idempotent. If you want a rerun to stop rather than silently double your episode count, pass mode='error'.

Installing: the extras are sized on purpose

There are three install lines. pip install 'stable-worldmodel[data]' is described as the recommended option: base plus Lance dataset I/O. pip install stable-worldmodel is planning and model only, with no dataset I/O. pip install 'stable-worldmodel[all]' adds training, environments and data formats.

The README explains why [data] is separate: the Lance stack (lancedb, pylance, pyarrow) is roughly 410 MB of native wheels, and consumers who only need stable_worldmodel.planning inside a robotics image should not be forced to install them. That is a deliberate packaging choice, and it is the kind of detail that usually only appears after someone has been burned by image size. LeRobot support is a further opt-in extra and requires Python 3.12 or newer: pip install 'stable-worldmodel[lerobot]'.

For development, the README gives a uv flow: clone the repository, run uv venv --python=3.10, activate, then uv sync --extra all --group dev. Note the version gap: the development path pins Python 3.10 while the lerobot extra needs 3.12 or newer, so a single environment cannot cover both without thought.

Datasets and checkpoints live under $STABLEWM_HOME, which defaults to ~/.stable_worldmodel/. The README states you can override the variable to point at another storage location. On a machine with a small home partition, that override is the first thing to set.

Where it will not help you

The README carries an explicit warning: the library is in active development and APIs may change between minor versions. The release history backs that up. Three releases are listed, 0.0.5 in February 2026, 0.1.0 in May 2026 and 0.1.1 in June 2026, and the project is still pre-1.0. If you are pinning this as infrastructure under a longer-lived codebase, budget for upgrade work at each minor bump.

The second limitation is scope. The environment suite is described as standardized, and the only environment named anywhere in the supplied material is swm/PushT-v1. If your task is not in that suite, the platform does not remove your environment work; you will be writing the wrapper and the expert policy yourself, which is most of what you were trying to avoid.

The third is the one to watch for if you are comparing against published numbers. The README includes a GPU utilization figure for LeWM trained on the Push-T LanceDB dataset on an H200, and points at scripts/benchmark/compare_h5_lance.py for throughput and storage benchmarks. Those are the project's own measurements on its own hardware. They tell you the harness can saturate a GPU; they do not tell you what your model will score. Reproducibility here means the loop is fixed, not that results transfer across hardware or dataset versions.

How it differs from LeRobot

The most direct comparison in the material is LeRobot, and the difference is not a feature checklist. LeRobot is the dataset source: stable-worldmodel reads it through a read-only adapter addressed as lerobot://<repo_id>, so you can train and evaluate directly on Hub datasets without converting them first. That is an integration, not a rivalry.

The divergence is in what each one treats as the center of the system. LeRobot centers the dataset and the policy training loop around it. stable-worldmodel centers the evaluate-with-planning step: the solver, the PlanConfig, the receding horizon, and the success_rate returned by world.evaluate. If your work is imitation learning from a fixed dataset, LeRobot's framing is closer to the problem. If your work is asking whether a learned model can plan, the solver and horizon abstractions are the ones you want, and the LeRobot adapter means you can still start from Hub data.

A second alternative worth naming is simply writing your own loop. For a single environment and a single model, a few hundred lines of PyTorch will be less code than learning this API, and you will not inherit the pre-1.0 churn. The trade-off is that your loader, your evaluation and your planner will be private, and a reviewer asking for a comparison will have to trust them.

Licence, maintenance and what to verify first

The repository is MIT licensed. In practical terms that is a permissive licence with minimal conditions, and it is compatible with embedding the planning package in a larger system. This is a description of the licence identifier, not legal advice; read the LICENSE file and talk to counsel if the terms matter to your organisation.

Maintenance signals visible in the material: the repository is not archived, the last push is dated 2026-09-08, and the release cadence shows three versions across roughly seven months. The README links a test workflow badge and the project uses Ruff, so there is tooling in place. None of that tells you how quickly an issue will be answered.

The upgrade cost is the pre-1.0 API. The README says APIs may change between minor versions, which means a 0.1.1 to 0.2.0 move is a code-review event, not a version bump. Pin the version, and read the release notes before moving.

What to verify before you invest: whether the environment you need exists under the swm namespace and what its version suffix is, because only swm/PushT-v1 appears in the supplied material; what interface your model must implement to satisfy CEMSolver, since the quick start leaves it as an ellipsis; and whether $STABLEWM_HOME has the capacity for your planned episode count in the format you choose, given that the video backend trades decode cost for smaller image storage.

Editorial conclusion

Adopt it if you are comparing world models or planning solvers and want the data and evaluation plumbing to be someone else's problem: the format registry, the CEMSolver and PlanConfig split, and the two reference training scripts in scripts/train give you a working starting point. Do not adopt it if you need a frozen API or a long-term-stable dependency surface, because the README states that APIs may change between minor versions and the project has not reached 0.2.0. Before committing, verify two things yourself: that $STABLEWM_HOME points at storage with room for your episode count, and that the environment you care about exists under the swm namespace with a version suffix, since the README only shows swm/PushT-v1.

Official sources

  1. galilai-group/stable-worldmodel on GitHub
  2. License: MIT
  3. Project website
  4. README
  5. Releases
Community notes

Community notes