Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .claude/skills/generate-openenv-env/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,8 @@ Use these standards:
- 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.yaml` aligned with current scaffold format (`spec_version: 1`, `name`, `type`, `runtime`, `app`, `port`).
- Add a Harbor schema 1.1 `task.toml` and configure truthful resource,
networking, timeout, verifier, and artifact requirements for the environment.
- Avoid training/evaluation code paths in this skill.

### 8. Validate before handoff
Expand All @@ -134,6 +136,7 @@ PYTHONPATH=src:envs uv run python -c "from envs.<name>_env.server.<name>_environ
cd envs/<name>_env
openenv build
openenv validate --verbose
openenv validate --profile publish --remote
PYTHONPATH=src:envs uv run pytest envs/<name>_env -q
```

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
schema_version = "1.1"

[task]
name = "openenv/__ENV_NAME__"
description = "__ENV_TITLE_NAME__ OpenEnv environment"

[environment]
cpus = 1
memory_mb = 2048
storage_mb = 10240
gpus = 0
# Set this to false when the environment does not need outbound internet.
allow_internet = true
Original file line number Diff line number Diff line change
Expand Up @@ -79,11 +79,14 @@ Ask only what changes architecture or contracts.
Mark complete only when all are true:

- `envs/<name>_env/openenv.yaml` exists, uses `spec_version: 1`, and points to `server.app:app`.
- `envs/<name>_env/task.toml` uses Harbor schema 1.1 and truthfully declares
publish-time resource and network requirements.
- `models.py` defines typed action/observation/state.
- `server/<name>_environment.py` implements `reset`, `step`, and `state`.
- `server/app.py` calls `create_app` with action/observation classes.
- `client.py` matches the selected archetype and correctly serializes/parses data.
- `__init__.py` exports the public API.
- `README.md` includes quickstart and configuration.
- `openenv build` and `openenv validate --verbose` pass, or failures are documented.
- `openenv build` and `openenv validate --profile publish --remote` pass, or
failures are documented.
- Runtime smoke check is executed (`/health`; optionally `openenv validate --url`).
12 changes: 12 additions & 0 deletions envs/echo_env/task.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
schema_version = "1.1"

[task]
name = "openenv/echo-env"
description = "Canonical OpenEnv echo environment used for validation and examples."

[environment]
cpus = 1
memory_mb = 2048
storage_mb = 10240
gpus = 0
allow_internet = false
13 changes: 13 additions & 0 deletions src/openenv/cli/templates/openenv_env/task.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
schema_version = "1.1"

[task]
name = "openenv/__ENV_NAME__"
description = "__ENV_TITLE_NAME__ OpenEnv environment"

[environment]
cpus = 1
memory_mb = 2048
storage_mb = 10240
gpus = 0
# Set this to false when the environment does not need outbound internet.
allow_internet = true
17 changes: 17 additions & 0 deletions tests/test_cli/test_init.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ def test_init_creates_directory_structure(tmp_path: Path) -> None:
assert (env_dir / "client.py").exists()
assert (env_dir / "README.md").exists()
assert (env_dir / "openenv.yaml").exists()
assert (env_dir / "task.toml").exists()
assert (env_dir / "server").exists()
assert (env_dir / "server" / "__init__.py").exists()
assert (env_dir / "server" / "app.py").exists()
Expand Down Expand Up @@ -116,6 +117,22 @@ def test_init_generates_openenv_yaml(tmp_path: Path) -> None:
assert "__ENV_NAME__" not in yaml_content


def test_init_generates_publish_requirements(tmp_path: Path) -> None:
env_name = "test_env"
result = runner.invoke(
app,
["init", env_name, "--output-dir", str(tmp_path)],
input="\n",
)

assert result.exit_code == 0
task_content = (tmp_path / env_name / "task.toml").read_text()
assert 'schema_version = "1.1"' in task_content
assert 'name = "openenv/test_env"' in task_content
assert "[environment]" in task_content
assert "__ENV_NAME__" not in task_content


def test_init_readme_has_hf_frontmatter(tmp_path: Path) -> None:
"""Test that README has Hugging Face Space compatible frontmatter."""
env_name = "test_env"
Expand Down