Shimmy wraps external reinforcement learning environments for Gymnasium and PettingZoo
PettingZoo and Gymnasium bindings for popular reinforcement learning environments outside of Farama
At a glance
- What is it?
- Shimmy is an API conversion tool from the Farama Foundation that puts Gymnasium and PettingZoo bindings around reinforcement learning environments it does not own, such as OpenAI Gym, DeepMind Control Suite and OpenSpiel. The conversions are thin wrappers, which keeps the work small but pushes the version constraints of every upstream library onto the Python you can run.
- Who is it for?
- Shimmy is the right tool for a reinforcement learning codebase that wants one gym.make interface across several upstream environment families, and it is cheap to try because the wrappers add little overhead of their own. It is the wrong tool when you need a Python newer than the one your upstream library supports, because the ceilings come from the upstream packages and Shimmy cannot lift them.
- 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 14 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 November 7, 2026, and from our analysis. They are not legal advice.
Star history
- Farama-Foundation/Shimmy932 ★ · -5
| Repository | 2026-10-21 | 2026-11-07 |
|---|---|---|
| Farama-Foundation/Shimmy | 937 | 932 |
-5 Stars in the last 17 days, measured from the daily GitHub snapshot. Compare with other projects
Editorial analysis
Shimmy sits between your code and environments it does not own
Reinforcement learning codebases accumulate environment libraries. A project might start on OpenAI Gym, move to Gymnasium, and still need DeepMind Control Suite for its locomotion tasks or OpenSpiel for a game environment. Each of those libraries exposes its own creation API, and the training code ends up with a different call, a different observation structure and a different reset signature depending on which environment is loaded.
Shimmy is an API conversion tool that provides Gymnasium and PettingZoo bindings for popular external reinforcement learning environments. The point is not to reimplement those environments. The point is that a wrapper makes an external environment look like a Gymnasium or PettingZoo environment to the code that trains on it.
The people who benefit are researchers and engineers who already use Gymnasium or PettingZoo as the training interface and want to swap in an environment from another family without rewriting their training loop. The people who do not benefit are those who only need one environment family and are happy with its native API, since for them the extra dependency buys nothing.
Each extra pulls in a different upstream API and its own pin set
The supported APIs are grouped, and each group is installed as an extra so that you only pull in the dependencies you need. The choices are gym-v21, gym-v26, dm-control, dm-control-multi-agent and openspiel.
pip install shimmyThat base install gives you the package. The environment dependencies come from the extra you name.
pip install shimmy[dm-control]The extras list in setup.py shows how much each choice drags in. gym-v21 pins gym==0.21.0, pyglet==1.5.11 and numpy<2.0. gym-v26 pins gym==0.26.2 with the same NumPy ceiling. dm-control requires dm-control>=1.0.10 together with imageio and h5py>=3.7.0. dm-control-multi-agent adds pettingzoo>=1.23 and protobuf<4 on top, and openspiel requires open_spiel>=1.2 with pettingzoo>=1.23.
That layout has a practical effect. A single environment cannot be installed through all of them at once, because gym==0.21.0 and gym==0.26.2 are different pins of the same distribution. The project answers this by telling you to use a separate virtual environment for an extra that needs a different Python than the rest of your setup, which is the honest answer but also a real cost in CI and developer setup.
The Python ceiling comes from the upstream library, not from Shimmy
Shimmy requires Python 3.11 or newer. The interesting constraint is the ceiling on each extra, and the README is unusually explicit about where those ceilings come from.
The gym-v21 extra stops at Python 3.11 because gym 0.21.0 needs setuptools==65.5.0, which calls pkgutil.ImpImporter, a name removed in Python 3.12, and it also needs pip<24.1 to accept its malformed metadata. The gym-v26 extra stops at 3.12 because it pins numpy<2.0 and NumPy 1.26 ships wheels only through cp312, so on newer Python pip falls back to building NumPy 1.x from source, which the README calls slow and not guaranteed to work. The dm-control and dm-control-multi-agent extras also stop at 3.12, because labmaze, which dm_control pulls in, ships no wheels beyond cp312. The openspiel extra goes furthest, to Python 3.14, since open_spiel publishes wheels through cp314.
Read that table as a warning about the direction of travel. The newest supported extra still trails the newest Python, and the older Gym extras trail further. Shimmy cannot fix this because the constraint is inside the library it wraps, and the fix the project proposes is a separate virtual environment rather than a patch.
Making a DM Control suite environment and flattening its observation
The at-a-glance example loads one environment out of the DM Control suite, prints the environment ids it knows about, and then compares the raw observation space with the flattened one. The list of ids comes from a registration module inside the package.
import gymnasium as gym
from shimmy.registration import DM_CONTROL_SUITE_ENVS
env_ids = [f"dm_control/{'-'.join(item)}-v0" for item in DM_CONTROL_SUITE_ENVS]
print(env_ids)
env = gym.make(env_ids[0])
env_flatten = gym.wrappers.FlattenObservation(env)
print(env_ids[0])The ids take the form dm_control/<task>-v0, and the example prints a list that runs from acrobot-swingup through walker-run, including sparse and pure state variants of several tasks. The first id in the list resolves to dm_control/acrobot-swingup-v0.
What the example demonstrates is that the wrapper produces a Gymnasium observation space rather than the raw DeepMind Control one. For that environment the observation space is a Dict with orientations and velocity Box entries, and the action space is a Box between -1.0 and 1.0. Applying gym.wrappers.FlattenObservation turns the Dict into a single Box of shape (6,) while leaving the action space alone. That flatten step is a Gymnasium wrapper, not something Shimmy adds, so the wrapper layer stays thin and the shape change stays a choice you make in your own code.
Multi-agent coverage stops at DM Control Soccer and OpenSpiel
The bindings are not symmetric across the two target APIs. OpenAI Gym environments are converted to Gymnasium. DeepMind Control environments are converted to Gymnasium. PettingZoo bindings exist for two sources only: DM Control Soccer environments, and OpenSpiel environments.
That asymmetry is worth knowing before you design an experiment around it. If your multi-agent baseline is a DeepMind Control locomotion task other than Soccer, there is no PettingZoo binding for it in the list of supported APIs. If it is an OpenSpiel game, there is. The setup.py extras mirror this: pettingzoo appears as a dependency of dm-control-multi-agent and openspiel, but not of the plain gym or dm-control extras.
The repository also ships an android-env extra in setup.py, pulling in android-env>=1.2.4, and a testing extra with pytest>=7.1.3 and pillow>=9.3.0. The README's list of installation choices does not mention android-env, so its status in the documented workflow is unclear from what is written there.
Wrapping an environment instead of calling its native API
The alternative to Shimmy is to use the upstream library directly, and for a single environment family that is often the better choice. The difference in approach is narrow but real. The native API asks you to call the upstream library's own environment constructor and to handle its reset and step signatures. A Shimmy binding gives you a Gymnasium or PettingZoo environment, so gym.make works with the same argument shape and the same wrappers you already use everywhere else in the project.
That buys uniformity, and it costs a layer. The wrapper translates observations, actions, resets and termination signals between two APIs, and any behaviour the upstream library exposes but the target API has no slot for has to be dropped or reached around. The DM Control Soccer case shows the shape of the problem: a multi-agent task has to be squeezed into an API that was designed for a single agent, and the README gives no list of what is preserved.
A third path is writing the wrapper yourself. The general point stands: for one environment, a short adapter of your own is often cheaper than a dependency, and for four or five environments across three libraries a shared adapter library starts to pay for itself.
Maintenance signals, citation and what the licence covers
The repository is not archived and the last push was on 2026-10-14. The release history is sparse rather than steady: v2.0.1 was published on 2026-04-10, v2.0.0 on 2024-05-21, and v1.3.0 on 2023-10-17. A project with this shape is one you will see updated in large steps, not weekly, so a pinned dependency will sit unchanged for long stretches and then jump a major version.
The project is maintained under the Farama Foundation, with Mark Towers named as project manager and other Farama team members contributing maintenance. It is released under the MIT licence, and the setup.py file points at a LICENSE file for the licence text. If you use Shimmy in research, the README asks you to cite a software DOI, 10.5281/zenodo.8140744, with the citation file CITATION.cff also present in the repository.
The licence choice matters mostly for downstream packaging: MIT places no restriction on using the bindings inside a proprietary or closed-source research stack, though it does require the licence and copyright notice to travel with copies of the software.
Editorial conclusion
Shimmy is the right tool for a reinforcement learning codebase that wants one gym.make interface across several upstream environment families, and it is cheap to try because the wrappers add little overhead of their own. It is the wrong tool when you need a Python newer than the one your upstream library supports, because the ceilings come from the upstream packages and Shimmy cannot lift them. Verify first which extra you actually need and which Python it permits, then create a separate virtual environment for any extra whose ceiling differs from the rest of your project.
Frequently asked questions
How do I install Shimmy and the environment dependencies?
Install the base package with pip install shimmy, then add the extra for the environment family you need, for example pip install shimmy[dm-control]. The documented choices are gym-v21, gym-v26, dm-control, dm-control-multi-agent and openspiel.
Which Python versions does Shimmy support?
Shimmy requires Python 3.11 or newer. Each extra has its own ceiling set by the upstream library: gym-v21 stops at 3.11, gym-v26 and the dm-control extras stop at 3.12, and openspiel goes to 3.14. The README suggests a separate virtual environment when you need a newer Python than an extra supports.
Which external environments have PettingZoo bindings?
Two families are listed: DM Control Soccer environments and OpenSpiel environments. OpenAI Gym and DeepMind Control environments are converted to Gymnasium instead.
What do the Shimmy environment ids look like?
The at-a-glance example builds them from the DM_CONTROL_SUITE_ENVS list as dm_control/<task>-v0, and the first entry resolves to dm_control/acrobot-swingup-v0. The list is imported from shimmy.registration.
Can I install every Shimmy extra in one environment?
Not the two Gym extras, since they pin different versions of the same gym distribution, gym==0.21.0 against gym==0.26.2. The README advises using a separate virtual environment for an extra that needs a different Python than the rest of your setup.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/farama-foundation-shimmy)Star history chart for your README
[](https://hysenlabs.com/projects/farama-foundation-shimmy)Was this useful?