Environment Contract

The Gymnasium-style environment shape RLMesh serves and the contract clients receive on connect.

RLMesh follows the Gymnasium reset/step contract. Any environment that implements this shape can be served over an endpoint. Environments created with gym.make(...) work as-is, and custom objects only need to match the same surface.

observation, info = env.reset(seed=42, options=None)
observation, reward, terminated, truncated, info = env.step(action)

Environment shape

An environment exposes its spaces alongside the lifecycle methods:

class Env:
    observation_space = ...
    action_space = ...

    def reset(self, seed=None, options=None):
        ...

    def step(self, action):
        ...

    def close(self):
        ...

RLMesh reads the two spaces and drives reset, step, and close. Vectorized environments can additionally expose num_envs, single_observation_space, and single_action_space. See Connect a Client for how those are served and consumed.

Common Gymnasium wrappers can stay in place. RLMesh reads the spaces and drives the wrapped environment through the normal Gymnasium API, so a wrapper stack behaves the same locally and behind a server.

Serving the contract

When EnvServer wraps an environment it derives an environment contract from the spaces and metadata. That contract is what travels to clients:

server = rlmesh.EnvServer(env, "127.0.0.1:5555")
contract = server.env_contract

print(contract.id)
print(contract.observation_space.kind)
print(contract.action_space.kind)
print(contract.num_envs)

server.spec is an alias for server.env_contract. See Serving Environments for the full serving workflow.

Remote contract

On connect, a client receives the environment contract before any step runs. It carries:

  • environment id and metadata
  • render mode
  • number of environments
  • observation space
  • action space
from rlmesh.numpy import RemoteEnv

env = RemoteEnv("127.0.0.1:5555")
print(env.env_contract)
print(env.observation_space)
print(env.action_space)
env.close()

Because the contract arrives up front, a remote client can validate shapes and dtypes without taking a step. Observation and action values cross the RLMesh protocol as transport values and are decoded by whichever backend adapter the client chose — see Spaces and Values for how that decoding works, and Remote Clients for the client side of the connection.