Serving and Clients

Note

This is the autodoc API reference. For authoring environments (tags, params, variants, containers) see Environments; for the serving mechanics see Serve an Environment; for the client walkthrough see Connect a Remote Environment.

Env Server

EnvServer owns one Python environment object and exposes it as an RLMesh environment endpoint. It is self-describing: pass a vectorized environment (one exposing num_envs and single_observation_space / single_action_space) and it serves a vector endpoint automatically; otherwise it serves a single-environment endpoint. A model or evaluator connects with RemoteEnv for scalar endpoints and RemoteVectorEnv for vector endpoints.

Environment Contract

The server inspects the environment once during construction and caches an EnvContract. The contract describes the endpoint id, spaces, render mode, metadata, and number of environments. EnvServer.spec is an alias for env_contract so code that expects a Gymnasium-style spec field can still reach the same RLMesh contract.

server = rlmesh.EnvServer(env, "127.0.0.1:5555")
print(server.env_contract.id)
print(server.env_contract.observation_space.kind)
print(server.spec.action_space.kind)

See Contracts and Specs for contract fields.

Bind Address Environment Variables

When RLMesh serves an environment through its bootstrap entrypoint (for example inside a sandbox container), the bind address follows a single canonical contract so that hosts and downstream images agree on where the environment listens:

Variable

Meaning

RLMESH_ADDRESS

Full bind address (host:port, port, tcp://host:port, unix:///...). When set, it wins.

RLMESH_PORT

Port-only fallback, bound on 0.0.0.0, used when RLMESH_ADDRESS is unset (default 50051).

RLMESH_ENV_ADDRESS

Deprecated alias for RLMESH_ADDRESS; read only when it is unset.

RLMESH_ENV_PORT

Deprecated alias for RLMESH_PORT; read only when both addresses are unset.

RLMESH_ADDRESS is the preferred knob; it accepts the same forms as the server address argument, so a non-default host or a Unix socket can be selected without code changes. RLMESH_ENV_ADDRESS / RLMESH_ENV_PORT are deprecated aliases kept for backward compatibility. Constructing EnvServer directly in your own process ignores these variables. Pass address/host/port explicitly.

class rlmesh.EnvServer[source]

Bases: object

Serves an RLMesh-compatible environment.

Parameters:
  • env – Environment satisfying the RLMesh protocols.

  • address – Optional bind address. Supports "tcp://host:port", "host:port", "port", and "unix:///path/to/socket.sock". Defaults to "tcp://127.0.0.1:0" when omitted.

  • host – TCP host helper used when address is omitted.

  • port – TCP port helper used when address is omitted.

  • path – Unix socket path helper used when address is omitted.

  • transport – Explicit transport selector.

  • options – Optional serve lifecycle options controlling remote shutdown, idle shutdown, drain timeout, and close timeout.

  • tags – Optional adapter env tags (rlmesh.adapters.EnvTags) to publish for this env. They are validated against the env’s spaces and merged into its metadata, so a model client can resolve an adapter from the contract alone (see rlmesh.adapters.resolve_from_contract()).

  • framework – The framework the env’s step requires its action as – "torch", "jax", "numpy" (default), or a ValueBridge. Only needed for a framework-strict env (one whose step does e.g. action.to(...)); a tolerant env can omit it. Observations need no declaration – a torch/jax obs (GPU included) is auto-detected and encoded either way. The wire stays framework-neutral, so the env’s action framework is independent of any consuming model’s framework.

  • device – Device to place the incoming action on (torch/jax only), e.g. "cuda:0" or a torch.device. Requires framework=; rejected for numpy/the default.

Examples

>>> from rlmesh import EnvServer, spaces
>>>
>>> class TinyEnv:
...     observation_space = spaces.from_gymnasium_space(
...         __import__("gymnasium").spaces.Discrete(4)
...     )
...     action_space = spaces.from_gymnasium_space(
...         __import__("gymnasium").spaces.Discrete(2)
...     )
...
...     def reset(self, *, seed=None, options=None):
...         return 0, {}
...
...     def step(self, action):
...         return 0, 0.0, False, False, {}
...
...     def close(self):
...         return None
>>> server = EnvServer(TinyEnv(), "localhost:5555")
>>> server.serve()
__init__(env, address=None, *, host=None, port=None, path=None, transport=None, options=None, tags=None, framework=None, device=None)[source]
Parameters:
  • env (EnvLike[Any, Any] | VectorServerEnvLike)

  • address (str | None)

  • host (str | None)

  • port (int | None)

  • path (str | None)

  • transport (Transport | None)

  • options (ServeOptions | None)

  • tags (EnvTags | None)

  • framework (str | ValueBridge | None)

  • device (object | None)

Return type:

None

property address: str[source]

Get the bound server address.

property env_contract: EnvContract[source]

Environment contract served by this endpoint.

property spec: EnvContract[source]

Alias for env_contract.

serve()[source]

Start serving the environment (blocking).

Return type:

None

start()[source]

Start serving the environment on a background thread.

Return type:

None

wait(timeout=None)[source]

Wait for a background server to stop.

Parameters:

timeout (float | None) – Optional timeout in seconds. None waits indefinitely.

Returns:

True if the server has stopped, or False if the timeout elapsed.

Return type:

bool

shutdown()[source]

Stop the server if it is running.

Return type:

None

Serving Helpers

Note

rlmesh._serving is experimental and not yet part of the public surface. Use it with version pinning; signatures may still change before the stable release.

rlmesh._serving exposes a small surface for constructing an environment to serve through EnvServer. It promotes the loaders previously hidden in rlmesh._cli.serve_env so that scripts and downstream runners can build an environment by Gymnasium id or by module:callable entrypoint.

Reach for it when a script or runner has to build the environment itself before serving. If you already hold an env object, pass it straight to EnvServer.

import rlmesh
from rlmesh import _serving

env = _serving.load_env("CartPole-v1")
rlmesh.EnvServer(env).serve()
rlmesh._serving.load_env(env_id, *, packages=(), num_envs=1, vectorization_mode=None, kwargs=None)[source]

Load a Gymnasium/Gym environment by registered id (e.g. "CartPole-v1").

packages are imported first so their environments self-register; num_envs > 1 vectorizes (vectorization_mode "sync"/"async"). Returns an environment suitable for rlmesh.EnvServer.

Parameters:
  • env_id (str)

  • packages (Sequence[str])

  • num_envs (int)

  • vectorization_mode (str | None)

  • kwargs (Mapping[str, object] | None)

Return type:

ServedEnv

rlmesh._serving.load_env_entrypoint(entrypoint, *, packages=(), kwargs=None)[source]

Load an environment from a module:callable factory entrypoint.

The callable must return an env exposing reset(...)/step(...); packages are imported before resolving it. Returns an environment suitable for rlmesh.EnvServer.

Parameters:
  • entrypoint (str)

  • packages (Sequence[str])

  • kwargs (Mapping[str, object] | None)

Return type:

ServedEnv

rlmesh._serving.import_packages(packages)[source]

Import packages so they can register their environments.

Parameters:

packages (Sequence[str])

Return type:

None

Remote Clients

Remote clients connect to an environment endpoint and expose the same core calls as a local Gymnasium environment: reset, step, render, and close. Reach for one when the environment runs in another process; the contract from the handshake supplies the spaces, so the client needs no local copy of the env.

Use the concrete backend modules in application code:

  • rlmesh.RemoteEnv and rlmesh.RemoteVectorEnv preserve RLMesh-native values.

  • rlmesh.numpy.RemoteEnv and rlmesh.numpy.RemoteVectorEnv decode tensor leaves as NumPy arrays.

  • rlmesh.torch.RemoteEnv and rlmesh.torch.RemoteVectorEnv decode tensor leaves as Torch tensors.

Every remote client keeps the endpoint handshake in env_contract. The spec property is an alias for that same contract. observation_space and action_space are client-side wrappers built from the contract’s SpaceSpec values.

Use render() to pull a single decoded frame from the endpoint. The environment must produce frames, typically render_mode="rgb_array"; render() returns None when it has no frame.

Single Environment Base

class rlmesh._client.RemoteEnvBase[source]

Bases: RemoteClientBase[ValueT, ActionT]

Base class for backend-specific single-environment remote clients.

Backend modules such as rlmesh.numpy and rlmesh.torch configure the value bridge. User code should normally instantiate those concrete backends instead of this base class.

Parameters:
  • address – Endpoint address such as "tcp://127.0.0.1:5555".

  • host – TCP host helper used when address is omitted.

  • port – TCP port helper used when address is omitted.

  • path – Unix socket path helper used when address is omitted.

  • transport – Explicit transport selector.

property observation_space: Space[ValueT][source]

Observation space loaded from the remote environment contract.

property action_space: Space[ActionT][source]

Action space loaded from the remote environment contract.

reset(*, seed=None, options=None)[source]

Reset the remote environment and decode the observation.

Parameters:
  • seed (int | None) – Optional environment reset seed.

  • options (dict[str, object] | None) – Optional reset options forwarded to the environment.

Returns:

A decoded observation and reset info dictionary.

Return type:

tuple[ValueT, ResetInfo]

step(action)[source]

Step the remote environment with one encoded action.

Parameters:

action (ActionT) – Action accepted by the remote environment action space.

Returns:

Observation, reward, terminated flag, truncated flag, and step info.

Return type:

tuple[ValueT, float, bool, bool, StepInfo]

Vector Environment Base

class rlmesh._client.RemoteVectorEnvBase[source]

Bases: RemoteClientBase[ValueT, ActionT]

Base class for backend-specific vector-environment remote clients.

Backend modules such as rlmesh.numpy and rlmesh.torch configure the value bridge. User code should normally instantiate those concrete backends instead of this base class.

Parameters:
  • address – Endpoint address such as "tcp://127.0.0.1:5555".

  • host – TCP host helper used when address is omitted.

  • port – TCP port helper used when address is omitted.

  • path – Unix socket path helper used when address is omitted.

  • transport – Explicit transport selector.

property num_envs: int[source]

Number of environment instances served by the endpoint.

property single_observation_space: Space[ValueT][source]

Observation space for one environment in the vector.

property single_action_space: Space[ActionT][source]

Action space for one environment in the vector.

property observation_space: Space[ValueT][source]

Alias for single_observation_space.

property action_space: Space[ActionT][source]

Alias for single_action_space.

reset(*, seed=None, options=None)[source]

Reset all remote environments and decode the observations.

Parameters:
  • seed (int | list[int] | None) – Optional seed or per-environment seed list.

  • options (dict[str, object] | None) – Optional reset options forwarded to the vector environment.

Returns:

Batched decoded observations and reset info dictionary.

Return type:

tuple[ValueT, ResetInfo]

step(actions)[source]

Step all remote environments with a batch of actions.

Parameters:

actions (ActionT) – Batched actions accepted by the vector endpoint.

Returns:

Batched observations, rewards, terminations, truncations, and info.

Return type:

tuple[ValueT, ValueT, ValueT, ValueT, StepInfo]

Where next