Skip to content

[SKILL] add skill for generating env#429

Open
burtenshaw wants to merge 1 commit intomainfrom
feature/generate-env-skill
Open

[SKILL] add skill for generating env#429
burtenshaw wants to merge 1 commit intomainfrom
feature/generate-env-skill

Conversation

@burtenshaw
Copy link
Collaborator

This PR adds a skill to help agents generate openenv compatible envs.

@meta-cla meta-cla bot added the CLA Signed This label is managed by the Meta Open Source bot. label Mar 8, 2026
@burtenshaw burtenshaw requested a review from Darktex March 8, 2026 16:02
@greptile-apps
Copy link
Contributor

greptile-apps bot commented Mar 8, 2026

Greptile Summary

This PR adds a /generate-openenv-env skill that guides agents through building production-ready OpenEnv environments from a use-case prompt. It includes a structured 9-step SKILL.md workflow, a canonical template scaffold (assets/openenv_env_template/), reference documentation, and an OpenAI agent YAML. It also adds a .codex/skills symlink so Codex agents can discover the same skills. The skill fits cleanly into the existing .claude/skills/ architecture and integrates correctly with the alignment-review and pre-submit-pr pipelines.

Findings: The canonical template has 3 mechanical issues that should be fixed before merge:

  1. reset() signature — Missing seed, episode_id, and **kwargs parameters, violating the Gymnasium API invariant specified in INVARIANTS.md and SKILL.md §7. This will break all generated environments when training infrastructure passes these parameters.
  2. Exception handling — Catching Exception instead of ImportError masks real errors (SyntaxError, AttributeError) from the openenv module, degrading debuggability.
  3. Package name mismatchrequirements.txt specifies openenv[core]>=0.2.0 while pyproject.toml specifies openenv-core[core]>=0.2.1 (different names, different floors). This creates silent dependency divergence depending on which installation method is used.

Additionally, there is 1 alignment point for human review: the template sets SUPPORTS_CONCURRENT_SESSIONS=True but max_concurrent_envs=1, contradicting SKILL.md's requirement that these be coordinated. This warrants a design decision on whether the canonical template should support concurrent sessions.

Confidence Score: 1/5

  • Do not merge. The canonical template violates the Gymnasium API invariant (reset signature) which will break all generated environments. Additionally, critical dependencies are misaligned between requirements.txt and pyproject.toml.
  • The PR introduces a canonical scaffold that is the reference point for all generated environments. The reset() signature violation in the template is critical—every environment built from this template will be incompatible with training infrastructure that passes seed= or episode_id= arguments. The package name and version mismatch between requirements.txt and pyproject.toml creates silent dependency divergence. The exception handling issue masks real errors, degrading debuggability. The concurrency flag inconsistency is a design alignment point that should be resolved. These are fixable but must be addressed before merge.
  • .claude/skills/generate-openenv-env/assets/openenv_env_template/server/__ENV_NAME___environment.py (reset signature, concurrency flag), server/app.py (exception handling), server/requirements.txt (package name), and pyproject.toml (missing final newline).

Sequence Diagram

sequenceDiagram
    participant User
    participant Skill as /generate-openenv-env (SKILL.md)
    participant Template as assets/openenv_env_template/
    participant Refs as references/
    participant Repo as envs/<name>_env/

    User->>Skill: "generate an env for textarena"
    Skill->>Refs: Read openenv-tutorial-01-environments.md (Part 10)
    Skill->>Refs: Read openenv-docs-environment-builder.md
    Skill->>Refs: Read env-generation-checklist.md
    Skill->>Skill: Research target library API
    Skill->>Skill: Select archetype (typed / MCP / specialized)
    Skill->>Skill: openenv init <name>_env --output-dir envs
    note over Skill: Falls back to manual scaffold if CLI unavailable
    Skill->>Template: Copy files as reference
    Template-->>Repo: models.py, client.py, server/, openenv.yaml
    Skill->>Repo: Implement reset(), step(), state()
    Skill->>Repo: Implement _step_payload(), _parse_result()
    Skill->>Repo: openenv build && openenv validate --verbose
    Repo-->>User: Scaffold + validation report
Loading

Last reviewed commit: 3e2fddf

Comment on lines +53 to +68
def reset(self) -> __ENV_CLASS_NAME__Observation:
"""
Reset the environment.

Returns:
__ENV_CLASS_NAME__Observation with a ready message
"""
self._state = State(episode_id=str(uuid4()), step_count=0)
self._reset_count += 1

return __ENV_CLASS_NAME__Observation(
echoed_message="__ENV_TITLE_NAME__ environment ready!",
message_length=0,
done=False,
reward=0.0,
)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Template reset() violates Gymnasium API invariant

INVARIANTS.md specifies the required signature as reset(seed?, episode_id?) -> Observation. The template's reset(self) has no parameters, so every environment scaffolded from this template will be incompatible with training orchestration code that passes seed= or episode_id= (e.g., the EnvPool helpers). This is the canonical scaffold, so the problem will propagate to all generated environments.

SKILL.md (§7) also explicitly states: "Prefer reset/step signatures compatible with Environment: reset(seed=None, episode_id=None, **kwargs)".

Suggested change
def reset(self) -> __ENV_CLASS_NAME__Observation:
"""
Reset the environment.
Returns:
__ENV_CLASS_NAME__Observation with a ready message
"""
self._state = State(episode_id=str(uuid4()), step_count=0)
self._reset_count += 1
return __ENV_CLASS_NAME__Observation(
echoed_message="__ENV_TITLE_NAME__ environment ready!",
message_length=0,
done=False,
reward=0.0,
)
def reset(self, seed=None, episode_id=None, **kwargs) -> __ENV_CLASS_NAME__Observation:

Rule Used: .claude/docs/INVARIANTS.md (source)

Prompt To Fix With AI
This is a comment left during a code review.
Path: .claude/skills/generate-openenv-env/assets/openenv_env_template/server/__ENV_NAME___environment.py
Line: 53-68

Comment:
**Template reset() violates Gymnasium API invariant**

`INVARIANTS.md` specifies the required signature as `reset(seed?, episode_id?) -> Observation`. The template's `reset(self)` has no parameters, so every environment scaffolded from this template will be incompatible with training orchestration code that passes `seed=` or `episode_id=` (e.g., the `EnvPool` helpers). This is the canonical scaffold, so the problem will propagate to all generated environments.

`SKILL.md` (§7) also explicitly states: "Prefer reset/step signatures compatible with `Environment`: `reset(seed=None, episode_id=None, **kwargs)`".

```suggestion
    def reset(self, seed=None, episode_id=None, **kwargs) -> __ENV_CLASS_NAME__Observation:
```

**Rule Used:** .claude/docs/INVARIANTS.md ([source](https://app.greptile.com/review/custom-context?memory=dbd1ab5e-bd4d-4701-9de0-9817404155a9))

How can I resolve this? If you propose a fix, please make it concise.

Comment on lines +42 to +46
# Enable concurrent WebSocket sessions.
# Set to True if your environment isolates state between instances.
# When True, multiple WebSocket clients can connect simultaneously, each
# getting their own environment instance (when using factory mode in app.py).
SUPPORTS_CONCURRENT_SESSIONS: bool = True
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ALIGNMENT FLAG: SUPPORTS_CONCURRENT_SESSIONS inconsistent with max_concurrent_envs

The template sets SUPPORTS_CONCURRENT_SESSIONS: bool = True, but server/app.py uses max_concurrent_envs=1. SKILL.md (line 119) explicitly states: "Set SUPPORTS_CONCURRENT_SESSIONS=True only when isolation is real. Set max_concurrent_envs in create_app accordingly (1 when False, >1 when True)". Having both set in contradictory directions signals opposing concurrency intent.

  • Principle at stake: "One canonical way to build environments" (PRINCIPLES.md) / be hands-on
  • The concern: Agents copying this template will carry forward a contradiction—they'll see SUPPORTS_CONCURRENT_SESSIONS=True but be unable to run multiple sessions
  • Suggested reviewer: @Darktex

Align by choosing one:
Option A: Set SUPPORTS_CONCURRENT_SESSIONS = False (matches max_concurrent_envs=1)
Option B: Change app.py to use max_concurrent_envs=4 (matches True)

For a generic echo-style template, Option A (False/1) is the safer default.

Suggested change
# Enable concurrent WebSocket sessions.
# Set to True if your environment isolates state between instances.
# When True, multiple WebSocket clients can connect simultaneously, each
# getting their own environment instance (when using factory mode in app.py).
SUPPORTS_CONCURRENT_SESSIONS: bool = True
# Set to True only when your environment isolates state between instances
# and you set max_concurrent_envs > 1 in server/app.py.
SUPPORTS_CONCURRENT_SESSIONS: bool = False

Rule Used: .claude/docs/PRINCIPLES.md (source)

Prompt To Fix With AI
This is a comment left during a code review.
Path: .claude/skills/generate-openenv-env/assets/openenv_env_template/server/__ENV_NAME___environment.py
Line: 42-46

Comment:
**ALIGNMENT FLAG: SUPPORTS_CONCURRENT_SESSIONS inconsistent with max_concurrent_envs**

The template sets `SUPPORTS_CONCURRENT_SESSIONS: bool = True`, but `server/app.py` uses `max_concurrent_envs=1`. `SKILL.md` (line 119) explicitly states: "Set `SUPPORTS_CONCURRENT_SESSIONS=True` only when isolation is real. Set `max_concurrent_envs` in `create_app` accordingly (1 when `False`, >1 when `True`)". Having both set in contradictory directions signals opposing concurrency intent.

- **Principle at stake**: "One canonical way to build environments" (PRINCIPLES.md) / be hands-on
- **The concern**: Agents copying this template will carry forward a contradiction—they'll see `SUPPORTS_CONCURRENT_SESSIONS=True` but be unable to run multiple sessions
- **Suggested reviewer**: @darktex

Align by choosing one:  
Option A: Set `SUPPORTS_CONCURRENT_SESSIONS = False` (matches `max_concurrent_envs=1`)  
Option B: Change `app.py` to use `max_concurrent_envs=4` (matches `True`)  

For a generic echo-style template, Option A (False/1) is the safer default.

```suggestion
    # Set to True only when your environment isolates state between instances
    # and you set max_concurrent_envs > 1 in server/app.py.
    SUPPORTS_CONCURRENT_SESSIONS: bool = False
```

**Rule Used:** .claude/docs/PRINCIPLES.md ([source](https://app.greptile.com/review/custom-context?memory=67b96369-b31e-4918-84c9-a0a4e3c8aa97))

How can I resolve this? If you propose a fix, please make it concise.

Comment on lines +31 to +36
try:
from openenv.core.env_server.http_server import create_app
except Exception as e: # pragma: no cover
raise ImportError(
"openenv is required for the web interface. Install dependencies with '\n uv sync\n'"
) from e
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Overly broad exception catch

except Exception as e will swallow errors that are not import failures (e.g., AttributeError, SyntaxError in the openenv module itself), masking the real error and making debugging much harder. Since the intent is only to catch missing-dependency scenarios, this should be except ImportError.

Suggested change
try:
from openenv.core.env_server.http_server import create_app
except Exception as e: # pragma: no cover
raise ImportError(
"openenv is required for the web interface. Install dependencies with '\n uv sync\n'"
) from e
try:
from openenv.core.env_server.http_server import create_app
except ImportError as e: # pragma: no cover
raise ImportError(
"openenv is required for the web interface. Install dependencies with '\n uv sync\n'"
) from e
Prompt To Fix With AI
This is a comment left during a code review.
Path: .claude/skills/generate-openenv-env/assets/openenv_env_template/server/app.py
Line: 31-36

Comment:
**Overly broad exception catch**

`except Exception as e` will swallow errors that are not import failures (e.g., `AttributeError`, `SyntaxError` in the openenv module itself), masking the real error and making debugging much harder. Since the intent is only to catch missing-dependency scenarios, this should be `except ImportError`.

```suggestion
try:
    from openenv.core.env_server.http_server import create_app
except ImportError as e:  # pragma: no cover
    raise ImportError(
        "openenv is required for the web interface. Install dependencies with '\n    uv sync\n'"
    ) from e
```

How can I resolve this? If you propose a fix, please make it concise.

Comment on lines +1 to +3
openenv[core]>=0.2.0
fastapi>=0.115.0
uvicorn>=0.24.0
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Package name and version mismatch with pyproject.toml

requirements.txt specifies openenv[core]>=0.2.0, but pyproject.toml specifies openenv-core[core]>=0.2.1. These are two different package names with different minimum versions. Since the Dockerfile uses uv sync (which reads pyproject.toml), the requirements.txt is most likely to be used by developers or pip install -r — creating silent environment differences and confusion.

The package name should be aligned. Based on pyproject.toml and the SKILL.md docs (which reference openenv-core[core]), the correct name is openenv-core:

Suggested change
openenv[core]>=0.2.0
fastapi>=0.115.0
uvicorn>=0.24.0
openenv-core[core]>=0.2.1
fastapi>=0.115.0
uvicorn>=0.24.0

Note: pyproject.toml also lacks a newline at end of file.

Prompt To Fix With AI
This is a comment left during a code review.
Path: .claude/skills/generate-openenv-env/assets/openenv_env_template/server/requirements.txt
Line: 1-3

Comment:
**Package name and version mismatch with pyproject.toml**

`requirements.txt` specifies `openenv[core]>=0.2.0`, but `pyproject.toml` specifies `openenv-core[core]>=0.2.1`. These are two different package names with different minimum versions. Since the Dockerfile uses `uv sync` (which reads `pyproject.toml`), the `requirements.txt` is most likely to be used by developers or `pip install -r` — creating silent environment differences and confusion.

The package name should be aligned. Based on `pyproject.toml` and the SKILL.md docs (which reference `openenv-core[core]`), the correct name is `openenv-core`:

```suggestion
openenv-core[core]>=0.2.1
fastapi>=0.115.0
uvicorn>=0.24.0
```

**Note**: `pyproject.toml` also lacks a newline at end of file.

How can I resolve this? If you propose a fix, please make it concise.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

CLA Signed This label is managed by the Meta Open Source bot.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant