generate-openenv-env
/generate-openenv-env
Build a production-ready OpenEnv environment from a use-case prompt.
Execute Workflow
When invoked, execute this workflow end-to-end.
1. Parse the use case and name the environment
Derive a repo path in the form envs/<name>_env/.
- Normalize to snake_case.
- Keep names short and domain-specific.
- Example: "generate an env for the library textarena" ->
envs/textarena_env/.
2. Research the target library/API before coding
Gather the minimum interface facts needed to implement reset, step, and state serialization.
- Search local docs/examples first.
- Search upstream docs/repo for the target library when local context is insufficient.
- Extract only implementation-critical details:
- installation/dependency requirements
- environment creation API
- action format
- observation format
- reward and done semantics
- special setup (model files, downloads, auth, etc.)
3. Mine matching OpenEnv examples
Select 2-3 existing environments as implementation templates.
- Always read
references/openenv-tutorial-01-environments.md(Part 10) andreferences/openenv-docs-environment-builder.md. - Prefer
envs/textarena_envfor external-library wrappers with richer state. - Add one simpler baseline (for example
envs/snake_envorenvs/echo_env) to keep the implementation minimal. - Follow patterns, do not copy blindly.
- Exclude generated or vendored files when mining examples (
.venv/,build/,site-packages/,__pycache__/).
For a compact checklist and mapping, read references/env-generation-checklist.md.
4. Ask focused implementation questions
Ask only the questions that materially affect architecture. Use the question bank in references/env-generation-checklist.md.
Cover at least:
- action space contract
- observation fields needed by agents
- reward design and terminal conditions
- episode/session configuration knobs
- deployment target and dependency constraints
If answers are unavailable, proceed with explicit assumptions and document them.
5. Choose the environment archetype
Choose one archetype before scaffolding:
- Typed step/reset environment (default): use
EnvClient+ typedAction/Observation[/State]models. - MCP tool environment: use
MCPEnvironment+MCPToolClientand MCP action/observation types. - Specialized client flow (rare): only when the standard clients cannot express required behavior (for example local+remote hybrid clients).
6. Scaffold the environment
Use the CLI to scaffold:
PYTHONPATH=src uv run openenv init <name>_env --output-dir envs
This generates all files with correct placeholders replaced, including pyproject.toml, Dockerfile, and uv.lock.
If the CLI is unavailable (import errors, missing dependencies), create the structure manually matching:
envs/<name>_env/
├── __init__.py
├── client.py
├── models.py
├── openenv.yaml
├── pyproject.toml
└── server/
├── __init__.py
├── app.py
├── <name>_environment.py
└── Dockerfile
Use assets/openenv_env_template/ as a reference for file contents when scaffolding manually.
7. Implement with OpenEnv contracts
Implement these files in order:
models.pyserver/<name>_environment.pyserver/app.pyclient.pyopenenv.yamlREADME.md
Use these standards:
- Use typed models (Action/Observation/State).
- Use
create_app(<factory_or_class>, ActionType, ObservationType, env_name=...)inserver/app.py. Pass a class or factory callable, not an instantiated environment. - Dual-import pattern (required in
server/app.pyandserver/<name>_environment.py): Usetry: from ..models import X / except ImportError: from models import X. Relative imports work in-repo (PYTHONPATH=src:envs); bare imports work in Docker (PYTHONPATH=/app/env). The same pattern applies to intra-server imports (e.g.,from .foo import Barvsfrom server.foo import Bar). client.pyusesEnvClient[ActionType, ObservationType, State](three type parameters).- Keep server logic in
server/, keep client parsing inclient.py. - Expose config through environment variables when behavior is likely to vary.
- Keep reward logic inside the environment.
- Prefer reset/step signatures compatible with
Environment:reset(seed=None, episode_id=None, **kwargs)step(action, timeout_s=None, **kwargs)
- Set
SUPPORTS_CONCURRENT_SESSIONS=Trueonly when isolation is real. Setmax_concurrent_envsincreate_appaccordingly (1 whenFalse, >1 whenTrue). - For MCP/tool-call UIs that send stringified JSON arguments, add action validators/parsers in
server/app.py. - Export public client/models symbols in
__init__.py. - Keep
openenv.yamlaligned with current scaffold format (spec_version: 1,name,type,runtime,app,port). - Avoid training/evaluation code paths in this skill.
8. Validate before handoff
Run the narrowest useful checks:
# Verify in-repo imports work (catches missing dual-import pattern)
PYTHONPATH=src:envs uv run python -c "from envs.<name>_env.server.<name>_environment import <ClassName>Environment"
# Build and validate
cd envs/<name>_env
openenv build
openenv validate --verbose
PYTHONPATH=src:envs uv run pytest envs/<name>_env -q
If tests do not exist, run a smoke check:
PYTHONPATH=src:envs uv run uvicorn envs.<name>_env.server.app:app --port 8000
curl http://localhost:8000/health
openenv validate --url http://localhost:8000
9. Deliver with assumptions and gaps
Report:
- files created/updated
- chosen archetype (typed vs MCP vs specialized)
- assumptions made due to missing answers
- validation commands executed and outcomes
- remaining risks or follow-up questions
Guardrails
- Do not route into model training/evaluation workflows.
- Do not invent library APIs; confirm against source docs.
- Do not skip reading at least one existing OpenEnv env before implementation.
- Do not copy outdated manifest patterns from older envs (
name/version/action/observation-only manifests). - Do not copy build artifacts or virtualenv files from example envs.
- Do not set
max_concurrent_envs > 1unless the environment explicitly supports concurrent sessions.