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

Generate Ors Env

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

generate-ors-env is a Claude Code skill that scaffolds an Open Reward Standard (ORS) variant of a reinforcement-learning environment using the openreward package, with inline per-tool-call rewards over REST and SSE.

About

This skill scaffolds an Open Reward Standard (ORS) variant of a reinforcement-learning environment using the official openreward package. ORS is an HTTP REST plus Server-Sent Events protocol where reward arrives inline with every tool output, unlike post-episode grading. A developer uses it to wrap an env in ORS, add per-call rewards, or deploy to OpenReward.ai or HF Spaces.

  • Scaffolds an Open Reward Standard (ORS) variant of an RL environment using the openreward package
  • Uses HTTP REST plus Server-Sent Events with reward arriving inline on every tool output
  • Generates a runnable ors folder with server.py, tasks.py, Dockerfile.spaces, and rollout.py

Generate Ors Env by the numbers

  • 18 all-time installs (skills.sh)
  • Ranked #10,710 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-ors-env capabilities & compatibility

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

What generate-ors-env says it does

ORS is the Open Reward Standard ([openrewardstandard.io](https://openrewardstandard.io)) — an HTTP REST + Server-Sent Events protocol for agent envs.
SKILL.md
Reward arrives **inline** with every `ToolOutput`, which is the framework's defining feature
SKILL.md
npx skills add https://github.com/adithya-s-k/rl_envs_101 --skill generate-ors-env

Add your badge

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

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

What it does

Scaffold an Open Reward Standard RL environment with REST+SSE and inline per-tool-call rewards for LLM-agent training and OpenReward.ai deployment.

Who is it for?

ML engineers who need an RL environment with per-tool-call inline rewards deployable to OpenReward.ai or HF Spaces.

Skip if: Users wanting post-episode-only grading or non-HTTP envs, since ORS delivers reward inline over REST+SSE.

When should I use this skill?

Someone asks to wrap an env in ORS, make an OpenReward env, or add per-call reward to an env.

What you get

  • ors/server.py
  • tasks.py
  • pyproject.toml

By the numbers

  • Requires openreward >= 0.1.33
  • Wire protocol exposes 8 REST/SSE endpoints for envs, tools, splits, tasks, prompt, and sessions

Files

SKILL.mdMarkdownGitHub ↗

generate-ors-env

Build the ORS variant of an env using the official `openreward >= 0.1.33` package (the ors-sdk name is a common mistake — it does not exist on PyPI).

Concept

ORS is the Open Reward Standard (openrewardstandard.io) — an HTTP REST + Server-Sent Events protocol for agent envs. Reward arrives inline with every ToolOutput, which is the framework's defining feature compared to OpenEnv (external/post-hoc reward) and NeMo Gym (post-episode /verify).

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

Archetypes

ArchetypeHallmarks
Pure-Python gameSingle @tool, tasks.py with N task dicts forming the train split, terminal reward via finished=True.
Stateful sandboxsetup() allocates resources from task_spec; teardown() frees them; per-tool reward stubs.
Vision / computer-useImageBlock(data=<base64>, mimeType="image/png") returns; terminate(status) tool emits the terminal reward.

Imports — exactly these

Server side:

from openreward.environments import (
    Environment, Server, tool, ToolOutput, TextBlock, Split, ImageBlock,
)

Client side (rollouts):

from openreward import EnvironmentsAPI
api = EnvironmentsAPI(base_url=URL, api_key="")
env = api.get(ENV_NAME)
Don't use `OpenReward(api_key=..., base_url=...)` even though it's the high-level client. It prepends matrix. / api. / construct. subdomains to the base URL — that breaks HF Space URLs. EnvironmentsAPI talks to base_url verbatim.

Architecture

<env_dir>/ors/
├── pyproject.toml         # openreward>=0.1.33 + e2b-* (if needed) + pydantic
├── __init__.py
├── Dockerfile             # local dev image
├── Dockerfile.spaces      # HF Space (port 7860, single-stage pip install)
├── README.spaces.md       # HF Space frontmatter
├── server.py              # the Environment subclass + main()
├── tasks.py               # list of dicts (task_spec for each task)
├── rollout.py             # or rollout_openai.py + rollout_qwen.py
└── README.md              # one-page dev README

Implementation order

1. Tasks file — tasks.py

A list of plain dicts. Each dict becomes a task_spec per session. ORS auto-wraps these into Task objects on list_tasks().

TASKS = [
    {"answer": "apple", "task": "Guess the 5-letter word."},
    # ...
]

2. The Environment subclass — server.py

from pydantic import BaseModel
from openreward.environments import Environment, Server, tool, ToolOutput, TextBlock, Split

class GuessInput(BaseModel):
    word: str

class WordleORS(Environment):
    def __init__(self, task_spec=None, secrets=None, **kw):
        super().__init__(task_spec=task_spec or {}, secrets=secrets or {})
        self._game = None

    def setup(self):                      # called on first tool invocation
        self._game = WordleGame(self.task_spec.get("answer"))

    def teardown(self):                   # called on session delete
        self._game = None

    @classmethod
    def list_splits(cls): return [Split(name="train", type="train")]

    @classmethod
    def list_tasks(cls, split): return TASKS

    def get_prompt(self):
        return [TextBlock(text="Play Wordle. Guess the 5-letter word.")]

    @tool
    def guess(self, params: GuessInput) -> ToolOutput:
        feedback = self._game.guess(params.word)
        return ToolOutput(
            blocks=[TextBlock(text=feedback)],
            reward=self._game.reward,
            finished=self._game.done,
        )

Key contracts:

  • Tools take a `params: PydanticModel` as the second arg. ORS uses the model's JSON schema as the tool's input_schema.
  • Empty inputs still need a Pydantic model (class _Empty(BaseModel): pass). Don't omit the param.
  • `ToolOutput.blocks` is [TextBlock | ImageBlock]. For images: ImageBlock(data=<base64>, mimeType="image/png"). Vision models actually see this.
  • `reward` is float | None. None means "no reward this step"; 0.0 means "stepped, scored zero". For pure terminal reward, return None everywhere except in the last ToolOutput.
  • `finished=True` ends the session. Pair with reward=1.0 (or whatever) to give the rollout a clean stop.
  • `task_spec` is a dict you read from self.task_spec — no schema validation. If you want validation, do it in setup().

3. Server entry point — server.py main

def main():
    parser = argparse.ArgumentParser()
    parser.add_argument("--port", type=int, default=8080)
    parser.add_argument("--host", type=str, default="0.0.0.0")
    args = parser.parse_args()
    Server([WordleORS]).run(host=args.host, port=args.port)

The endpoint name is auto-derived from the class name lowercased — WordleORSwordleors. Tell the user this so they know what ENV_NAME to pass.

4. Rollout

Always discover tools and tasks from the env. Don't hardcode names:

api = EnvironmentsAPI(base_url=ENV_URL, api_key="")
env = api.get("wordleors")
tasks = env.list_tasks("train")
tools = env.list_tools(format="openai")     # built-in OpenAI tool-schema converter
with env.session(task=tasks[0]) as session:
    prompt = session.get_prompt()
    result = session.call_tool("guess", {"word": "crane"})
    # result.blocks, result.reward, result.finished

For vision envs, the screenshot tool returns an ImageBlock — read it as b.data (already base64). Pass that into the model's image content.

5. Dockerfiles

Dockerfile.spaces is the HF Space deploy image. Keep it minimal:

FROM python:3.11-slim
RUN useradd -m -u 1000 user
RUN pip install --no-cache-dir openreward pydantic <other-deps>
USER user
ENV HOME=/home/user PATH=/home/user/.local/bin:$PATH
WORKDIR $HOME/app
COPY --chown=user . $HOME/app
EXPOSE 7860
CMD ["python", "server.py", "--host", "0.0.0.0", "--port", "7860"]

README.spaces.md:

---
title: My Env ORS
emoji: 🎯
colorFrom: pink
colorTo: indigo
sdk: docker
app_port: 7860
tags: [ors, openreward]
---

Pushing to HF Spaces

Create a Space named <owner>/<env_name>-ors. Set E2B_API_KEY (and any other secrets) as Space secrets, not environment variables — they survive rebuilds. The local .env file should not be uploaded.

api.add_space_secret(repo_id="<owner>/<env>-ors", key="E2B_API_KEY", value="...")
api.upload_file(path_or_fileobj="Dockerfile.spaces", path_in_repo="Dockerfile", repo_id=...)
api.upload_file(path_or_fileobj="README.spaces.md", path_in_repo="README.md", repo_id=...)
# upload server.py, tasks.py, __init__.py, pyproject.toml

Validation gates

1. Local serveruv run python server.py --port 8772 then curl http://localhost:8772/list_environments returns ["<envname>"]. 2. Tool discoverycurl http://localhost:8772/<envname>/tools | jq '.tools | length' matches the number of @tool methods. 3. End-to-endMAX_TURNS=3 uv run python rollout.py drives the model through at least one tool call without errors.

Gotchas (from real-world ORS work)

  • `from openreward.environments.types import Task` — wrong; Task is in openreward.api.environments.types and you usually don't import it. list_tasks can return plain dicts; ORS wraps them.
  • `OpenReward(base_url=URL)` rewrites the URL — prepends matrix. / api. / construct. subdomains. For HF Spaces, use EnvironmentsAPI(base_url=URL, api_key="") directly.
  • `e2b-desktop` without `e2b`e2b-desktop imports from e2b, but doesn't pin it. Add both to dependencies.
  • Endpoint name is the lowercased class nameMyEnvORS becomes myenvors. Tell users this explicitly so their ENV_NAME env var is right.

Reference

  • references/architecture.md — protocol shape + Server / Environment / Session lifecycle

Official documentation

Related skills

FAQ

What is Open Reward Standard?

An HTTP REST plus Server-Sent Events protocol for agent RL environments where reward arrives inline with every tool output rather than post-episode.

Which package does this skill use?

The official openreward package (>= 0.1.33); note ors-sdk does not exist on PyPI.

AI & Agent Buildingagentsresearch

This week in AI coding

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

unsubscribe anytime.