Release OpenEnv 0.6.0 - #1211
Conversation
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>
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>
There was a problem hiding this comment.
Stale comment
Candidate refreshed — state at
fee469c4I 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 sincev0.5.07e591317, 7 commitsDiff 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.lockis the only environment lock that resolves the root
openenvpackage 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, anduv lock --checkfails in that directory. After the one-line
change to0.6.0it passes, anduv sync --frozen --all-groups --all-extras --dry-run --no-install-projectpasses there too. Both verified locally.No repository job catches this on its own:
uv sync --frozenskips the freshness
check, andvalidate-env-locksis both scoped to changed env dependency files and
currently a no-op (it filters paths withrg, which is absent onubuntu-latest,
so it logsrg: command not foundand 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'spost-release-bumpjob edits
onlypyproject.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:
test3.11 and 3.12,test-thinkingbox-env3.11 and
3.12,lint,check-env-docs,snapshot,Analyze (python), andBuild and smoke-test package— the last one builds the wheel and sdist, runstwine check,
installs each into a clean venv, assertsopenenv.__version__equals the installed
metadata version, and runsopenenv --help.mergeStateStatusisCLEAN.A real Echo
reset/stepsmoke also passes against this tree: reset metadata is
{'status': 'ready', 'message': 'Echo environment ready!'},list_toolsreturns
both tools, the step envelope'sdatais the echoed message,call_toolreturns
the bare string, andstatereportsstep_count=1.Still blocking publication
- Version decision —
0.6.0(recommended) or0.5.1. One line either way.- The Novita debt list in the body above needs an explicit ship-or-fix call.
publish-testpypi.ymlhas 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.Sent by Cursor Automation: Release
There was a problem hiding this comment.
Stale comment
Independent release validation at
fee469c4— all local gates greenRan 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 buildwheel + sdistopenenv-0.6.0-py3-none-any.whl,openenv-0.6.0.tar.gztwine checkPASSED both artifacts Clean-venv wheel install openenv 0.6.0,__version__== installed metadata,openenv --helpOKClean-venv sdist install same, openenv --helpOKopenenv[novita]extrainstalls; NovitaSandboxProviderimportsTests (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 diffReal Echo reset/step/state/call_tool PASSED On lint:
usort checkalone reportstests/envs/test_grid_world.pyandtests/envs/test_julia_env.pyas unsorted, which reads like standing debt. It is not — CI runsusort formatthenruff format, and ruff reverts usort's change, so the combined pipeline is a no-op andgit diffis 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_countaccounting, directcall_tool, rejection of an unknown tool, and a second reset clearingstep_countto 0.
validate-env-lockspassed vacuously on this PRWorth 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 onubuntu-latest, somapfileyields an empty array and the job exits 0 without validating anything. Theenvs/grid_world_env/uv.lockchange in this PR was never checked by CI. I validated it locally instead:uv lock --checkresolves 117 packages cleanly anduv sync --frozen --all-groups --all-extras --dry-run --no-install-projectsucceeds.Also confirmed while checking:
grid_world_envis the only env lock withsource = { editable = "../../" }, so it is the only one that tracks the root project version. The other 37 env locks pin publishedopenenvversions 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
ARGsubstitution order in_resolve_from_references. Reproduced against the shipped code:
Dockerfile shape Result ARG BASEthenARG BASE_IMAGE,FROM ${BASE_IMAGE}correct ARG BASEthenARG BASE_IMAGE,FROM $BASE_IMAGEFROM python:3.12_IMAGElonger 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 acrossenvs/andsrc/, 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_defaultslongest-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_message→AttributeError: 'GenericMCPObservation' object has no attribute 'echoed_message'. The text is atresult.metadata["message"].result.observation.resultis a dict, not the"Hello, World!"string the comment claims; the string is atresult.observation.result["data"].This is not new — it is present at
v0.4.2andv0.5.0and 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
- Version call — 0.6.0 vs 0.5.1 (rationale in the PR body). One-line change either way.
- Ship-or-fix on the Novita debt — recommendation above is ship.
- TestPyPI dispatch — required by the release checklist and I get HTTP 403 on
workflow_dispatch, so this needs a maintainer to runpublish-testpypi.ymlfromcursor/openenv-release-management-7ba7.Nothing is tagged or published. PyPI and the GitHub release remain
0.5.0.Sent by Cursor Automation: Release
There was a problem hiding this comment.
Stale comment
Monday check-in — candidate re-validated, and the cargo list changed
mainis still7e591317and this PR is stillfee469c4, 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 buildopenenv-0.6.0-py3-none-any.whl+openenv-0.6.0.tar.gztwine checkPASSED both clean-venv wheel install 0.6.0,__version__matches metadata,openenv --helpOKclean-venv sdist install same openenv[novita]extrainstalls, NovitaSandboxProviderimportstests (CI-equivalent flags) 2761 passed, 95 skipped, 37 deselected lint (CI-equivalent) no resulting diff, ruff checkcleangrid_world_envlockuv lock --checkresolves 117 packages; frozen dry-run cleanreal Echo reset / step / state / list_tools PASSED The
grid_world_envlock was checked by hand again because CI'svalidate-env-locksstill 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 againstmaininstead of against an idealised baseline: on the path I called a regression,mainis 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'sstate_clsfix actually reach users (onmain,maze_env's/schemaand/statedropcurrent_position,exit_cell,statusanddone, 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
$ARGcollision is latent and no in-repo Dockerfile can trigger it), and the TestPyPI dispatch, which I cannot run (workflow_dispatchreturns 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 sincev0.5.0". It is now 7 commits and the base is7e591317; 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.
Sent by Cursor Automation: Release
Includes #1145 provider cleanup on failed connect. Co-authored-by: benjamin.burtenshaw <benjamin.burtenshaw@huggingface.co>
There was a problem hiding this comment.
Stale comment
Candidate reconciled at 12:20 UTC Monday. I could not edit the PR description (the app token is refused on
updatePullRequest), so the corrections to the notes are here.The description is now stale in three places.
- Candidate base is
228bd147, not39fdf5cd; this branch merges it atcf88ef23. That is 8 commits sincev0.5.0, not 6.- #1145 merged to
mainat 07:56 UTC today, so it is in this candidate — it should come out of the "not in this candidate" list and into the release notes. Suggested entry:Failed session startup no longer leaks a provider: when
new_session()cannot bring up a client,EnvClientstops the container or sandbox it started instead of leaving it running. Cleanup is retry-safe, and a client whose cleanup is still pending refuses to reconnect to the old base URL rather than overwriting the only resource handle (#1145).- #1208 is closed unmerged, so it should drop off the fork-CI list. The remaining package-touching fork PRs are #1198, #1200, #1203, #1209 and #1217, all still
action_required.Measured severity for the
$ARGdebt item, so that decision does not rest on a description alone. Reproduced against_resolve_from_referencesexactly as shipped on228bd147:
Dockerfile Resolved FROMARG BASE_IMAGE=…+FROM ${BASE_IMAGE}FROM ghcr.io/huggingface/openenv-base:latestARG BASE=python:3.11-slim,ARG BASE_IMAGE=…+FROM ${BASE_IMAGE}FROM ghcr.io/openenv-base:latestARG BASE=python:3.11-slim,ARG BASE_IMAGE=…+FROM $BASE_IMAGEFROM python:3.11-slim_IMAGESo it needs all three of: the opt-in provider's
image_from_dockerfilepath, two global ARGs where one name prefixes the other, and unbraced$NAMEinFROM. No in-repo Dockerfile uses the unbraced form, and the failure mode is a hard build error on an invalid reference, not a silent wrong image. I agree with the existing recommendation: ship 0.6.0 and fix it in a follow-up.State right now: head
cf88ef23,CLEAN, all checks green (tests 3.11/3.12, lint, Package CI, env locks, docs, CodeQL). Still draft, correctly — the two things standing between this and Thursday are the0.6.0vs0.5.1call and a TestPyPI run from the final head.Sent by Cursor Automation: Release
There was a problem hiding this comment.
Stale comment
TestPyPI validation is done — that ask can come off Ben's list.
We do not need a manual
workflow_dispatchfor this. The same mechanism used forv0.4.2andv0.5.0still works: push the candidate to atestpypi/<version>branch carrying the nine-linepush: testpypi/**trigger, which the publish workflow accepts withoutactions: write. I pushedtestpypi/0.6.0at683e003a, which is this PR's headcf88ef23plus that trigger commit and nothing else (git diff --stat cf88ef23 683e003ashows only.github/workflows/publish-testpypi.yml, +9 lines). The branch is a scratch branch and is not proposed formain.Run 35598458908 published
0.6.0.dev71. Both jobs succeeded, including the workflow's own install-from-TestPyPI check.Independently verified afterwards, outside the workflow:
- Downloaded the TestPyPI wheel directly; sha256
030437b64fa638c7ac66e4c4b833595444a62f053f3dce0e9478e6951db5a738matches TestPyPI metadata (sdist46cdd802…bafd3).- Clean Python 3.11 venv, wheel installed with the new extra (
openenv[novita], dependencies resolved from PyPI, never TestPyPI):importlib.metadata.version("openenv")andopenenv.__version__both report0.6.0.dev71, the package imports from the fresh venv, andopenenv --helpworks.NovitaSandboxProviderimports from the installed wheel, as doopenenv.harbor,openenv.discoveryandopenenv.validation. This is the first candidate carrying thenovitaextra, so that resolution path is the one worth proving early.- Real Echo round trip against the installed package (repo
envs/onPYTHONPATH, core from the wheel):reset()returned{'status': 'ready', 'message': 'Echo environment ready!'}, discovery returnedecho_messageandecho_with_length, and anecho_messagestep round-trippedrelease-0.6.0.dev71-smokethrough bothstep()andcall_tool().Release mutations were serialized behind the
automation-locks/openenv-release-0.6.0branch lock, which is now released.What is left before Thursday is only the version decision (
0.6.0vs0.5.1) and explicit acceptance of the documented Novita debt. If the version changes, this is one line plus a re-run of the same TestPyPI branch; if it stays0.6.0, Thursday is merge, tag, publish, verify.Sent by Cursor Automation: Release
Fold RFC 008 Level-2 validation contracts (#1178) into the draft cut. Co-authored-by: benjamin.burtenshaw <benjamin.burtenshaw@huggingface.co>
There was a problem hiding this comment.
Refreshed candidate onto main 1e3f16d6 (#1178 Level-2 validation contracts).
- Head:
ca0180c8(merge of main into the 0.6.0 bump) - Package cargo now: Novita #1191 + provider cleanup #1145 + RFC 008 L2 contracts #1178
- Local:
uv build+ twine PASS; validation suite 169 passed; clean 3.11 wheel+[novita]install reports0.6.0and imports harbor/discovery/validation/RuntimePlan - TestPyPI: re-pushed
testpypi/0.6.0→ run 35606807532 published0.6.0.dev81(prior0.6.0.dev71is stale vs this head)
Still draft; nothing tagged. Ben asks unchanged (version / Novita debt).
Sent by Cursor Automation: Release
Co-authored-by: benjamin.burtenshaw <benjamin.burtenshaw@huggingface.co>
Co-authored-by: benjamin.burtenshaw <benjamin.burtenshaw@huggingface.co>
There was a problem hiding this comment.
Stale comment
Candidate refreshed to
8bbb8542on mainca4219d2The PR body above is stale and I cannot edit it (
updatePullRequestis 403 for this token), so treat this comment as the current release notes and blocker list. 13 commits sincev0.5.0.Release notes for v0.6.0
In the wheel and sdist
- 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 unlesssurface_server_logs=True. Installs viapip install openenv[novita]. (#1191)- RFC 008 Level 2 validation contracts.
openenv.validationgainsopenenv.validation.runtimecontract types, themanifest-v2/report-v2/runtime-planJSON schemas, and aseverity-v2policy, so an environment can declare and be checked against a Level 2 contract. (#1178)- Client no longer leaks a sandbox when session startup fails.
EnvClienttears the provider down if the session cannot be established, instead of leaving the container or sandbox allocated. (#1145)- Packaging metadata. The PyPI long description picks up the Miles entry added to the root README. (#1220)
Not in the wheel, but shipped to environment images, CI, and docs this week
coding_envconstructor arguments work as documented:additional_importsmerges on top ofDEFAULT_SAFE_IMPORTSinstead of replacing the allowlist, so passing one module no longer breaksimport json. (#1147)- Environment lockfile security updates: anyio 4.14.2 for the critical
TLSStreamIDNA certificate-spoofing advisory plus two lower-severity fixes (#1201, #1202, #1197 for the remaining 31 lockfiles), and soupsieve 2.9.2 for the polynomial-ReDoS advisories (#1196).- Documentation navigation refresh. (#1219)
- The release pipeline now pins
actions/upload-artifacttov7.0.1by immutable SHA, so a futurev7.0.xcannot change the publish path mid-release. (#1221)Full comparison: v0.5.0...8bbb854
This PR's own diff is still only the version change:
0.5.1.dev0to0.6.0inpyproject.tomland thegrid_world_envlockfile.Validation at this head
- Exact-head repository CI: 11/11 green (
test3.11 and 3.12,lint,Package CI,validate-env-locks,check-env-docs,snapshot, CodeQL, ThinkingBox 3.11 and 3.12).buildis skipped only because the PR is still a draft.- Local CI-equivalent suite: 2931 passed, 95 skipped, 41 deselected.
ruff formatandruff checkclean.usortstill reportstests/envs/test_grid_world.pyandtests/envs/test_julia_env.py; I confirmed both are identical onmain, so it is pre-existing and not candidate cargo.uv buildplustwine check: both wheel and sdist PASSED. Clean 3.11 venv installs of each, with imports (openenv.harbor,openenv.discovery,openenv.validation,NovitaSandboxProvider,openenv.validation.runtime.contracts) andopenenv --help/harbor/catalog/discover/validateall passing.- TestPyPI
0.6.0.dev91published fromtestpypi/0.6.0at5e95203a, whose only tree delta from this candidate is the push-trigger block inpublish-testpypi.yml(run 35694308033). This run also exercised the newly pinnedactions/upload-artifact@v7.0.1on the real publish path.
- Wheel
sha256:f73b243d42569e9ec4268a68afef08a0a9df5ac5cf49584862985f525386a20f, sdistsha256:57446bf8d62b2f5fbd54b6f6f86d53da26488471d8d690cf3d2e609b3cae97e5. I re-downloaded the wheel and the hash matches both the upload log and TestPyPI metadata.- All 165
src/openenv/**files in the published wheel are byte-identical to this candidate. The six non-Python assets that are not packaged (core/README.md,containers/images/Dockerfile, and similar) are absent from the shipped0.5.0wheel too, so this is existing packaging behaviour rather than a regression.- Clean 3.11 install with the
[novita]extra, imports and CLI verified, and a real Echo reset/step smoke passed:resetreturned ready, tool discovery returnedecho_messageandecho_with_length, and bothcall_toolandstep(CallToolAction(...))round-trippedrelease-0.6.0.dev91-smoke.One tooling note: the workflow's own Verify install from TestPyPI step failed even though the upload returned
200 OKfor both artifacts. Its retry budget is five attempts 30 seconds apart, and the TestPyPI simple index had not caught up within those 2.5 minutes. The publication itself is fine and I verified the install independently, but the same race exists inpublish-pypi.yml, so Thursday's production run could report a false failure after a successful upload. I have not changed the workflow, since widening that budget is a release-policy edit rather than routine maintenance.Outstanding blockers
- Version decision.
0.6.0is my recommendation and is now better supported than when this PR was opened: the candidate carries two separate pieces of new public surface, the Novita provider (#1191) and the RFC 008 Level 2 validation contracts (#1178). If you would rather ship0.5.1, it is a one-line change.- Novita debt. Recommend ship and track as follow-ups: unbraced
$ARGsubstitution during Dockerfile flattening can corrupt aFROMline when one build arg name is a prefix of another (no in-repo Dockerfile triggers it), andexamples/novita_tbench2_simple.pycallswait_for_readyoutside itstry/finally, so a readiness timeout leaks the sandbox.Nothing is tagged. Production PyPI is still
0.5.0.Sent by Cursor Automation: Release
Keep draft #1211 exact-main after workflow-only Dependabot merge. Co-authored-by: benjamin.burtenshaw <benjamin.burtenshaw@huggingface.co>
There was a problem hiding this comment.
Candidate refresh
Exact-main again at 0150e7e4 after folding #1223 (doc-builder upload_pr_documentation workflow pin only).
- Net PR diff unchanged vs main: root
0.6.0+ GridWorld editable lock version. - Package bytes unchanged vs prior tip
8bbb8542— TestPyPI0.6.0.dev91evidence remains valid (no republish needed for this refresh). - Exact-head CI re-running.
Still draft / no tag. Holding publish pending Ben’s version (0.6.0 vs 0.5.1) + Novita-debt call.
Note on #1221: publish workflows still use mutable actions/upload-artifact@v7.0.1 (tag); #1228 is the still-open immutable-SHA harden and stays held thru Thursday unless Ben.
Sent by Cursor Automation: Release
Keep draft #1211 exact-main after workflow-only Dependabot merge. Co-authored-by: benjamin.burtenshaw <benjamin.burtenshaw@huggingface.co>
There was a problem hiding this comment.
Candidate refresh
Exact-main again at a59a1b48 after folding #1225 (doc-builder build_main_documentation pin only).
- Net PR diff unchanged vs main: root
0.6.0+ GridWorld editable lock version. - Package bytes unchanged — TestPyPI
0.6.0.dev91still valid (no republish). - Exact-head CI re-running.
Still draft / no tag. Holding publish pending Ben’s version + Novita-debt call.
Sent by Cursor Automation: Release
Co-authored-by: benjamin.burtenshaw <benjamin.burtenshaw@huggingface.co>
There was a problem hiding this comment.
Candidate refresh + publish-path change
Exact-main at fd997ac1 after folding #1228 (Pauline merged publish-workflow immutable SHA pins for checkout / setup-python / upload-artifact / download-artifact).
- Net package diff vs main unchanged: root
0.6.0+ GridWorld editable lock. - Publish path changed → prior TestPyPI
0.6.0.dev91is stale for release evidence. - Exact-head CI re-running on
fd997ac1. - TestPyPI revalidation already pushed:
testpypi/0.6.0@104c639a(= tip + push trigger); run 35696413568 queued.
Still draft / no tag. Holding production publish pending Ben’s version + Novita-debt call.
Note: pypa/gh-action-pypi-publish@release/v1 remains on the mutable branch ref (the two HIGH findings #1228 deliberately left for release-owner decision).
Sent by Cursor Automation: Release
L2 Docker lab is package cargo for 0.6.0 after Ben merged #1179. Co-authored-by: benjamin.burtenshaw <benjamin.burtenshaw@huggingface.co>
There was a problem hiding this comment.
Candidate refresh — folded #1179
Ben merged the Docker validation lab → main 26c9465e. Draft tip now 984533f3 (exact main).
- Package cargo changed — prior TestPyPI
0.6.0.dev101is stale. Will revalidate viatestpypi/0.6.0after exact-head CI is green. - Net version bump vs main unchanged (
0.6.0+ GridWorld lock). - Stacked #1181 still open on main with REQUEST_CHANGES (Bugbot report-path mediums); not folded yet.
Still draft / no tag. Holding publish pending Ben’s version + Novita-debt call.
Sent by Cursor Automation: Release
Lab toolchain only — package cargo unchanged. Keeps #1211 exact-main for Thursday. Co-authored-by: benjamin.burtenshaw <benjamin.burtenshaw@huggingface.co>
|
The docs for this PR live here. All of your documentation changes will be reflected on that endpoint. The docs are available until 30 days after the last update. |
There was a problem hiding this comment.
Alignment Review Report
Automated two-tier review of the 0.6.0 release version bump (0.5.1.dev0 → 0.6.0). The diff touches only pyproject.toml and envs/grid_world_env/uv.lock — no Python source, no API/signature changes.
Automated Checks
- Lint: PASS (no regression from this PR). The CI
lintjob is green. The local.claude/hooks/lint.shreports failures, but they are entirely pre-existing and outside this diff:ruff format --checkflags 56 files underenvs/**(CI only formatssrc/ tests/, notenvs/), plus the two knownusortquirk filestests/envs/test_grid_world.pyandtests/envs/test_julia_env.pydocumented inAGENTS.md. This PR changes no.pyfiles, so it introduces zero lint issues. - Debug code: CLEAN for this diff.
check-debug.shscans the wholesrc/tree (informational, always exit 0); every hit is legitimateconsole.print/CLI output, docstring>>> print(...)examples, or one manual e2e script — none are in this PR.
Open RFCs Context
No RFC is affected by a version-string bump. For reference: In Review — 000, 001, 002, 003, 005, 008, 012; Draft — 010, 011. None touch packaging/versioning or the files in this diff.
Tier 1: Fixes Required
-
tests/validation_runtime/uv.lock:916— stale rootopenenvversion. It still recordsversion = "0.5.1.dev0"for thesource = { directory = "../../" }entry while this release bumps the repo root to0.6.0. This is the only remaining reference to0.5.1.dev0anywhere in the repo. Its sibling — the only other lockfile that tracks the repo root via../../—envs/grid_world_env/uv.lockwas bumped to0.6.0in dedicated commitfee469c4, so this one looks like it was simply missed.- Severity: low / not CI-blocking. The
Runtime validationjob runsuv sync --project tests/validation_runtime --frozen, which builds + installs the actual0.6.0from source and ignores the recorded version (verified locally:uv sync --frozen→ exit 0, installs0.6.0). Andvalidate-env-locksonly scans changed files underenvs/**, so it never inspects this file. It is, however, a release-artifact inconsistency:uv lock --check/uv sync --lockedagainst this project reports the lockfile out-of-date (verified locally: exit 1). - Fix: run
uv lock --project tests/validation_runtime(or bump the single recorded version line to0.6.0) so the committed lockfile matches the release, for parity with the grid_world_env bump. - Suggested reviewer: @burtenshaw (author of
tests/validation_runtime/and.github/workflows/validation-runtime.yml).
- Severity: low / not CI-blocking. The
No other version-bump gaps found: openenv.__version__ resolves dynamically via importlib.metadata (no hardcoded version to update), there is no CHANGELOG in the repo, and the many env lockfiles pinned to older published versions (0.3.1, 0.4.x, 0.3.2.dev0) reference published releases rather than the repo root — they are intentionally independent and out of scope for this bump.
Tier 2: Alignment Discussion
Principle Conflicts
None identified. A pre-1.0 MINOR bump (0.5.x → 0.6.0) with no API changes is consistent with the Breaking Change Policy in INVARIANTS.md. Nothing touches reset/step/state signatures, client–server separation, rewards-in-environment, or the MCP/Gym API boundary.
RFC Conflicts
None identified. The diff changes no code covered by any open or accepted RFC.
Summary
- 1 mechanical issue to fix (low-severity, not CI-blocking): stale
openenvversion intests/validation_runtime/uv.lock. - 0 alignment points for human review.
- 0 RFC conflicts.
Sent by Cursor Automation: Pre-review
| [[package]] | ||
| name = "openenv" | ||
| version = "0.5.1.dev0" | ||
| version = "0.6.0" |
There was a problem hiding this comment.
This root-tracking lockfile (source = { editable = "../../" }) is correctly bumped to 0.6.0.
One gap to mirror here: tests/validation_runtime/uv.lock is the only other lockfile that tracks the repo root (source = { directory = "../../" }), and it still records openenv version = "0.5.1.dev0" — the last remaining reference to the old version in the repo. It appears to have been missed in this release.
Not CI-blocking (Runtime validation uses uv sync --frozen, which installs the actual 0.6.0; validate-env-locks only scans envs/**), but for a consistent 0.6.0 release please run uv lock --project tests/validation_runtime.
…ptools) Lab toolchain only — package cargo unchanged. Keeps #1211 exact-main for Thursday. Co-authored-by: benjamin.burtenshaw <benjamin.burtenshaw@huggingface.co>
Align tests/validation_runtime/uv.lock with the release version bump (parity with envs/grid_world_env). Relocked with lab-pinned uv 0.9.3. Co-authored-by: benjamin.burtenshaw <benjamin.burtenshaw@huggingface.co>
Lab toolchain only — package cargo unchanged. Keeps #1211 exact-main for Thursday. Co-authored-by: benjamin.burtenshaw <benjamin.burtenshaw@huggingface.co>
There was a problem hiding this comment.
Release notes and validation evidence for v0.6.0 — head ab7818d1
The PR body above is stale and cannot be edited (updatePullRequest returns 403 for this token), so these are the authoritative notes. They supersede every earlier evidence comment on this PR.
What this PR changes
Nothing but the version, in three places, all on exact main (c32c3174):
| File | 0.5.1.dev0 → 0.6.0 |
|---|---|
pyproject.toml |
package version |
envs/grid_world_env/uv.lock |
local openenv entry |
tests/validation_runtime/uv.lock |
local openenv entry |
Release contents (v0.5.0..main, 22 commits)
New public API surface — this is what justifies a minor bump rather than a patch:
- Novita sandbox provider (#1191) —
NovitaSandboxProviderplus a newopenenv[novita]extra (novita-sandbox>=2.1.1). - RFC 008 Level 2 validation contracts (#1178) —
openenv.validation.runtime(RuntimePlanand friends), themanifest-v2/report-v2/runtime-planJSON schemas, andseverity-v2. - Docker validation provider (#1179) —
openenv.validation.providers.docker.DockerValidationProviderand the reproducible validation lab.
Fixes and metadata:
- Client now cleans up the provider when session startup fails (#1145).
coding_envdocumented constructor arguments actually work (#1147).- README is the package long description, including the Miles integration (#1220).
Repo-only, not shipped in the wheel: docs navigation (#1219), env lockfile security bumps (#1196/#1197/#1201/#1202), workflow SHA pinning (#1221/#1223/#1225/#1226/#1228), and today's validation-lab toolchain bumps (#1229/#1230/#1231).
Validation on this exact head
- Repository CI: green on
ab7818d1, including Runtime validation / Linux Docker, both Python matrices, ThinkingBox, CodeQL, lint, env-lock validation, and Bugbot. The docs build now runs too, since this PR is out of draft. - Local CI-equivalent suite: 2970 passed, 103 skipped, 44 deselected.
- TestPyPI
0.6.0.dev111(run 35717494905) remains the current package evidence. Today's three merges touched onlytests/validation_runtime/**, which the wheel does not ship, and I re-proved that rather than asserting it: a wheel built from this head has all 166openenv/**files byte-identical to the published0.6.0.dev111wheel (sha256:b8784828…fc3b22, re-downloaded and hash-checked against the TestPyPI index). - Fresh-install checks from the wheel built at this head, in a clean 3.11 venv: reports
0.6.0; importsopenenv.harbor,openenv.discovery,openenv.validation,NovitaSandboxProvider,RuntimePlan,DockerValidationProvider; the[novita]extra resolvesnovita_sandbox;openenv --helpplusharbor/catalog/discover/validateall work. - Real Echo reset/step smoke: server started from the installed wheel,
reset()→ ready,list_tools()→echo_message+echo_with_length, and bothcall_toolandstep(CallToolAction(...))round-tripped a unique marker.
Outstanding blockers
Two release-owner decisions, not code:
- Version — 0.6.0 (recommended) vs 0.5.1.
- Novita debt — accept and ship, or fix first. Both items are latent:
_resolve_from_referencessubstitutes unbraced$ARGnames, so a Dockerfile declaringARG BASEbeforeARG BASE_IMAGEwould resolveFROM $BASE_IMAGEtopython:3.12_IMAGE(no in-repo Dockerfile declares both), andexamples/novita_tbench2_simple.pycallswait_for_readyabove itstry/finally, so a readiness timeout leaks the sandbox.
Nothing is tagged and PyPI is still on 0.5.0. Once both decisions land I merge this at its verified head, tag that exact commit, and run the existing production publish workflow.
Sent by Cursor Automation: Release
There was a problem hiding this comment.
Release-notes gap after #1189/#1237 fold
Alignment review on merged #1237 flagged this for the 0.6.0 notes (I cannot edit this PR body — 403).
Please add under Release notes (breaking, documented):
collect --llm-endpoint/OpenAIClientaccept full base URLs: pathless endpoints get/v1; an existing path is kept;--llm-portonly fills in when the URL has no port. Non-http(s), missing host, credentials, query/fragment, and conflicting ports are rejected. Breaking: the old implicit port8000for bare hosts is gone —--llm-endpoint http://localhostis now port 80; usehttp://localhost:8000or--llm-port 8000(#1189 / #1237).
Also worth refreshing the stale checklist: version is decided (0.6.0); Novita debt is follow-up #1235 (not a cut blocker); TestPyPI is 0.6.0.dev121 verified against tip ee33f7ae; Level 2 contracts (#1178/#1179) are already on main and in this candidate.
Sent by Cursor Automation: Release
There was a problem hiding this comment.
The breaking-change bullet landed correctly — thanks. While checking it I diffed the candidate against v0.5.0 and found the notes are still missing two of the four package-level changes, plus a stale header. Since you can edit the body and I cannot (403), here is the exact text.
Missing bullets. git diff --stat v0.5.0..81379bd3 -- src/openenv/ shows 17 files and ~3,600 added lines. The notes cover Novita (#1191) and the LLM endpoint change (#1189/#1237); these two are in the candidate but undocumented:
- **Level 2 validation building blocks:** `openenv.validation` gains the RFC 008 Level 2 contracts — new `manifest-v2`, `report-v2` and `runtime-plan` JSON schemas, a `severity-v2` severity policy, runtime contract types, and `DockerValidationProvider`, a validation-only provider that builds an image and probes it locally with network-policy enforcement and in-sandbox exec ([#1178](https://github.com/huggingface/OpenEnv/pull/1178), [#1179](https://github.com/huggingface/OpenEnv/pull/1179)). The `openenv validate` CLI is unchanged in this release; the runtime probes that drive these contracts are still in review ([#1181](https://github.com/huggingface/OpenEnv/pull/1181)).
- **Failed session startup no longer leaks a provider:** when `new_session()` cannot bring up a client, `EnvClient` stops the container or sandbox it started instead of leaving it running. Cleanup is retry-safe, and a client whose cleanup is still pending refuses to reconnect to the old base URL rather than overwriting the only resource handle ([#1145](https://github.com/huggingface/OpenEnv/pull/1145)).I deliberately wrote the validation bullet as building blocks rather than a working --level runtime --local: src/openenv/cli/commands/validate.py is unchanged since v0.5.0 (only #1181 touches it), so claiming a usable runtime-probe CLI would overstate what ships tomorrow.
Stale header, three spots. The top still describes the state from five days ago:
- "Candidate base:
39fdf5cd… 6 commits sincev0.5.0" → candidate isee33f7aeon main81379bd3, 23 commits sincev0.5.0. - "the only package change since
v0.5.0is new public surface —NovitaSandboxProvider" → no longer true; it is now Novita, the Level 2 validation contracts plusDockerValidationProvider, the LLM endpoint change, and the provider-cleanup fix. That is a stronger case for the minor bump, not a weaker one. - "please say so before Wednesday" → the version is decided; Ben chose
0.6.0in Slack this morning. The Version decision checkbox under Outstanding blockers can be ticked, as can the three TestPyPI items (0.6.0.dev121, run 35842587905, verified byte-identical to this tip). - The compare link at the bottom still points at
39fdf5cd; it should bev0.5.0...81379bd3.
One caveat on the TestPyPI checklist line: the documented verification command uses --index-url test.pypi.org --extra-index-url pypi.org, which lets a TestPyPI name-squat outrank a real dependency. That is a release-policy fix rather than something to change silently during a cut, so I am only flagging it here — the workflow itself resolves dependencies from PyPI and installs the package --no-deps, so the published evidence is sound.
Sent by Cursor Automation: Release
There was a problem hiding this comment.
Correction to my previous comment, and it makes one edit mandatory rather than optional.
I reported that the #1145 bullet was in the body. It is not. The only mention of #1145 is in this paragraph:
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…
That statement is wrong now: #1145 merged on Monday as 228bd147 and is in this candidate; #1208 was closed unmerged. So the release notes currently tell readers that a shipped fix is not in the release. Two edits, both in that paragraph and the notes list:
- Remove #1145 and #1208 from the "Not in this candidate" list. The accurate remainder is #1198, #1200, #1203, #1209 and #1217 — all forks still at
action_required. - Add the #1145 bullet under Release notes (text in my previous comment), alongside the still-missing Level 2 bullet for #1178/#1179.
Everything else from that comment stands: the header still says candidate base 39fdf5cd and "6 commits since v0.5.0" where the truth is ee33f7ae on main 81379bd3 with 23 commits, and the compare link points at the old base.
Mechanically that is one paragraph edit plus two bullets. The candidate itself is unaffected — still CLEAN, 13/13 green, and byte-identical to the verified TestPyPI 0.6.0.dev121.
Sent by Cursor Automation: Release
…oping) Co-authored-by: benjamin.burtenshaw <benjamin.burtenshaw@huggingface.co>
Co-authored-by: benjamin.burtenshaw <benjamin.burtenshaw@huggingface.co>
There was a problem hiding this comment.
Independent pre-tag verification — the TestPyPI gate is closed
Read-only check from a sibling run (bc-799dc749); the release lock
refs/release-jock/v0.6.0... correction: refs/release-lock/v0.6.0 is held by
bc-ab703bc0, so I touched nothing — no merge, tag, publish or branch push.
The last publish-testpypi.yml run (35855102604, abbfb4fc) is red, and that
red is misleading in a way worth recording: the upload succeeded and
0.6.0.dev151 exists on TestPyPI (uploaded 2026-09-23 11:33:38Z). The job failed
afterwards, in its own verification step, because the index had not made the new
version resolvable inside the retry window — No matching distribution found for openenv==0.6.0.dev151, then ModuleNotFoundError: No module named 'openenv' as a
consequence. Nothing about the artifact was wrong.
I completed that verification by hand, and tied it to the commit being tagged.
1. The published artifact is the candidate, to the byte
Built a wheel from candidate head 0034202e with uv build --wheel and compared
it entry by entry against the downloaded TestPyPI wheel (sha256
c5019f30…54c2, matches the index digest):
- 167 packaged files on each side, no file on only one side, zero content
differences. dist-info:LICENSE,WHEEL,entry_points.txt,top_level.txtidentical;
METADATAdiffers in exactly one line (Version: 0.6.0vs
Version: 0.6.0.dev151);RECORDdiffers only in the version-nameddist-info
paths.
2. That same source is what is now on main
git diff 0034202e 5f95614f is empty — the squash tree is identical to the
candidate — and git diff abbfb4fc 5f95614f -- src/ pyproject.toml README.md MANIFEST.in is also empty. So the artifact verified below and the package source
at 5f95614f (the commit to tag v0.6.0) are the same bytes.
3. The published artifact actually works
uv pip install --no-deps --index-url https://test.pypi.org/simple/ openenv==0.6.0.dev151now resolves, which is the step that timed out in CI.- Clean venv, artifact from TestPyPI and dependencies from PyPI (avoiding the
mixed-index ordering problem flagged earlier):openenv.__version__==
importlib.metadata.version("openenv")==0.6.0.dev151, andopenenv --help
renders. - All three new API surfaces import from the installed wheel:
NovitaSandboxProvider(#1191),openenv.validation.runtime.contracts(#1178),
andopenenv.core.llm_client.LLMClient(#1237). - Real Echo episode against the installed package (repo
envs/on
PYTHONPATH, nosrc/):/health200, reset metadata
{'status': 'ready', 'message': 'Echo environment ready!'}, both tools listed,
stepreturnedv0.6.0-preflightwithis_error: False,
call_tool("echo_with_length", message="abc")returned
{'message': 'abc', 'length': 3}, andstatereportedstep_count=1.
Still outstanding for the publisher
publish-pypi.yml and publish-testpypi.yml were both rewritten by #1240 (action
SHA pins) after dev151 was built, so the pinned publish path itself has never
been exercised. That is a workflow-mechanics risk, not an artifact risk: watch the
first publish-pypi.yml run closely and confirm it actually started from the tag
rather than assuming the tag push triggered it.
Production is still 0.5.0 and no v0.6.0 tag exists as of this comment.
Sent by Cursor Automation: Release


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 sincev0.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.0is new publicsurface —
NovitaSandboxProvider(1,207 lines undersrc/openenv/core/containers/runtime/), a documented entry indocs/source/reference/core.md, and the newopenenv[novita]extra. That is addedfunctionality, which is a minor bump under the same standard applied when
0.5.0was cut rather than a quiet
0.4.3. If you would rather treat opt-in providers asnon-API and ship
0.5.1, it is a one-line change to this PR — please say so beforeWednesday so the notes and tag match.
Release notes
Breaking change — LLM endpoint URLs:
--llm-endpointis now a full base URL, and the implicit port8000has been removed.http://localhostnow uses the standard HTTP port80; to retain the previous local behavior, usehttp://localhost:8000or--llm-port 8000(#1189, landed via #1237).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 stagefor Novita's template parser. HTTPS/WSS transport is enforced and captured sandbox
output is withheld from raised errors unless
surface_server_logs=True. Installsvia
pip install openenv[novita](#1191).Not in the wheel, but shipped to environment images and the repo this week:
coding_envconstructor arguments work as documented:additional_importsnow merges on top of
DEFAULT_SAFE_IMPORTSinstead of replacing the allowlist,so passing one module no longer breaks
import json(#1147).
TLSStreamIDNA 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_envandfinrl_envin chore(deps): aggregate envs Dependabot updates #1197).Full candidate comparison: v0.5.0...39fdf5c
Release-maintenance changes in this PR
0.5.1.dev0to stable0.6.0. Nothing else.Outstanding blockers
0.6.0(recommended) or say0.5.1and I willchange the one line.
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
$ARGsubstitution during Dockerfile flattening can corrupt aFROMline (
$BASEmatching before$BASE_IMAGE);examples/novita_tbench2_simple.pycalls
wait_for_readyoutside itstry/finally, so a readiness timeout leaks apaid 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.
publish-testpypi.ymlfrom this exact branch with a unique0.6.0pre/dev suffix.mainimmediately before merge; rerun all required checks if thehead 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.tomlversion changed from0.5.1.dev0→0.6.0hf-staging/is NOT in this PR's diffprint(),breakpoint(), orTODOadded to release-critical pathsCI gates (must be green before merge)
testpasses on Python 3.11testpasses on Python 3.12lintpasses (usort + ruff)Package CIbuilds, checks, and smoke-tests wheel/sdist installsTestPyPI validation (before merging)
publish-testpypi.ymlfrom this branch0.6.0.devNpip install --index-url https://test.pypi.org/simple/ --extra-index-url https://pypi.org/simple/ openenv==0.6.0.devNPost-merge steps
v0.6.0pushed against the exact merge commit onmainpublish-pypi.ymlcompleted successfully from the tagpip install openenv==0.6.0from production PyPI verified (import,__version__,openenv --help, real Echo reset/step)RFC Status
Note
Low Risk
Metadata-only version and lockfile sync with no runtime or API changes in the diff.
Overview
Release version bump for the
openenvpackage:pyproject.tomlmoves from0.5.1.dev0to stable0.6.0, aligning the published package version with the v0.6.0 release.The editable
openenventries inenvs/grid_world_env/uv.lockandtests/validation_runtime/uv.lockare updated to0.6.0so those lockfiles stay consistent with the root project. No application or library code changes appear in this diff.Reviewed by Cursor Bugbot for commit 0034202. Bugbot is set up for automated code reviews on this repo. Configure here.