Skip to content

feat(claude-code): support owned and borrowed sandbox sessions - #4745

Merged
lafrancef merged 8 commits into
mainfrom
flafrance/claude-code-sandbox
Oct 21, 2026
Merged

lafrancef merged 8 commits into
mainfrom
flafrance/claude-code-sandbox

Conversation

@lafrancef

@lafrancef lafrancef commented Oct 19, 2026 •

Copy link
Copy Markdown
Contributor

Run Claude Code in agent-owned or borrowed sandboxes through the existing agent-session API. Configure sandbox_provider, sandbox_config, and an exact claude_code_version, or supply SandboxAccess when seeding a session. The agent README and YAML document setup and supported inputs.

The adapter follows the other sandboxed harnesses: ClaudeCodeAgent owns session hooks and dispatch, while ClaudeCodeSandboxSession delegates supervision and release to SandboxSession. Native stdout, stderr, and runtime identity have separate artifacts. Interrupted activations report a cancelled sandbox outcome. Close waits for cleanup and captured-artifact parsing within bounds, retaining native observations when close overlaps parsing; it also returns observations if no activation ran. Repeating the same activation returns its result; a different request receives 409.

Runtime setup works without sandbox internet access. Gym downloads the native release for the sandbox's architecture/libc into the current user's owned, mode-0700 ~/.cache/nemo_gym/claude directory. Verified file identities are memoized within each worker; changed files are reverified. Compressed transfers share a four-chunk limit across sessions, staging at most 4 MiB per worker instead of a full archive per seed. The sandbox verifies the decompressed SHA-256 and version before atomically installing a shared, versioned runtime. Subsequent seeds in the same sandbox verify and reuse it without uploading the binary; sandboxes without a verified runtime receive the transfer. An offline Gym host can set sandbox_local_executable_path; a binary already in the sandbox can use sandbox_executable_path. Either supplied-binary option requires sandbox_executable_sha256. The worker scripts support Linux Python 3.8+.

Local prompt handling, explicit skills_ref, command options, and subprocess behavior are preserved. Configured skills.path fallback applies only to sandbox sessions. In sandbox sessions using model_server, both Anthropic authentication variables use placeholders; the configured direct credential stays on the Gym host. The local setup-timing change is intentional: host CLI installation happens on first local use, rather than server startup, to avoid installing an unused host CLI on sandbox-only servers. Concurrent local setup shares one attempt, and failures can be retried.

Sandbox inputs accept a single user text prompt, optionally preceded by a system message. metadata.agent_timeout_sec sets a per-task execution budget capped by the configured timeout; other metadata keys receive 422. History, developer/assistant messages, and request instructions receive 422 rather than being discarded. The harness implementation is under responses_api_agents/claude_code_agent/. The config migration script also recognizes Claude Code's unbound native template, preserving legacy wrappers for resource-bound local configurations; regression tests cover both forms and inherited bindings. The default YAML selects native composition, so legacy --resources-server X --agent-type claude_code_agent swap configurations must explicitly restore resources_server: {type: resources_servers, name: "???"} on the agent. Existing bound recipes keep their bindings. nemo_gym/ is unchanged. No separate issue is needed for this focused harness capability.

Live validation on 11ccc88f8b28 used Claude Code 2.1.108 and gpt-4.1-mini in a borrowed OpenSandbox through the standard EnvironmentServer → Resources → Agent → verifier flow. With sandbox egress denied, runtime setup used host-staged bytes and model traffic used a test-only file-transfer relay to Gym's model server. A request carrying a 90-second task budget completed with native exit 0; independent repair checks improved from 2/8 to 8/8 (reward 1), with 8 native observation records and no gaps. Checked the staged input uses placeholder proxy credentials, the host cache is private, and the native binary and compressed archive are each hashed once across reseeding. Verified agent close before grading, runtime reuse without re-upload, unused-session close observations, and resource teardown.

Validation

Commands run against the same revision:

.venv/bin/pytest -q -o addopts= \
  tests/unit_tests/test_add_legacy_agent_environment_servers.py \
  responses_api_agents/claude_code_agent/tests

ng_test +entrypoint=responses_api_agents/claude_code_agent \
  +delete_venvs_after_each_test=true +should_validate_data=true

pre-commit run --all-files

The focused suite passed 211 tests (52 migration and 159 Claude Code); isolated ng_test passed all 159 Claude Code tests. Pre-commit passed locally and on Linux; the private guardword catalog was unavailable, so that scan was skipped.

CI-equivalent core and sandbox commands on Linux:

bash scripts/ci/core_unit_tests.sh
source scripts/ci/setup_dev.sh
uv sync --extra dev --extra ray --extra sandbox --extra openshell --extra mlflow --extra wandb
pytest --cov=. --cov-append --cov-report=term-missing \
  --cov-fail-under="$(python3 scripts/ci/cov_fail_under.py)" --durations=10 -m sandbox

Core: 9,304 passed, 28 skipped. Sandbox: 928 passed, 6 skipped. Combined coverage: 95.14%, above the checkout's 95% gate.

Full server suite:

bash scripts/ci/server_tests.sh 0 2
bash scripts/ci/server_tests.sh 1 2

Both shards exited 1; all 236 modules were attempted. After isolated reruns, 213 modules passed. The remaining 23 were blocked during dependency installation (21 GitHub HTTP 503 responses and two PyTorch CDN connection resets), so full-suite success is not claimed.

Signed-off-by: Frederic Lafrance <flafrance@nvidia.com>
@copy-pr-bot

copy-pr-bot Bot commented Oct 19, 2026

Copy link
Copy Markdown

This pull request requires additional validation before any workflows can run on NVIDIA's runners.

Pull request vetters can view their responsibilities here.

Contributors can view more details about this message here.

@lafrancef lafrancef added area:agent Agent harnesses and Responses API agent behavior feature New capabilities, enhancements, or enablement work labels Oct 19, 2026
Signed-off-by: Frederic Lafrance <flafrance@nvidia.com>
…havior

Signed-off-by: Frederic Lafrance <flafrance@nvidia.com>
Signed-off-by: Frederic Lafrance <flafrance@nvidia.com>
@lafrancef

Copy link
Copy Markdown
Contributor Author

/ok to test d77400b

Signed-off-by: Frederic Lafrance <flafrance@nvidia.com>
@lafrancef

Copy link
Copy Markdown
Contributor Author

/ok to test d859b91

@nemo-automation-bot
nemo-automation-bot Bot requested review from a team October 19, 2026 19:39
@yaoyu-33 yaoyu-33 added complexity:high Cross-component or shared-contract change with a large review surface needs-review PR is ready for code review and waiting on a reviewer labels Oct 19, 2026
Signed-off-by: Frederic Lafrance <flafrance@nvidia.com>
@lafrancef

Copy link
Copy Markdown
Contributor Author

/ok to test ef18b3a

@yaoyu-33 yaoyu-33 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Thanks for the follow-up, @lafrancef. Both earlier threads are addressed at ef18b3af5a58: close now waits for captured-artifact parsing, and metadata.agent_timeout_sec is honored with the configured ceiling. This brings claude_code_agent in line with the other sandboxed harnesses; nothing here is blocking.

Before merge

  • The branch conflicts with main in scripts/add_legacy_agent_environment_servers.py and its test. main added kilocode_agent and a stirrup_agent early return, so the merged set should keep both alongside claude_code_agent. Could you rebase?

Inline comments: four risks (the --agent-type swap migration note, the API key reaching the sandbox with a Gym model server, the shared /tmp host cache as the trust anchor, and serialized host hashing plus per-seed upload copies), plus two small notes (the cancelled outcome and a weak 409 test assertion).

PR description

  • Could the body list the exact local test and pre-commit commands run, and the commit the live smoke run used?

Local check at ef18b3af5a58: responses_api_agents/claude_code_agent/tests 149 passed; tests/unit_tests/test_add_legacy_agent_environment_servers.py 48 passed.

Signed-off-by: Frederic Lafrance <flafrance@nvidia.com>
Signed-off-by: Frederic Lafrance <flafrance@nvidia.com>
@lafrancef

Copy link
Copy Markdown
Contributor Author

/ok to test 11ccc88

@marta-sd marta-sd left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

All comments were addressed so I'm approving

@lafrancef
lafrancef added this pull request to the merge queue Oct 21, 2026
@github-actions

Copy link
Copy Markdown
Contributor

🔄 Merge queue validation started! You can track the progress here: https://github.com/NVIDIA-NeMo/Gym/actions/runs/39570394529

Merged via the queue into main with commit 8035cfd Oct 21, 2026
50 of 56 checks passed
@lafrancef
lafrancef deleted the flafrance/claude-code-sandbox branch October 21, 2026 08:53

This branch was previously deployed

1 inactive deployment
public — 11ccc88f Deployed Oct 21, 2026 by copy-pr-bot[bot] via release / finalize / notify #6183
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area:agent Agent harnesses and Responses API agent behavior complexity:high Cross-component or shared-contract change with a large review surface feature New capabilities, enhancements, or enablement work needs-review PR is ready for code review and waiting on a reviewer

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants