Now liveThe Skillselion MCP - thousands of ranked skills, loaded into your agent mid-task. No install.Get it →
adithya-s-k avatar

Generate Openenv Env

  • 19 installs
  • 164 repo stars
  • Updated August 3, 2026
  • adithya-s-k/rl_envs_101

generate-openenv-env is a Claude Code skill that scaffolds an OpenEnv (Meta) variant of a reinforcement-learning environment, exposing tools via MCP over an HTTP FastAPI server.

About

This skill scaffolds an OpenEnv variant of a reinforcement-learning environment, Meta's HTTP server that exposes tools via the Model Context Protocol. It wraps a shared domain module into a FastAPI server with FastMCP-decorated tools discovered through list_tools, an optional Gradio UI, and sandbox-backed sessions. A developer uses it to port an env to OpenEnv, add MCP tools, or deploy it as a Docker container or HF Space.

  • Scaffolds an OpenEnv (Meta) variant of an RL environment for LLM agents
  • Exposes tools via the Model Context Protocol shape over an HTTP FastAPI server
  • Generates a runnable openenv folder with server app, environment class, Dockerfile, and rollout.py

Generate Openenv Env by the numbers

  • 19 all-time installs (skills.sh)
  • Ranked #10,579 of 16,546 AI & Agent Building skills by installs in the Skillselion catalog
  • Data as of Aug 5, 2026 (Skillselion catalog sync)
At a glance

generate-openenv-env capabilities & compatibility

Capabilities
rl env scaffold · mcp tooling · agent training env · code generation
Works with
docker
Use cases
api development · orchestration
Runs
Runs locally
Pricing
Free
From the docs

What generate-openenv-env says it does

OpenEnv is an HTTP server exposing tools via the **MCP** (Model Context Protocol) shape. The runtime is FastAPI; tools are FastMCP-decorated functions.
SKILL.md
Builds an OpenEnv (Meta) variant of an RL environment.
SKILL.md
npx skills add https://github.com/adithya-s-k/rl_envs_101 --skill generate-openenv-env

Add your badge

Show developers this skill is listed on Skillselion. Paste this into your README.

Listed on Skillselion
Installs19
repo stars164
Last updatedAugust 3, 2026
Repositoryadithya-s-k/rl_envs_101

What it does

Scaffold an OpenEnv (Meta) RL environment that exposes MCP tools over HTTP, with sandbox sessions and Docker/HF Space deployment for LLM-agent training.

Who is it for?

ML engineers building an MCP-based RL environment for LLM agents with sandbox sessions and container deployment.

Skip if: Users wanting inline per-step rewards or in-process envs, since OpenEnv computes reward externally and runs as an HTTP server.

When should I use this skill?

Someone asks to wrap an env in OpenEnv, make an MCP env, or add the openenv variant.

What you get

  • openenv/server/app.py
  • server/<env>_environment.py
  • pyproject.toml

By the numbers

  • Targets OpenEnv >= 0.2.3
  • Vision archetype models a 19-tool action surface on Anthropic's computer_20251124

Files

SKILL.mdMarkdownGitHub ↗

generate-openenv-env

Build the OpenEnv variant of an env. Targets OpenEnv >= 0.2.3 (openenv-core[core]).

Concept

OpenEnv is an HTTP server exposing tools via the MCP (Model Context Protocol) shape. The runtime is FastAPI; tools are FastMCP-decorated functions. Clients discover tools via list_tools() (under the hood: a list-tools action on /step) and call them via call_tool(name, **args).

When the user has a shared domain module (<domain>.py) and wants an OpenEnv variant, never duplicate domain logic into the framework folder — wrap it.

Archetypes (pick the one matching the task)

ArchetypeHallmarks
Pure-Python gameDeterministic, single @mcp.tool, text-only observations. Reward computed externally from the trajectory.
Stateful sandboxE2B / browser / DB, multiple tools mutating session state, MCPEnvironment per session.
Vision / computer-useScreenshots returned as MCP image content blocks (fastmcp.utilities.types.Image), 19-tool action surface modelled on Anthropic's computer_20251124, optional custom Gradio UI mounted at /web.

Recommended file layout

The user picks the actual paths. The canonical shape:

<env_dir>/openenv/
├── pyproject.toml      # openenv-core[core] + e2b-* + fastmcp + uvicorn + gradio
├── __init__.py
├── models.py           # Pydantic State / typed action / observation models
├── Dockerfile          # multi-stage from ghcr.io/meta-pytorch/openenv-base
├── openenv.yaml        # spec_version 1, name, runtime, app, port
├── server/
│   ├── __init__.py
│   ├── app.py          # create_app(EnvCls, CallToolAction, CallToolObservation, env_name=...)
│   └── <env>_environment.py    # MCPEnvironment subclass with @mcp.tool methods
├── rollout.py          # MCPToolClient drives the server; auto-discovers tools
└── README.md           # one-page; with HF frontmatter if deploying to Spaces

Implementation order (one continuous pass)

1. Pydantic state model — models.py

Subclass openenv.core.env_server.types.State. Add per-episode fields you'll mutate (step_count, last_output, sandbox/session ids, anything you want to inspect later).

For visual envs, add last_screenshot_b64. Don't store huge blobs unless you need them in state — use metadata on observations instead.

2. The MCPEnvironment — server/<name>_environment.py

class MyEnv(MCPEnvironment):
    SUPPORTS_CONCURRENT_SESSIONS = True   # only if real session isolation
    def __init__(self):
        # ... env-side state init
        mcp = FastMCP("my_env")
        @mcp.tool
        def my_tool(arg: int) -> str: ...
        super().__init__(mcp)

Key contracts:

  • Dual-import pattern. Inside server/, write try: from ..models import X; except ImportError: from models import X. Relative imports work inside the repo (PYTHONPATH=src:envs); flat imports work in Docker (/app/env). Same applies to sibling modules like e2b_sandbox.py.
  • Tool methods are @mcp.tool decorated functions inside __init__. They close over self and read/write env state. Don't try to put @mcp.tool on instance methods — FastMCP introspects free functions.
  • For images, use fastmcp.utilities.types.Image: return Image(data=png_bytes, format="png"). The model receives an MCP image content block. Returning a base64 string in text means the model is blind.
  • Lifecycle hooks: reset(seed=None, episode_id=None, **kwargs) returns an Observation; step(action, timeout_s=None, **kwargs) is inherited from MCPEnvironment for tool dispatch — only override if you need pre/post hooks (e.g. step-counter increment, terminate signal handling).

3. The FastAPI app — server/app.py

import os
from openenv.core.env_server.http_server import create_app
from openenv.core.env_server.mcp_types import CallToolAction, CallToolObservation
try:
    from .my_environment import MyEnv
    from .gradio_ui import my_ui_builder      # only if you have a custom UI
except ImportError:
    from server.my_environment import MyEnv
    from server.gradio_ui import my_ui_builder

def _custom_gradio_builder(*args, **kwargs):
    return my_ui_builder(env_factory=MyEnv)

os.environ["ENABLE_WEB_INTERFACE"] = "true"
app = create_app(
    MyEnv, CallToolAction, CallToolObservation,
    env_name="my_env",
    max_concurrent_envs=int(os.getenv("MAX_CONCURRENT_ENVS", "4")),
    gradio_builder=_custom_gradio_builder,   # omit if no custom UI
)

Pass the class to create_app, not an instantiated env.

4. Custom Gradio UI (optional, computer-use-style envs benefit)

server/gradio_ui.py defines my_ui_builder(env_factory) that returns a gr.Blocks. Mounted at /web (set base_path: /web in the HF Space frontmatter). For computer-use envs, the canonical pattern includes an iframe panel showing the E2B stream URL alongside text controls — but any gr.Blocks layout works.

5. The rollout — rollout.py

Use openenv.core.mcp_client.MCPToolClient. Discover tools, don't hardcode:

from openenv.core.mcp_client import MCPToolClient
with MCPToolClient(base_url=ENV_URL).sync() as env:
    env.reset()
    tools = env.list_tools()                 # list of ToolSpec
    # convert to OpenAI tool schemas, drive the LLM, call env.call_tool(name, **args)

Note: for image-returning tools, env.call_tool strips to result.data (which is None for image returns). Use env.step(CallToolAction(tool_name="screenshot", arguments={})) to get the full result dict, then read obs.result["content"][0]["data"] for the b64 image. Pattern:

def _call(env, name, **kwargs):
    out = env.step(CallToolAction(tool_name=name, arguments=kwargs))
    return out.observation.result or {}

def _b64_screenshot(env):
    res = _call(env, "screenshot")
    for c in res.get("content", []) or []:
        if c.get("type") == "image" and c.get("data"):
            return c["data"]
    raise RuntimeError(f"screenshot returned no image: {res}")

For multimodal models (Qwen3-VL, GPT-4o), feed the latest screenshot as an image block in the user message every turn.

6. The Dockerfile

Use a multi-stage build:

  • FROM ghcr.io/meta-pytorch/openenv-base:latest (the official base — already has FastAPI, MCP, Gradio).
  • uv sync twice (no-install-project, then with project) for cache friendliness.
  • Healthcheck via /health.
  • Expose port 8000.

For HF Spaces, the canonical app_port is 8000 (not 7860 — OpenEnv's pattern uses 8000). Set base_path: /web in the README frontmatter so Gradio mounts under that prefix.

7. The HF Space README frontmatter

---
title: My Env Server
emoji: 🤖
colorFrom: blue
colorTo: purple
sdk: docker
pinned: false
app_port: 8000
base_path: /web
tags: [openenv, your-domain]
short_description: One-line summary
---

Validation gates

Before declaring done, all four must pass:

1. In-repo importPYTHONPATH=envs uv run python -c "from envs.<name>.openenv.server.<name>_environment import <Cls>" 2. Local serveruv run uvicorn server.app:app --port 8000 then curl /health returns {"status":"healthy"} and /list_environments returns the env name. 3. Tool discoveryMCPToolClient.list_tools() returns the expected list. 4. RolloutMAX_TURNS=3 uv run python rollout.py runs without errors.

Common gotchas (from real-world OpenEnv work)

  • `KeyError: 'tools'` from POST /list_tools — OpenEnv doesn't expose /list_tools directly; MCPToolClient uses /step with a list-tools action under the hood. Always discover via the client.
  • Screenshot returns `None`env.call_tool("screenshot") returns only the structured data field. Use env.step(CallToolAction(...)) and read obs.result["content"].
  • `address already in use` — common during local-dev iteration. Just pick a different --port.
  • `ModuleNotFoundError` in Docker but works locally — missing dual-import pattern in server/app.py or server/<name>_environment.py.

Reference

  • references/architecture.md — full architecture deep-dive (when needed)

Official documentation

Related skills

FAQ

What is OpenEnv?

Meta's RL environment framework that is an HTTP FastAPI server exposing tools via the Model Context Protocol, with tool discovery through list_tools.

What does this skill output?

A runnable openenv folder with server/app.py, an environment class, pyproject.toml, a Dockerfile, and rollout.py.

AI & Agent Buildingagentsresearch

This week in AI coding

Five minutes, every Monday - the tools, releases and tactics for developers.

unsubscribe anytime.