Framework Backends
A backend decides what RLMesh decodes values into at the Python boundary.
A backend decides what RLMesh decodes values into at the Python boundary. The wire stays framework-neutral, so the backend is a client-side choice: it changes the type you receive from reset and step, not the protocol or the server. The same served environment can feed a NumPy client, a Torch client, and a JAX client at once.
Every backend exposes the same surface (RemoteEnv, RemoteVectorEnv, Model, RemoteModel, and the sandbox sessions) under its own import path. Pick the one whose import matches the values your code already speaks.
import rlmesh # plain Python and RLMesh-native values
from rlmesh.numpy import RemoteEnv # NumPy arrays
from rlmesh.torch import RemoteEnv # Torch tensors (experimental)
from rlmesh.jax import RemoteEnv # JAX arrays (experimental)
Choosing a backend
| Backend | Import | Install | Tensor leaves decode to | Status | Reach for it when |
|---|---|---|---|---|---|
| Plain Python | rlmesh |
bundled | RLMesh-native values | supported | you want no array dependency, just primitives |
| NumPy | rlmesh.numpy |
pip install "rlmesh[numpy]" |
NumPy arrays | supported | examples, notebooks, and most CPU evaluation |
| Torch | rlmesh.torch |
pip install "rlmesh[torch]" |
Torch tensors | experimental | your model or environment already speaks Torch, GPU included |
| JAX | rlmesh.jax |
pip install "rlmesh[jax]" |
JAX arrays (immutable) | experimental | your pipeline is JAX |
In every backend, only tensor leaves change type. Python primitives and nested containers (dict, tuple, lists) are preserved as they are.
Install the extra for the backend you use, then import its client or model class:
pip install "rlmesh[numpy]" # or rlmesh[torch], rlmesh[jax]
from rlmesh.numpy import RemoteEnv
with RemoteEnv("127.0.0.1:5555") as env:
obs, info = env.reset(seed=0)
Space wrappers use the client’s backend too, so env.action_space.sample() produces a value that env.step() can accept. Torch and JAX conversion happens at the client boundary; the environment itself can remain a plain Gymnasium environment. JAX arrays are immutable. For conversion details and version requirements, see the Python API.
What “experimental” means here
Torch and JAX are device-bearing frameworks: their obs/action seam can carry tensors that live on a device, GPU included. NumPy and the plain backend have no device concept. That difference is the source of the limitations to know before you reach for them.
| Behavior | NumPy / plain | Torch / JAX |
|---|---|---|
| Device | none | tensors can live on a device; an env-side action accepts device= (see Serve an Environment) |
| Serving a vector env | num_envs > 1 fans out via Gymnasium |
not supported: Gymnasium vectorization concatenates observations with NumPy and discards framework tensors. Serve scalar (num_envs=1), or serve with NumPy |
| Mutability of decoded values | NumPy arrays are writable | JAX arrays are immutable |
The wire is framework-neutral regardless of backend, so a client’s framework is independent of the server’s. A NumPy environment can serve a Torch model client; nothing in between needs to agree on a framework.
Models
Backends apply to models the same way. A Model from any backend hands predict values in that backend’s types:
from rlmesh.numpy import Model
model = Model(lambda obs: 0)
model.run("127.0.0.1:5555", episodes=1)