Upload a Model or Environment
Build a container, push it to RLMesh, and run it from the dashboard.
This example uploads a Gymnasium environment. A model follows the same login and push steps; its image serves a model instead of an environment.
Create the environment
In a new directory, add environment.py:
import gymnasium as gym
from rlmesh import EnvFactory
class CartPole(EnvFactory):
def make(self) -> gym.Env:
return gym.make("CartPole-v1")
Add a Dockerfile beside it:
FROM python:3.11-slim
ARG RLMESH_VERSION=0.1.0
RUN pip install --no-cache-dir "rlmesh[gymnasium]==${RLMESH_VERSION}"
WORKDIR /app
COPY environment.py .
EXPOSE 50051
CMD ["python", "-m", "rlmesh.serve", "--env", "environment:CartPole"]
rlmesh.serve starts the environment server when RLMesh runs the image. The platform uses that command to identify and probe the environment after you push it. For a model, use CMD ["python", "-m", "rlmesh.serve", "model:MyModel"] and declare its inputs and outputs with a ModelSpec. See Bring Your Own Container for a model container example.
This example pins rlmesh==0.1.0; override RLMESH_VERSION at build time to use another release. Use the SDK version your managed deployment pins. From the SDK release that advertises workflow editions in rlmesh describe, the platform admits an image when it shares a workflow edition with the runtime instead of requiring the same SDK version: every release carries the sealed edition it implements (for example 2026.06) beside its own build, so a platform release does not invalidate an image you already pushed unless the sealed edition changes, and the push probe reports the negotiated edition or why none was shared. For a complete environment/model pair and a local container test, follow Bring Your Own Container.
Check before you push
rlmesh check is available from the SDK release that includes it; until then skip this step. It runs the same packaging checks the platform runs at push time, so a missing ModelSpec, an environment without tags, or a spec that does not resolve fails here instead of on the probe. Run it against the class from the directory that holds it:
rlmesh check environment:CartPole
After building, rlmesh check-image <tag> reads the image config: the serve command, the exposed port, the architecture, and any dev.rlmesh.* labels. Fix what either command reports as failed; warnings do not block a push.
GPU images
The platform needs no resource declaration except a GPU. It looks for one in this order:
- A
gputag on the repository (Edit metadata on the image page), or in the image’s package label:LABEL dev.rlmesh.package='{"schemaVersion":1,"name":"cartpole","tags":["gpu"]}'. Either one requires a GPU for every run. Acputag in the same places forces CPU. - Without a tag, the probe runs on a GPU when the image is built from a CUDA base (it reads
CUDA_VERSIONorNVIDIA_REQUIRE_CUDAfrom the image config) or when the previous version of the same repository used one, and your organization has a GPU cluster. If the probe measures VRAM use, the image is markedgpu: measuredand evaluations default to a GPU; add acputag if that use was incidental. If it measures none, the measurement is recorded with agpu_unconfirmedflag and evaluations stay on CPU; a probe on a CPU node is what confirms CPU compatibility. - Otherwise the image runs on CPU. A CPU probe that fails with a CUDA or driver error says so on the image page; add the
gputag and probe again.
CPU and memory come from the probe’s measurements, floored at the platform defaults, unless the package label declares them.
Log in and push
Install the RLMesh Python package on your machine, then run:
rlmesh login
rlmesh registry login
The first command opens a browser to sign in. The second connects your local Docker client to the RLMesh registry. You do not need to run docker login separately.
Open Registry in the dashboard to find your registry host and organization namespace. Replace your-namespace below with yours, then build and push from the directory containing the two files:
docker build --platform linux/amd64 -t registry.rlmesh.dev/your-namespace/cartpole:latest .
rlmesh check-image registry.rlmesh.dev/your-namespace/cartpole:latest
docker push registry.rlmesh.dev/your-namespace/cartpole:latest
If the dashboard shows a different registry host, use it in both commands. Push latest (or current) to advance the repository’s selected digest; an immutable tag such as v1 records a version without selecting it as the current image.
Run an evaluation
Watch the image under Registry → Your uploads. RLMesh probes it after the push; if the probe fails, open the image to see why. Once it is ready, choose New evaluation, select the environment and a model, then launch. The evaluation page shows progress, episode results, and logs.