Skip to content

feat(computer): computer envs deploy on local Docker - #369

Open
earakely-scale wants to merge 19 commits into
mainfrom
edgararakelyan/fd-4358-m07-computer-envs-deploy-on-local-docker-the-computer-env
Open

earakely-scale wants to merge 19 commits into
mainfrom
edgararakelyan/fd-4358-m07-computer-envs-deploy-on-local-docker-the-computer-env

Conversation

@earakely-scale

@earakely-scale earakely-scale commented Oct 28, 2026 •

Copy link
Copy Markdown
Collaborator

M0.7 of the CUA env epic (FD-4345): computer envs deploy on local Docker, FD-4358, with M0.8 (deploy_env env_params, FD-4349), M0.5 (the computer skill, FD-4355) and M0.11 (Env.close at teardown, FD-4464) folded in. It follows the reviewed design, CUA Env M0.7: Deploying a Computer Env on Local Docker, with its 15 choices confirmed and the changes below decided in review. It builds on #358 (M0.6), now merged, and is rebased onto main.

What's in it

  • Providers say what they run natively, and containers can have no network.
    • native_platforms(): linux/amd64 by default, the host's for local Docker. A computer boots only on a provider that runs its arch natively; create_container takes no platform (decided in review), since that choice is made before it's called.
    • NetworkPolicy.closed is an allowlist of nothing. Local Docker enforces it for a container: it runs on an internal network of its own, with a relay container (providers/sandbox_providers/relay/, built here from its sources) publishing its port to the computer's address there. A VM given a restricting policy is refused.
    • reset_container(sandbox, ...) resets a sandbox's container to a fresh one of the image, on the same sandbox and port; local Docker replaces the relay too. A computer env's reset uses it, since a computer's state is its whole filesystem and running session, with no seed to reload in place as an MCP server does.
  • The computer env provider (providers/env_providers/env_computer_provider.py) deploys a computer env with no gateway in front:
    • it boots the first ready build, in the base's order of forms and arches (or env_params.form's), on a sandbox provider that runs its arch natively;
    • the driver's card is the env card, served under the env's environment_name;
    • it checks the driver reports the env's display;
    • the record's metadata.computer keeps the form, arch, provider, image, computer, display, network, computer_settings (a secret's or a generated one's withheld) and env_params.
  • Gate 3 (composer.py): after a build, the composer boots it at the env's settings and display, as a deploy does, on a configured provider that runs its arch natively, and probes it at full. The build becomes ready with the driver's card, or failed at the probe with the report stored as a FileArtifact. A build no configured provider runs natively stays unverified, saying why, and env build probes it once one does. A probe's sandbox, and a boot that fails (a closed-network one whose setup fails too), go with their local work folders.
  • deploy_env env_params (M0.8), one table per layer: a computer env takes form, computer_settings (deploy-phase values of the base's settings, checked as the env's are; a secret one, here or on the env, only as a bare secret:/env: reference, since the env, the task and the deploy record keep what's given) and driver_settings (the driver's ComputerSettings, such as its default coordinate space, passed in AGENTENV_COMPUTER_SETTINGS). Preflight now asks every env type's deploy_refusal, so another type, or an option a type's deploy doesn't name, is refused before anything deploys.
  • Reset returns the computer to boot state: the driver ends its recordings, then a fresh container of the same image boots in the old one's place, readied as a deploy readies it. A sandbox provider that can't replace a container (Modal today) fails the reset step, naming itself, rather than skipping it. The computer keeps its address, so the agent's registered MCP URL stays valid, but an agent's MCP session ends with the old driver: the fresh one answers it with 404, after which an MCP client starts a new session (decided in review; Claude Code opens a new one every turn). Redeploying into a new sandbox instead was ruled out: a run's stored context can add a deployed env but not replace one, so the new address wouldn't be saved.
  • Env.close at teardown (M0.11): teardown_run and the teardown_sandboxes step share one core (task.teardown.tear_down). First the recordings the run left open end, each through its driver with a fresh grant, whatever env serves it; then each env still up closes under the per-sandbox timeout; a recording still open after that is registered from its namespace; then every sandbox is terminated by id as before and a local one's folder removed (the step now does both too). Env.close and Env.reset keep their signatures, so out-of-tree overrides are unaffected.
  • A computer env ends its own recordings. computer-recording/v1 gains end_all, which ends every recording not yet ended under the grant each started with, and every end uploads the manifest beside the segments (<recording_id>/manifest.json). A computer env's close and reset call it before the computer goes, so a recording open at a reset, or at a close outside a run's teardown, is saved too. Teardown, and end_computer_recording when the driver no longer knows a recording (as after a reset), register it from what its namespace holds, reading that manifest.
  • Env skills, and the computer's (M0.5): any env built on the protocol SDK can serve agents a skill. skill/v1 (SKILL_EXTENSION_URI) answers get {name} with {name, description, skill_md}, written under the name the caller gives, and an env serves it by marking the method that writes it with @agent_skill (description and body). The computer driver's base class serves one written from the computer as it booted, ending with the driver class's new notes; computer/v1 now only declares the seven tools and the driver's features, and the conformance probe checks the skill. add_skills takes env_ids: for each env the run deployed and bound to the agent, it installs the env's skill under its environment name (the agent's MCP alias for it, with a digest of the env id when the name had to be normalized or shortened) and records the SKILL.md in the run's context (env_skills).
  • data/get takes paths (decided in feat(computer): the computer env type and the composer (container forms) #358's review): a computer returns the files under the paths it's given, or under the default_data_paths its card declares (Desktop, Documents, Downloads). A get hook that doesn't take paths refuses them; one that does gets None when the call names none. ComputerSettings.data_paths is gone.
  • A recording on a computer with no network is refused at start, since its segments couldn't reach the store.
  • The desktop example (src/agent_env/examples/desktop/, the eighth shipped bundle): a computer env of ubuntu-24.04 and reference, a probe task (deploy, probe at full) and an agent task (Claude Code, given the computer skill, makes a folder through the file manager under a recording; the check reads it back through the driver).
  • The M0.3 scaffold is gone. Its probe and agent tasks are the example's; its scripted drive under a recording runs on the example env (tst/integration/computer/recording/); the recording chaos tests run on the example's composed image, with the conformance fixture started through computer-exec as the probe starts it.

Where this differs from the design

  1. A computer env ends its own recordings at close and reset (decided in review), through the driver's new end_all, instead of Env.close(context) and Env.reset(deployed, context) ending them from the run's context, which would have broken out-of-tree overrides of both. Teardown still ends the run's open recordings first, each with a fresh grant (decided in review of Greptile's finding that a recording served by another env type would lose its last segment). What remains: an end at reset uses the grant the recording started with, so on a store whose grants expire before a long recording is reset, the segments recorded after expiry are lost.
  2. Teardown terminates an env's sandboxes by id even after its close, instead of marking them torn down. A built-in close logs a failed terminate rather than raising, so trusting it could leak a sandbox; terminate_sandbox is idempotent, so the second terminate costs one lookup.
  3. A close that fails or times out is logged, and its sandboxes go into the report by what their terminate by id did, so failed keeps meaning "may still be running".
  4. env_params takes computer_settings and driver_settings (decided in review), one table per layer, instead of settings by layer and spaces.
  5. A deploy hides no tools (decided in feat(computer): the computer env type and the composer (container forms) #358's review): a task that wants fewer tools uses modify_env_tool_access, which works through the driver's disable-tool/v1.
  6. The skill is any env's, not the computer's (decided in review): skill/v1 and @agent_skill replace a skill method on computer/v1, and add_skills takes env_ids instead of computer_env_ids, so other env types can hand agents a skill the same way. get takes the name to write into the SKILL.md's frontmatter, so add_skills names it per env.
  7. A DeployedAgent records the env_ids its deploy_agent registered, since nothing in a run's context said which envs an agent is bound to.
  8. data/get paths and the driver's default replace data_paths (decided in feat(computer): the computer env type and the composer (container forms) #358's review; snapshot_env gains computer_file_paths in M1.8, FD-4382).
  9. The recording refusal on a computer with no network is new: local Docker's closed network relays only inbound, so a recording there could never upload.
  10. create_container takes no platform (decided in review). The design passed it so a provider would refuse a platform it would emulate, but both callers, the deploy and gate 3, choose a provider by native_platforms() first, so that check could never fire, and the new parameter broke out-of-tree overrides of create_container (the plugin-API check).

Review

Greptile's review of 9e775d5 raised seven threads. Six are fixed in 7655132, as the bullets above now say: teardown ends the run's open recordings first; gate 3 probes at the env's settings; a reset a provider can't carry out fails; skill names that come out alike get an env-id digest; a get hook that takes paths gets None; a failed closed-network boot removes its folder. The seventh, a secret setting given as its value reaching the deploy record, is fixed in 77cbffb (decided in review): a secret setting takes only a bare secret:KEY or env:NAME reference. The plugin-API check's break, create_container's new platform, is gone (difference 10); the check now reports no break. #358's fix for a driver file named outside the build folder (98e139a) applies here too.

Testing

  • Unit. Rebased onto main, and again with the secrets change, 11,341 passed; the one failure, the known test_deep_nesting timing flake, passes alone. On the review round before the rebase, 11,288 of 11,292 passed. Three failures were in the round's own new tests, which were fixed and rerun with their files (1,983 passed); the fourth is the known test_deep_nesting timing flake, which passes alone.
  • Integration (tst/integration/computer, laptop arm64, real Docker and the local registry), before the review round: 18 passed and 1 skipped (the agent task, which needs a model endpoint). The scripted-drive recording test failed that run: its pixel check compared against the recording's first frame, which can predate the Fixture Desk now that the drive starts it. Fixed to compare against the frame before the click, it passed twice on its own. CI's integration jobs run the same tier on Linux amd64.
  • Chaos on the laptop (arm64), 8/8, with deploy_chaos.py (scenarios from the design's chaos row; each also checks that no container, relay, network or work folder is left):
    • the driver killed mid-deploy: supervisord restarts it and the deploy goes on;
    • the computer killed mid-deploy: the deploy fails, naming the last thing it saw, and nothing is left. It waits out the 180 s ready timeout first, since readiness doesn't watch the container;
    • the computer killed mid-task: the call fails, and teardown still reports the sandbox terminated;
    • the probe's computer killed during gate 3: the pair fails at the probe, and env build resumes it to ready. This found a hang: the probe had no deadline, and on Docker Desktop a dead computer's connection stays open, so the put waited indefinitely. The probe now has 120 s;
    • a boot past its timeout: the deploy fails naming what it last saw;
    • a close with an open recording whose driver is gone: teardown goes on and registers the segment already uploaded;
    • two computer envs at once: separate sandboxes and ports, both pass the basic probe, deployed in 2.0 s;
    • teardown cancelled part-way: it returns what it reached, and a second teardown finishes the rest.
  • Chaos on EC2 (amd64, c6i.2xlarge), at 4ba6146: the same 8/8, and gate 3 again with Docker itself restarted mid-probe: the pair fails at the probe, and env build resumes it to ready once Docker is back. There the probe's computer dying fails fast, since the port closes with the container. The box had no arm64 emulation, so the arm64 pair fails at build, as gate 1 promises.
  • The agent run (agent-env run desktop --task agent, laptop only, the model key held in-process): passed in 52.7 s. Claude Code, given the computer's skill (then named computer-desktop; it is desktop since the review), made the folder through the file manager in 36.4 s, the check confirmed it through the driver, and the recording ended with 4 segments and none missing. Nothing was left.

🤖 Generated with Claude Code

RetriggerView in GreptileConfidence Score: 2/5

This PR needs fixes before merging: gateway-backed env skills fail, and two earlier blocking findings remain.

Fix All in CursorFindings

  1. P1 Gateway-backed skills cannot load ▶
  2. P1 Custom env cleanup gets skipped ▶
  3. P1 Secret overrides get refused ▶
  4. P2 Failed deploys leave folders ▶
Fix with agent prompt
### Issue 1
src/agent_env/task_step/task_steps/add_skills.py:313
An `MCPServerEnv` using its default `gateway` provider keeps its server's `@agent_skill` extension in a child card. `_env_skill` calls `invoke` without `environment_name`, so it checks only the gateway's card and raises “serves no skill.” This fails `add_skills` even though the server serves the skill.

Select the server's child card when fetching its skill, while keeping support for leaf cards.

### Issue 2
src/agent_env/task/teardown.py:undefined-213
`tear_down` sends every env through `close_deployed`, which reads `env._env_provider` before calling `close`. That private field is not part of the `Env` contract. A custom env can implement `from_deployed_env` and `close` and return a `DeployedSandboxEnv` without defining it. The helper then fails, and teardown stops the sandbox without letting the env save its final data.

Call the reconstructed env's public `close` method, keeping termination by id as the fallback.

### Issue 3
src/agent_env/env/envs/computer/gate.py:59-61
A secret setting with an `int`, `float`, or `bool` default can no longer be overridden. The new check rejects literal values, but a valid `env:NAME` or `secret:KEY` reference then fails the existing default-type check because it is a string. `Setting` allows these defaults, so both saving an env and deploying with an override fail for supported settings. Skip the literal-type comparison for secret references.

### Issue 4
src/agent_env/providers/env_providers/env_computer_provider.py:undefined-106
A computer that becomes ready but fails `_require_name` or `_require_display` leaves its local work folder behind. These checks run after `boot` returns, outside its `discard` cleanup. The provider's failure cleanup only calls `terminate`, which does not remove the folder. The failed deployment also leaves no run record for teardown to reclaim it.

Use `discard` when these post-boot checks fail so repeated failed deployments do not accumulate abandoned folders.

---

For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.

Summary

This PR adds computer env deployment on local Docker, fresh-container reset, build probes, recording cleanup, and a desktop example.

  • Computer environments boot on native providers and local Docker can isolate their network.
  • Computer builds are probed before they are marked ready.
  • Computer deployments accept separate computer and driver settings.
  • Computer recordings are saved when a computer resets or closes.
  • Agents can receive a skill written from the computer they use.
  • Computer file retrieval accepts requested paths and has a small default set.
  • A shipped desktop example replaces the test-only computer scaffold.
  • Protocol docs and compatibility checks describe the new computer workflow.

Diagram

%%{init: {'theme': 'neutral'}}%%
flowchart LR
  A["add_skills env_ids"] --> B["DeployedEnv.invoke"]
  B --> C["Top-level gateway card"]
  C --> D["Skill not found"]
  E["MCP server with @agent_skill"] --> F["Child card with skill/v1"]
  F -. "Requires environment_name" .-> B
Loading

Reviews (9) · Last reviewed commit: "feat(protocol): any env can serve agents..." · Reviewed by Greptile

Comment thread src/agent_env/task/teardown.py Outdated
Comment thread src/agent_env/task_step/task_steps/add_skills.py Outdated
Comment thread packages/agentenv-protocol/src/agentenv_protocol/agent_env_environment.py Outdated
@earakely-scale
earakely-scale force-pushed the edgararakelyan/fd-4358-m07-computer-envs-deploy-on-local-docker-the-computer-env branch from 496213f to 4ba6146 Compare October 28, 2026 16:42
@earakely-scale
earakely-scale force-pushed the edgararakelyan/fd-4356-m06-computer-env-type-and-the-composer-container-forms branch from 8b42cbb to f9cda77 Compare October 28, 2026 16:55
@earakely-scale
earakely-scale force-pushed the edgararakelyan/fd-4358-m07-computer-envs-deploy-on-local-docker-the-computer-env branch from 4ba6146 to d79d4ed Compare October 28, 2026 16:59
Comment thread src/agent_env/providers/env_providers/env_computer_provider.py Outdated
Comment thread src/agent_env/providers/sandbox_providers/local_sandbox.py
@earakely-scale
earakely-scale force-pushed the edgararakelyan/fd-4358-m07-computer-envs-deploy-on-local-docker-the-computer-env branch from d79d4ed to 9e775d5 Compare October 28, 2026 17:22
Comment thread src/agent_env/providers/env_providers/env_computer_provider.py
Comment thread src/agent_env/env/envs/computer/composer.py Outdated
@earakely-scale
earakely-scale force-pushed the edgararakelyan/fd-4356-m06-computer-env-type-and-the-composer-container-forms branch from 22348da to 572960c Compare October 28, 2026 17:32
Base automatically changed from edgararakelyan/fd-4356-m06-computer-env-type-and-the-composer-container-forms to main October 28, 2026 18:20
earakely-scale added a commit that referenced this pull request Oct 28, 2026
…e probe boots at the env's settings, no platform on create_container

From the review of #369:
- teardown ends the run's open recordings, each with a fresh grant whatever env serves it, before
  any env closes, so a recording on an env whose close doesn't end it keeps its last segment
- gate 3 boots a build at the env's computer_settings and display, as a deploy does
- a reset the sandbox provider can't carry out fails the step instead of being skipped
- a computer skill whose name had to be normalized or shortened takes a digest of the env id
- a data/get hook that takes paths gets None when the call names none
- a closed-network boot that fails removes its work folder
- create_container takes no platform: the deploy and gate 3 choose a provider by
  native_platforms() before calling it, so the refusal it carried never fired, and the new
  parameter broke out-of-tree overrides (the plugin-API check)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@earakely-scale
earakely-scale force-pushed the edgararakelyan/fd-4358-m07-computer-envs-deploy-on-local-docker-the-computer-env branch from 9e775d5 to f6e26fe Compare October 28, 2026 18:29
earakely-scale and others added 15 commits October 28, 2026 11:31
…iner's network away

create_container takes the platform its image must run as and refuses one the
provider doesn't run natively (native_platforms: this machine's for local,
linux/amd64 elsewhere). Local Docker enforces an allowlist of nothing for a
container: it runs on an internal network of its own, and a relay on that
network and the bridge publishes its port.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…each build, and deploy_env takes env_params

The computer env provider boots the env's first ready build that the sandbox
provider runs natively, with its deploy-phase settings and the driver's own,
waits for computer-ready, checks the display, hides the env's tools for every
role and records the driver's card as the env's. Gate 3 boots each build a
configured provider runs natively and probes it at full: ready with its card,
or failed at the probe; a build nothing here runs natively stays unverified.
deploy_env passes env_params to the env type's deploy() and checks them at save
for every env type.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…top folders

data/get passes `paths` to a get hook that takes them and refuses them otherwise; the client's
get_data sends them. A computer returns the files under the paths it's given, or under
DEFAULT_DATA_PATHS (Desktop, Documents, Downloads), which its card declares as
default_data_paths. ComputerSettings drops data_paths.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…dboxes go

Env.close(context) joins the base contract; built-ins take the context and ignore it. teardown_run
and the teardown_sandboxes step share one core (task.teardown.tear_down): each env still up closes
through close_deployed under the per-sandbox timeout, then every sandbox is terminated by id as
before (terminate_sandbox is idempotent, so a close that swallowed a failed terminate is still
covered) and a local one's folder removed, which the step now does too. A computer env's close ends
its open recordings; before_teardown keeps only the changelog drain. The shared helpers move from
the step module to task.teardown.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…omputer test

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Env.reset takes the run's context, which reset_env passes. ComputerEnv.reset ends the env's open
recordings, then the computer provider replaces its container with a fresh one of the image it
booted, its settings applied as the deploy applied them, on the same sandbox and host port, and
readies it as a deploy does (ready, display, hidden tools). SandboxProvider.recreate_container
removes and starts the container on a VM-backed sandbox; local Docker also replaces the relay of a
closed network, since the fresh container's address there may differ.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… refused at start

Its driver couldn't reach the store the segments upload to, so the start fails, recorded as any
failed start is, rather than recording segments that never arrive.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ed by add_skills

computer/v1 is served with a skill method: the driver base class writes a SKILL.md under the name
it's given from the computer as it booted (platform, session user and home, the live screen size,
what its input takes, a per-OS shortcut template, Linux for now, and the driver's new notes). Its
params are the driver's features, as before; the declaration keeps recording only those.

add_skills takes computer_env_ids: for each, an env this run deployed and bound to the agent (a
DeployedAgent now records the env_ids deploy_agent registered), it asks the driver for its skill
under computer-<environment name>, installs it, and records the SKILL.md in the run's context.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…rk folders

Gate 3's probe and a boot that fails partway tear down a sandbox no run records, so no run's teardown
removes its local work folder; they now discard it as teardown would.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The eighth shipped bundle: a computer env of ubuntu-24.04 and reference, a probe task (deploy,
probe at full) and an agent task (Claude Code, given the computer skill, makes a folder under a
recording; the check reads it back through the driver). The scaffold's probe and agent tasks are the
example's; its scripted drive under a recording runs on the example env; the recording chaos tests
run on the example's composed image, with the conformance fixture started through computer-exec.
The integration tests compose the example env once per module, and one deploys it with no network:
reached, reaching nothing, fresh after a reset, gone after teardown. Docs say a driver deploys only
as a computer env's driver, and how a computer env deploys.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… and reset take no context

The env, not the run, ends what runs on its computer: computer-recording/v1 gains end_all, which
ends every recording not yet ended under the grant each started with, and every end uploads the
manifest beside the segments. A computer env's close and reset call it before the computer goes.
Teardown then registers the recordings the run left open from their namespaces, reading the manifest
the driver uploaded (register_open_recordings), and end_computer_recording does the same when the
driver no longer knows a recording, as after a reset. So Env.close and Env.reset keep their
signatures, and an out-of-tree override of either is unaffected.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…y its computer and registered whole

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ings, one table per layer

A deploy sets the base's deploy-phase values in computer_settings, checked as the env's are, and the
driver's in driver_settings, checked by the protocol's ComputerSettings and passed in
AGENTENV_COMPUTER_SETTINGS; driver_settings replaces spaces, which set two of them.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…l_access

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…e probe boots at the env's settings, no platform on create_container

From the review of #369:
- teardown ends the run's open recordings, each with a fresh grant whatever env serves it, before
  any env closes, so a recording on an env whose close doesn't end it keeps its last segment
- gate 3 boots a build at the env's computer_settings and display, as a deploy does
- a reset the sandbox provider can't carry out fails the step instead of being skipped
- a computer skill whose name had to be normalized or shortened takes a digest of the env id
- a data/get hook that takes paths gets None when the call names none
- a closed-network boot that fails removes its work folder
- create_container takes no platform: the deploy and gate 3 choose a provider by
  native_platforms() before calling it, so the refusal it carried never fired, and the new
  parameter broke out-of-tree overrides (the plugin-API check)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@earakely-scale
earakely-scale force-pushed the edgararakelyan/fd-4358-m07-computer-envs-deploy-on-local-docker-the-computer-env branch from f6e26fe to 7655132 Compare October 28, 2026 18:35
its recordings). A type that can't close a deployment leaves them to be terminated by id."""
try:
async with asyncio.timeout(timeout):
await close_deployed(deployed, type(Env.get(deployed.env_id, deployed.env_version)))

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Custom env cleanup gets skipped

tear_down sends every env through close_deployed, which reads env._env_provider before calling close. That private field is not part of the Env contract. A custom env can implement from_deployed_env and close and return a DeployedSandboxEnv without defining it. The helper then fails, and teardown stops the sandbox without letting the env save its final data.

Call the reconstructed env's public close method, keeping termination by id as the fallback.

Prompt To Fix With AI
This is a comment left during a code review.
Path: src/agent_env/task/teardown.py
Line: 213

Comment:
**Custom env cleanup gets skipped**

`tear_down` sends every env through `close_deployed`, which reads `env._env_provider` before calling `close`. That private field is not part of the `Env` contract. A custom env can implement `from_deployed_env` and `close` and return a `DeployedSandboxEnv` without defining it. The helper then fails, and teardown stops the sandbox without letting the env save its final data.

Call the reconstructed env's public `close` method, keeping termination by id as the fallback.

---

For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.

Fix in Cursor Fix in Claude Code Fix in Codex

"computer_settings": recorded_settings(computer, values),
"env_params": params.model_dump(exclude_defaults=True)}},
)
await _require_display(record, values.get("resolution"))

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Failed deploys leave folders

A computer that becomes ready but fails _require_name or _require_display leaves its local work folder behind. These checks run after boot returns, outside its discard cleanup. The provider's failure cleanup only calls terminate, which does not remove the folder. The failed deployment also leaves no run record for teardown to reclaim it.

Use discard when these post-boot checks fail so repeated failed deployments do not accumulate abandoned folders.

Prompt To Fix With AI
This is a comment left during a code review.
Path: src/agent_env/providers/env_providers/env_computer_provider.py
Line: 106

Comment:
**Failed deploys leave folders**

A computer that becomes ready but fails `_require_name` or `_require_display` leaves its local work folder behind. These checks run after `boot` returns, outside its `discard` cleanup. The provider's failure cleanup only calls `terminate`, which does not remove the folder. The failed deployment also leaves no run record for teardown to reclaim it.

Use `discard` when these post-boot checks fail so repeated failed deployments do not accumulate abandoned folders.

---

For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.

Fix in Cursor Fix in Claude Code Fix in Codex

…erence

A secret setting given as its value, on the env or in deploy_env's env_params, was kept wherever
what's given is kept: the env, the task, the composed computer's defaults and the deploy record's
env_params, which reset reads back. check_computer_settings now refuses anything but a bare
reference, the form a stored context keeps, so only names are stored and every boot resolves them.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Comment on lines +59 to +61
elif setting.secret and not _names_a_secret(value):
problems.append(f"computer_settings.{name} is a secret, so it takes a {SECRET_REF_PREFIX}KEY or "
f"{ENV_REF_PREFIX}NAME reference with no ?default, not its value")

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Secret overrides get refused

A secret setting with an int, float, or bool default can no longer be overridden. The new check rejects literal values, but a valid env:NAME or secret:KEY reference then fails the existing default-type check because it is a string. Setting allows these defaults, so both saving an env and deploying with an override fail for supported settings. Skip the literal-type comparison for secret references.

Prompt To Fix With AI
This is a comment left during a code review.
Path: src/agent_env/env/envs/computer/gate.py
Line: 59-61

Comment:
**Secret overrides get refused**

A secret setting with an `int`, `float`, or `bool` default can no longer be overridden. The new check rejects literal values, but a valid `env:NAME` or `secret:KEY` reference then fails the existing default-type check because it is a string. `Setting` allows these defaults, so both saving an env and deploying with an override fail for supported settings. Skip the literal-type comparison for secret references.

---

For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.

Fix in Cursor Fix in Claude Code Fix in Codex

earakely-scale and others added 3 commits October 28, 2026 12:53
It resets the container create_container ran to a fresh one of the image, on the same sandbox and
port, which is what a computer env's reset uses it for; the provider guide now lists it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…MCP session

The fresh driver doesn't know the old one's MCP sessions and answers one with 404, after which an
MCP client starts a new session; Claude Code opens a new one every turn anyway.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…s env_ids

skill/v1 (SKILL_EXTENSION_URI) answers get {name} with {name, description, skill_md}: the env's
SKILL.md for agents under the name the caller gives. An env built on the SDK serves one by marking
the method that writes it with @agent_skill, which returns its description and body. The computer
driver's skill moves there from computer/v1, which is now declared with the driver's features, and
the conformance probe checks it. add_skills's computer_env_ids becomes env_ids: each env's skill is
installed under its environment name (the agent's MCP alias for it) and recorded in env_skills.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
"deploy_agent")
name = _env_skill_name((deployed.environment_card or {}).get("name") or env_id, env_id)
try:
return await deployed.invoke(SKILL_EXTENSION_URI, "get", {"name": name})

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Gateway-backed skills cannot load

An MCPServerEnv using its default gateway provider keeps its server's @agent_skill extension in a child card. _env_skill calls invoke without environment_name, so it checks only the gateway's card and raises “serves no skill.” This fails add_skills even though the server serves the skill.

Select the server's child card when fetching its skill, while keeping support for leaf cards.

Prompt To Fix With AI
This is a comment left during a code review.
Path: src/agent_env/task_step/task_steps/add_skills.py
Line: 313

Comment:
**Gateway-backed skills cannot load**

An `MCPServerEnv` using its default `gateway` provider keeps its server's `@agent_skill` extension in a child card. `_env_skill` calls `invoke` without `environment_name`, so it checks only the gateway's card and raises “serves no skill.” This fails `add_skills` even though the server serves the skill.

Select the server's child card when fetching its skill, while keeping support for leaf cards.

---

For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.

Fix in Cursor Fix in Claude Code Fix in Codex

This branch has not been deployed

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant