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:

  1. A gpu tag 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. A cpu tag in the same places forces CPU.
  2. Without a tag, the probe runs on a GPU when the image is built from a CUDA base (it reads CUDA_VERSION or NVIDIA_REQUIRE_CUDA from 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 marked gpu: measured and evaluations default to a GPU; add a cpu tag if that use was incidental. If it measures none, the measurement is recorded with a gpu_unconfirmed flag and evaluations stay on CPU; a probe on a CPU node is what confirms CPU compatibility.
  3. 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 gpu tag 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.