Skip to content

Release OpenEnv 0.6.0 - #1211

Draft
cursor[bot] wants to merge 4 commits into
mainfrom
cursor/openenv-release-management-7ba7
Draft

cursor[bot] wants to merge 4 commits into
mainfrom
cursor/openenv-release-management-7ba7

Conversation

@cursor

@cursor cursor Bot commented Sep 19, 2026

Copy link
Copy Markdown
Contributor

Release PR: v0.6.0

Planned release: Thursday, September 24, 2026 at 10:00 Europe/Brussels (08:00 UTC).

Candidate base: 39fdf5cd (main tip at the time of writing). 6 commits since v0.5.0.
This is the rolling release PR for the week; it will be refreshed onto the final
candidate head before merge.

Why 0.6.0 and not 0.5.1: the only package change since v0.5.0 is new public
surface — NovitaSandboxProvider (1,207 lines under
src/openenv/core/containers/runtime/), a documented entry in
docs/source/reference/core.md, and the new openenv[novita] extra. That is added
functionality, which is a minor bump under the same standard applied when 0.5.0
was cut rather than a quiet 0.4.3. If you would rather treat opt-in providers as
non-API and ship 0.5.1, it is a one-line change to this PR — please say so before
Wednesday so the notes and tag match.

Release notes

  • Novita AI sandbox provider: run an OpenEnv server inside a Novita sandbox and
    connect over wss://, from either a registry image or a local Dockerfile
    (image_from_dockerfile), with multi-stage Dockerfiles replayed as a single stage
    for Novita's template parser. HTTPS/WSS transport is enforced and captured sandbox
    output is withheld from raised errors unless surface_server_logs=True. Installs
    via pip install openenv[novita] (#1191).

Not in the wheel, but shipped to environment images and the repo this week:

  • coding_env constructor arguments work as documented: additional_imports
    now merges on top of DEFAULT_SAFE_IMPORTS instead of replacing the allowlist,
    so passing one module no longer breaks import json
    (#1147).
  • Environment lockfile security updates: anyio 4.14.2 for the critical
    TLSStream IDNA certificate-spoofing advisory plus two lower-severity fixes
    (#1201,
    #1202, and
    #1197 for the remaining 31
    lockfiles), and soupsieve 2.9.2 for the polynomial-ReDoS advisories
    (#1196, extended to
    browsergym_env and finrl_env in chore(deps): aggregate envs Dependabot updates #1197).

Full candidate comparison: v0.5.0...39fdf5c

Release-maintenance changes in this PR

  • Change 0.5.1.dev0 to stable 0.6.0. Nothing else.

Outstanding blockers

  • Version decision. Confirm 0.6.0 (recommended) or say 0.5.1 and I will
    change the one line.
  • Known debt accepted onto main with #1191, all scoped to the
    opt-in Novita provider and its examples, none of it re-blocking in my
    assessment — listed so the decision to ship it is explicit:
    unbraced $ARG substitution during Dockerfile flattening can corrupt a FROM
    line ($BASE matching before $BASE_IMAGE); examples/novita_tbench2_simple.py
    calls wait_for_ready outside its try/finally, so a readiness timeout leaks a
    paid sandbox; concurrent starts and failed kills can orphan sandboxes; flattened
    stages carry builder filesystem/ENV/USER state into the runtime image; and the
    RFC 002 provider amendment (root execution, unrestricted egress, HTTP-only
    readiness) is still unratified.
  • Dispatch and pass publish-testpypi.yml from this exact branch with a unique
    0.6.0 pre/dev suffix.
  • Reconcile main immediately before merge; rerun all required checks if the
    head or base changes.

Not in this candidate: every open small fix that touches the package
(#1145,
#1198,
#1200,
#1203,
#1208,
#1209) comes from a fork whose
workflows are still action_required, so none of them has ever run repository CI.
A maintainer clicking Approve and run is the only way any of them becomes
release-eligible.

Release Checklist

Before opening this PR

  • pyproject.toml version changed from 0.5.1.dev00.6.0
  • hf-staging/ is NOT in this PR's diff
  • No print(), breakpoint(), or TODO added to release-critical paths
  • Release notes include user-facing changes and linked PRs

CI gates (must be green before merge)

  • test passes on Python 3.11
  • test passes on Python 3.12
  • lint passes (usort + ruff)
  • Package CI builds, checks, and smoke-tests wheel/sdist installs

TestPyPI validation (before merging)

  • Manual dispatch of publish-testpypi.yml from this branch
  • TestPyPI published a unique pre/dev version such as 0.6.0.devN
  • Verified pip install --index-url https://test.pypi.org/simple/ --extra-index-url https://pypi.org/simple/ openenv==0.6.0.devN

Post-merge steps

  • Tag v0.6.0 pushed against the exact merge commit on main
  • publish-pypi.yml completed successfully from the tag
  • GitHub Release created by the successful PyPI publish workflow
  • pip install openenv==0.6.0 from production PyPI verified (import, __version__, openenv --help, real Echo reset/step)
  • Next development-version bump PR opened and processed

RFC Status

  • Not required (release maintenance)
Open in Web View Automation 

Sets the published version to 0.6.0 for the Thursday 2026-09-24 cut. The only
package change since v0.5.0 is the new NovitaSandboxProvider public surface,
which a patch number would misrepresent; see the PR body for the version
decision and outstanding blockers.

Co-authored-by: benjamin.burtenshaw <benjamin.burtenshaw@huggingface.co>
cursoragent and others added 2 commits September 19, 2026 06:25
Co-authored-by: benjamin.burtenshaw <benjamin.burtenshaw@huggingface.co>
grid_world_env is the only environment whose lock resolves the root openenv
package from an editable path, so its uv.lock pins the project version. Left at
0.5.1.dev0 it makes `uv lock --check` fail in that directory; `uv sync
--frozen` skips the freshness check, so no CI job catches it.

Co-authored-by: benjamin.burtenshaw <benjamin.burtenshaw@huggingface.co>

@cursor cursor Bot left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Candidate refreshed — state at fee469c4

I cannot edit this PR's body (no permission), so the description above is stale in
two ways. Current contents:

Body says Actually
Candidate base 39fdf5cd, 6 commits since v0.5.0 7e591317, 7 commits
Diff version line only version line + one lockfile line

Comparison for the refreshed base: v0.5.0...7e59131

Added since opening: the GridWorld lock line

envs/grid_world_env/uv.lock is the only environment lock that resolves the root
openenv package from an editable path (source = { editable = "../../" }), so it
records the project version. With the version bump alone it is left at
0.5.1.dev0, and uv lock --check fails in that directory. After the one-line
change to 0.6.0 it passes, and uv sync --frozen --all-groups --all-extras --dry-run --no-install-project passes there too. Both verified locally.

No repository job catches this on its own: uv sync --frozen skips the freshness
check, and validate-env-locks is both scoped to changed env dependency files and
currently a no-op (it filters paths with rg, which is absent on ubuntu-latest,
so it logs rg: command not found and exits 0 — see #1197 for the detail). Treat
the green check on this PR as vacuous and the local run above as the real gate.

Follow-up for a maintainer: publish-pypi.yml's post-release-bump job edits
only pyproject.toml, so it will re-stale this lock the moment it writes
0.6.1.dev0. Every future version transition will need the same second line until
that job also refreshes the GridWorld lock.

Gate status on this exact head

All 10 reporting checks pass: test 3.11 and 3.12, test-thinkingbox-env 3.11 and
3.12, lint, check-env-docs, snapshot, Analyze (python), and Build and smoke-test package — the last one builds the wheel and sdist, runs twine check,
installs each into a clean venv, asserts openenv.__version__ equals the installed
metadata version, and runs openenv --help. mergeStateStatus is CLEAN.

A real Echo reset/step smoke also passes against this tree: reset metadata is
{'status': 'ready', 'message': 'Echo environment ready!'}, list_tools returns
both tools, the step envelope's data is the echoed message, call_tool returns
the bare string, and state reports step_count=1.

Still blocking publication

  1. Version decision0.6.0 (recommended) or 0.5.1. One line either way.
  2. The Novita debt list in the body above needs an explicit ship-or-fix call.
  3. publish-testpypi.yml has not been dispatched from this branch, and the fresh
    production-PyPI install check obviously cannot run before publication.

Staying a draft until those clear. Nothing here should be read as a release
happening: this is a validated candidate, not a published version.

View PR

Open in Web View Automation 

Sent by Cursor Automation: Release

@cursor cursor Bot left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Independent release validation at fee469c4 — all local gates green

Ran the full release gate set off-CI against this exact head (base main 7e591317, unchanged since the last refresh). Recorded here because I cannot edit the PR body.

Gate Result
uv build wheel + sdist openenv-0.6.0-py3-none-any.whl, openenv-0.6.0.tar.gz
twine check PASSED both artifacts
Clean-venv wheel install openenv 0.6.0, __version__ == installed metadata, openenv --help OK
Clean-venv sdist install same, openenv --help OK
openenv[novita] extra installs; NovitaSandboxProvider imports
Tests (CI-equivalent: same ignores + not integration and not network and not docker) 2761 passed, 95 skipped, 37 deselected
Lint (CI-equivalent usort format + ruff format) no resulting git diff
Real Echo reset/step/state/call_tool PASSED

On lint: usort check alone reports tests/envs/test_grid_world.py and tests/envs/test_julia_env.py as unsorted, which reads like standing debt. It is not — CI runs usort format then ruff format, and ruff reverts usort's change, so the combined pipeline is a no-op and git diff is empty. No action needed.

Echo smoke covered reset metadata (status=ready), both advertised tools (echo_message, echo_with_length), a step whose payload echoes the sent message, step_count accounting, direct call_tool, rejection of an unknown tool, and a second reset clearing step_count to 0.

validate-env-locks passed vacuously on this PR

Worth stating explicitly since this PR changes a lockfile. The green check at fee469c4 (job log) contains:

rg: command not found
No environment dependency files changed.

The job filters changed paths with rg, which is not installed on ubuntu-latest, so mapfile yields an empty array and the job exits 0 without validating anything. The envs/grid_world_env/uv.lock change in this PR was never checked by CI. I validated it locally instead: uv lock --check resolves 117 packages cleanly and uv sync --frozen --all-groups --all-extras --dry-run --no-install-project succeeds.

Also confirmed while checking: grid_world_env is the only env lock with source = { editable = "../../" }, so it is the only one that tracks the root project version. The other 37 env locks pin published openenv versions and are unaffected by the bump.

Novita residual debt — triaged, recommend shipping

The one Tier 1 item that actually reaches the wheel is the unbraced ARG substitution order in _resolve_from_references. Reproduced against the shipped code:

Dockerfile shape Result
ARG BASE then ARG BASE_IMAGE, FROM ${BASE_IMAGE} correct
ARG BASE then ARG BASE_IMAGE, FROM $BASE_IMAGE FROM python:3.12_IMAGE
longer ARG declared first, unbraced correct
single ARG, unbraced correct

So it needs a user Dockerfile with two global ARGs where one name is a prefix of the other, the shorter declared first, and the longer used unbraced. No in-repo Dockerfile can trigger it — there are zero FROM $ARG (unbraced) occurrences across envs/ and src/, and zero Dockerfiles with prefix-colliding global ARGs.

Recommendation: this is a latent bug in brand-new opt-in surface, not a regression, and does not warrant holding 0.6.0. Ship and track the fix (sort arg_defaults longest-name-first) as a follow-up.

Pre-existing, ships again, not a blocker

The README quick start is the PyPI long description, and its first example raises. Run verbatim against a live Echo server:

  • result.observation.echoed_messageAttributeError: 'GenericMCPObservation' object has no attribute 'echoed_message'. The text is at result.metadata["message"].
  • result.observation.result is a dict, not the "Hello, World!" string the comment claims; the string is at result.observation.result["data"].

This is not new — it is present at v0.4.2 and v0.5.0 and is already live on the PyPI 0.5.0 page. Flagging rather than fixing here, to keep this PR to the version change; it should not gate the release.

Still outstanding before this can merge

  1. Version call — 0.6.0 vs 0.5.1 (rationale in the PR body). One-line change either way.
  2. Ship-or-fix on the Novita debt — recommendation above is ship.
  3. TestPyPI dispatch — required by the release checklist and I get HTTP 403 on workflow_dispatch, so this needs a maintainer to run publish-testpypi.yml from cursor/openenv-release-management-7ba7.

Nothing is tagged or published. PyPI and the GitHub release remain 0.5.0.

Open in Web View Automation 

Sent by Cursor Automation: Release

@cursor cursor Bot left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Monday check-in — candidate re-validated, and the cargo list changed

main is still 7e591317 and this PR is still fee469c4, so the candidate did not drift over the weekend. I re-ran the release gate from scratch at this exact head rather than carrying Sunday's result forward:

Gate Result
uv build openenv-0.6.0-py3-none-any.whl + openenv-0.6.0.tar.gz
twine check PASSED both
clean-venv wheel install 0.6.0, __version__ matches metadata, openenv --help OK
clean-venv sdist install same
openenv[novita] extra installs, NovitaSandboxProvider imports
tests (CI-equivalent flags) 2761 passed, 95 skipped, 37 deselected
lint (CI-equivalent) no resulting diff, ruff check clean
grid_world_env lock uv lock --check resolves 117 packages; frozen dry-run clean
real Echo reset / step / state / list_tools PASSED

The grid_world_env lock was checked by hand again because CI's validate-env-locks still passes vacuously (rg: command not found → "No environment dependency files changed"), so this PR's own lockfile edit is not actually covered by the green check above it.

Cargo update: #1145 is now eligible

The "not in this candidate" list in the PR body needs one correction.

  • #1145 is now approved from my side and it is package cargo — it changes src/openenv/core/env_client.py. I withdrew my earlier change request after measuring the flagged edge case against main instead of against an idealised baseline: on the path I called a regression, main is equally wedged and additionally swallows the real configuration error, while this PR surfaces it. Full evidence is on that PR. It fixes the #1144 provider leak, so it is worth folding into 0.6.0 if its CI greens before the cut.
  • #1198 is also approved but stays out of the wheel — it is envs/** plus one test. It makes #1174's state_cls fix actually reach users (on main, maze_env's /schema and /state drop current_position, exit_cell, status and done, which the WebSocket frame returns). No packaging risk either way.

Both are fork PRs whose repository CI has never run, so neither can merge until a maintainer clicks Approve and run. That click has a lead time if either is to make Thursday.

Blockers unchanged

The three items in the PR body still need @burtenshaw: the version call (0.6.0 vs 0.5.1), Novita ship-or-fix (my recommendation is still ship — the unbraced $ARG collision is latent and no in-repo Dockerfile can trigger it), and the TestPyPI dispatch, which I cannot run (workflow_dispatch returns 403 for this token, and that workflow has no other trigger).

One housekeeping note on this PR's own text: the body says "Candidate base: 39fdf5cd … 6 commits since v0.5.0". It is now 7 commits and the base is 7e591317; the added commit is #1197, which the release notes already list. The notes are correct; only that one line is stale, and it will be rewritten when this PR is refreshed onto the final candidate head.

Nothing has been tagged. PyPI is still 0.5.0.

Open in Web View Automation 

Sent by Cursor Automation: Release

Includes #1145 provider cleanup on failed connect.

Co-authored-by: benjamin.burtenshaw <benjamin.burtenshaw@huggingface.co>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant