# OpenEnv CLI Commands: Complete Guide to init, push, serve, build, and validate

> Master OpenEnv CLI commands init, push, serve, build, and validate. Scaffold, containerize, and deploy RL environments with this comprehensive guide and IaC workflow.

- Repository: [Hugging Face/OpenEnv](https://github.com/huggingface/OpenEnv)
- Tags: how-to-guide
- Published: 2026-06-15

---

**The OpenEnv CLI provides five essential commands—`init`, `build`, `push`, `validate`, and `serve`—that scaffold, containerize, verify, and deploy Gym-like reinforcement learning environments using a declarative infrastructure-as-code workflow.**

The OpenEnv framework from Hugging Face enables developers to package reinforcement learning environments as containerized microservices that expose a standard Gym-compatible API. Mastering these OpenEnv CLI commands allows you to manage the complete lifecycle of environment-as-code projects, from initial project generation to remote registry deployment.

## CLI Architecture and Core Design

The OpenEnv CLI is built on **Typer** and follows a strict separation of concerns between client-side orchestration and server-side execution. Located in `src/openenv/cli/commands/`, each command acts as a thin wrapper around the core library (`src/openenv/core/`), delegating heavy lifting to specialized providers while preserving the client-server boundary.

The architecture centers on the **MCP (Message-Control-Protocol)** layer defined in [`openenv.core.env_server.mcp_types.py`](https://github.com/huggingface/OpenEnv/blob/main/openenv.core.env_server.mcp_types.py). When you execute CLI commands, they interact with the runtime through `openenv.core.env_client.EnvClient`, which communicates with containerized environments via WebSocket endpoints exposed by `openenv.core.env_server.http_server`.

## Command: init

The `init` command scaffolds a new OpenEnv project with all necessary configuration files and starter code. Implemented in [`src/openenv/cli/commands/init.py`](https://github.com/huggingface/OpenEnv/blob/main/src/openenv/cli/commands/init.py), this command performs strict validation and template generation.

When you run:

```bash
openenv init my_env

```

The command executes the following operations:

- **Name validation** via `_validate_env_name()` to ensure `my_env` is a valid snake_case identifier
- **Template rendering** that creates [`my_env/openenv.yaml`](https://github.com/huggingface/OpenEnv/blob/main/my_env/openenv.yaml), [`pyproject.toml`](https://github.com/huggingface/OpenEnv/blob/main/pyproject.toml), `Dockerfile`, and [`my_env_environment.py`](https://github.com/huggingface/OpenEnv/blob/main/my_env_environment.py)
- **Metadata injection** using `_get_random_hf_space_config()` to populate Hugging Face Space attributes (emoji, colour palette) in [`openenv.yaml`](https://github.com/huggingface/OpenEnv/blob/main/openenv.yaml)

The resulting project structure includes:

```

my_env/
├── openenv.yaml            # Environment metadata and runtime config

├── pyproject.toml          # Python dependencies

├── my_env_environment.py   # EnvServer implementation stub

└── Dockerfile              # Container definition

```

## Command: build

The `build` command compiles your environment into a containerized artifact ready for execution or distribution. Found in [`src/openenv/cli/commands/build.py`](https://github.com/huggingface/OpenEnv/blob/main/src/openenv/cli/commands/build.py), it supports multiple runtime backends through the container abstraction layer.

By default, the build process utilizes [`src/openenv/core/containers/runtime/uv_provider.py`](https://github.com/huggingface/OpenEnv/blob/main/src/openenv/core/containers/runtime/uv_provider.py) to create lightweight images without a full Docker daemon, though standard Docker builds are also supported. The command produces an image tagged `openenv-my-env:latest` that bundles your environment code with the OpenEnv server entry point (`openenv serve`).

```bash
cd my_env
openenv build

```

The build system reads [`openenv.yaml`](https://github.com/huggingface/OpenEnv/blob/main/openenv.yaml) to determine the runtime configuration and ensures the server module is importable within the container context.

## Command: push

Once built, the `push` command handles registry authentication and image distribution. Located in [`src/openenv/cli/commands/push.py`](https://github.com/huggingface/OpenEnv/blob/main/src/openenv/cli/commands/push.py), it wraps Docker CLI operations via `subprocess.run` to tag and upload your environment to remote registries including Hugging Face Spaces, Docker Hub, or private repositories.

```bash
openenv push --registry docker.io --repo youruser/openenv-my-env

```

This command automatically tags the local image with the target repository URI and handles the push authentication flow. Upon successful completion, it returns the full image URI for use in deployment manifests or client connection strings.

## Command: validate

Before building or pushing, the `validate` command verifies that your environment conforms to the OpenEnv schema and runtime requirements. Implemented in [`src/openenv/cli/commands/validate.py`](https://github.com/huggingface/OpenEnv/blob/main/src/openenv/cli/commands/validate.py), it performs static analysis of your project structure.

Running `openenv validate` executes these checks:

- **Schema validation** of [`openenv.yaml`](https://github.com/huggingface/OpenEnv/blob/main/openenv.yaml) to confirm required fields (name, version, runtime) are present and correctly typed
- **Code verification** that [`my_env_environment.py`](https://github.com/huggingface/OpenEnv/blob/main/my_env_environment.py) contains a class named `EnvServer` inheriting from `openenv.core.env_server.base_transforms.BaseEnv`
- **Dependency analysis** of [`pyproject.toml`](https://github.com/huggingface/OpenEnv/blob/main/pyproject.toml) to ensure server-side dependencies are correctly declared

This validation catches configuration errors early in the development cycle, preventing failed builds or runtime protocol mismatches.

## Command: serve

The `serve` command currently exists as a placeholder in [`src/openenv/cli/commands/serve.py`](https://github.com/huggingface/OpenEnv/blob/main/src/openenv/cli/commands/serve.py) for future local development workflows. While the full implementation is pending, the command provides guidance for current local testing strategies.

```bash
openenv serve --port 8080 --reload

```

Currently, this outputs recommended alternatives:

1. **Docker-based local serving**: `openenv build && docker run -p 8080:8080 openenv-my-env:latest`
2. **Uv-based development**: `uv run --project . server --port 8080`

The future implementation will directly launch the WebSocket server via `uv run server`, enabling rapid local iteration without container overhead by leveraging the same `openenv.core.env_server.http_server` module used in production containers.

## Complete Development Workflow

A typical OpenEnv project lifecycle combines these commands in sequence:

```bash

# 1. Scaffold the project

openenv init my_env

# 2. Navigate and implement your environment logic

cd my_env

# Edit my_env_environment.py to implement your Gym-like logic

# 3. Validate configuration before building

openenv validate

# 4. Build the container image

openenv build

# 5. Push to remote registry for distribution

openenv push --registry docker.io --repo youruser/openenv-my-env

```

Each step leverages the core library's abstractions: `init` uses the auto-generation helpers in [`src/openenv/auto/auto_env.py`](https://github.com/huggingface/OpenEnv/blob/main/src/openenv/auto/auto_env.py), while `build` and `push` interface with the container runtime abstraction layer in `src/openenv/core/containers/runtime/`.

## Summary

- **OpenEnv CLI commands** manage the full lifecycle of RL environments through five specialized operations: `init`, `build`, `validate`, `push`, and `serve`.
- The **init** command in [`src/openenv/cli/commands/init.py`](https://github.com/huggingface/OpenEnv/blob/main/src/openenv/cli/commands/init.py) scaffolds projects with validated names, random HF Space metadata, and Docker configurations.
- **Build** and **push** operations in their respective command files handle containerization and registry distribution, supporting both Docker and uv-based runtimes.
- **Validate** ensures schema compliance and proper inheritance from `BaseEnv` before deployment.
- **Serve** remains a placeholder pending direct uv-based local server execution, currently directing users to Docker or manual uv workflows.
- All commands communicate with the underlying `EnvClient` and MCP protocol layer, maintaining strict separation between CLI orchestration and server-side environment execution.

## Frequently Asked Questions

### What is the difference between `build` and `push` in OpenEnv?

The `build` command compiles your environment source into a container image using either Docker or the uv provider, creating a local artifact tagged `openenv-my-env:latest`. The `push` command then takes this local image, tags it with a remote registry URI, and uploads it to a container registry such as Docker Hub or Hugging Face Spaces. You must build before pushing, as the push command expects the local image to exist.

### Why is the `serve` command not fully implemented yet?

According to the source code in [`src/openenv/cli/commands/serve.py`](https://github.com/huggingface/OpenEnv/blob/main/src/openenv/cli/commands/serve.py), the `serve` command is currently a placeholder indicating future functionality. The OpenEnv team plans to implement direct local serving using `uv run server` to launch the WebSocket server without Docker overhead. Until then, the command provides documented workarounds using Docker (`openenv build && docker run`) or direct uv execution (`uv run --project . server`).

### How does OpenEnv validate that my environment is correctly configured?

The `validate` command in [`src/openenv/cli/commands/validate.py`](https://github.com/huggingface/OpenEnv/blob/main/src/openenv/cli/commands/validate.py) performs two primary checks: it parses [`openenv.yaml`](https://github.com/huggingface/OpenEnv/blob/main/openenv.yaml) to verify required metadata fields (name, version, runtime) are present, and it inspects your generated server module to confirm it contains an `EnvServer` class that properly inherits from `openenv.core.env_server.base_transforms.BaseEnv`. This ensures compatibility with the MCP protocol and client-side `EnvClient` expectations.

### What container runtimes does OpenEnv support?

OpenEnv supports an extensible runtime architecture defined in `src/openenv/core/containers/runtime/`. Currently, it includes a **Docker runtime** for standard container builds and a **uv provider** ([`uv_provider.py`](https://github.com/huggingface/OpenEnv/blob/main/uv_provider.py)) for lightweight, Python-native containerization without a full Docker daemon. Additional runtimes such as Kubernetes or Daytona can be integrated by implementing the abstract base class in the runtime module.