Skip to content

claude code sandboxed agent - #4062

Closed
ertkonuk wants to merge 8 commits into
mainfrom
tkonuk/claude-code-sandboxed-agent
Closed

ertkonuk wants to merge 8 commits into
mainfrom
tkonuk/claude-code-sandboxed-agent

Conversation

@ertkonuk

@ertkonuk ertkonuk commented Oct 5, 2026

Copy link
Copy Markdown

What does this PR do?

Adds claude code sandboxed agent

Validation

Rollouts

Compatibility and benchmark impact

Checklist

  • I have read the contributing guidelines.
  • The change is focused; unrelated "drive-by" edits are tracked as separate issues/PRs.
  • Tests added or updated and pass locally, or N/A for docs-only / non-code changes (so CI unit/server checks pass when applicable).
  • Documentation added or updated, or N/A with justification.
  • Pre-commit checks pass locally (pre-commit run --all-files) (so CI lint/format checks pass).
  • New source files include the required Apache-2.0 SPDX header.
  • All commits have DCO sign-off (git commit -s) (so the DCO check passes).

sdevare-nv and others added 6 commits October 5, 2026 13:20
…tion, not content

conversation_digest hashed every request item including the harness's
system prompt. OpenCode regenerates that prompt per request with today's
date, so the first model call after 00:00 UTC in any running session no
longer matched its parent's recorded context: resolve_node returned
UNRESOLVED (no_match), the call was poisoned, and the finalizer rejected
the whole rollout. In a run whose step spanned 2026-09-24 00:00 UTC, 453 of
512 rollouts (every rollout that made calls on both sides of midnight)
became placeholder rows; the healthy rollouts were exactly those that ran
entirely before or entirely after midnight.

system/developer items now contribute only their role and position to the
digest. User, assistant and tool turns are hashed as before, so a
summarized or rewritten conversation still fails verification. Reusing the
parent's tokens then serves the instruction text the model actually saw,
which is what the training rows need. FINGERPRINT_VERSION bumps to 2.

[tkonuk: FINGERPRINT_VERSION 3 here, since #3382 already bumps it to 2]
Signed-off-by: Tugrul Konuk <tkonuk@nvidia.com>
Claude Code echoes a served tool call after normalizing it: it drops a
redundant `cd <cwd> &&` from Bash commands and maps legacy tool names
(Task to Agent). The assistant fingerprint hashed the call's name and
arguments, so the echo no longer matched the served call. That request
and every later one in the conversation recorded unresolved_parent, and
the fail-closed receipt masked the rollout. In an OpenCode + Claude Code
SWE run, nearly every Claude Code rollout was poisoned this way.

A tool call with a call id is now identified by that id alone
(FINGERPRINT_VERSION 4). The backend issues the id and the harness echoes
it verbatim; the name and arguments are what the harness executed. Calls
without an id keep name and arguments as identity. conversation_digest
still covers echoed arguments, so an earlier turn rewritten between two
requests still fails context verification, and token_in splicing still
trains the tokens the model produced.

A reply that adds no model-authored content (reasoning only) left its
request's fingerprint unchanged and was indexed under it, so every
request continuing the previous turn became ambiguous. Claude Code drops
such a reply and retries with a nudge. These calls are no longer lookup
candidates (their ledger rows carry no fingerprint), and the ledger now
verifies each candidate's context before counting candidates, as
RolloutLineage.resolve_node already did.

Replaying a recorded live Claude Code session (33 requests, main agent
and 4 subagents) through the resolver: 4 unresolved calls before, 0 after.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tugrul Konuk <tkonuk@nvidia.com>
Run the Claude Code CLI (`claude -p`) inside the task's own sandbox as a
SandboxedHarnessAgent, next to opencode_sandboxed_agent. Model calls go to
the Gym model server's /v1/messages route under the rollout's capture
prefix, so training-token capture records every call.

- Install from a staged binary (copied out of its read-only mount and made
  executable; a musl build is optional) or the official installer, then
  check the version the binary reports.
- A fresh CLAUDE_CONFIG_DIR, settings file, binary and stream-json
  transcript per rollout under remote_work_dir, outside the repository;
  stdin closed; the CLI is stopped harness_timeout_margin_s before
  sandbox_timeout.
- The full harness (not --bare, Claude Code's minimal mode), user settings
  only, no auto-memory, tools that do not fit a one-shot sandbox run
  disallowed, every model role routed to `model`, no telemetry and no
  per-request attribution text (it would change the system prompt on every
  call and break the capture's call chain).
- Longer header wait (CLAUDE_STREAM_FIRST_BYTE_TIMEOUT_MS) and request
  timeout: the model server sends a streamed reply's headers only after
  generation finishes.
- auto_compact: false turns compaction off (DISABLE_COMPACT,
  DISABLE_AUTO_COMPACT, autoCompactEnabled); capture cannot follow it.
- The transcript keeps the main conversation; observations come from the
  session transcripts through claude_code_agent.observability.

Add <server>_claude_code.yaml wiring for the five SWE resources servers,
mirroring the OpenCode ones, and let those servers accept the agent
(allowed_agents): they verify by diffing the repository in the sandbox,
whichever harness edited it. Exclude both sandboxed agents' results
directories from package discovery: a long run leaves tens of thousands
of them, and walking them stalled every package build for up to an hour.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Signed-off-by: Tugrul Konuk <tkonuk@nvidia.com>
Rewrite claude_code_sandboxed_agent on the pattern of opencode_sandboxed_agent
instead of a shared base class: the agent seeds the task through its resources
server, attaches to the seeded sandbox, runs `claude -p` once under
sandbox_timeout, reads the stream-json transcript on the host, grades through
verify_agent_response and stops the sandbox. Nothing but the Claude Code binary
is needed inside the sandbox. The command, environment, settings, install and
transcript parsing are unchanged.

New on the /run result, beside the verifier's fields and the execution fields
every sandboxed agent reports (finished, exit code, error type, failed, export
found, results path, stdout, stderr):
- how the session ended, from its final result event: result_success,
  result_error, result_missing (the deadline or a crash cut it off),
  context_overflow, duration_s;
- what it did, main conversation and subagents together: main_turns,
  subagent_turns, subagent_calls, tool_calls, tool_errors (calls Claude Code
  refused) and unknown_tool_calls (refused for naming a tool that does not
  exist).
All are plain numbers, so a trainer can aggregate them per harness without
reading transcripts. A generation.json receipt is written before grading, and
execution_failure_reward_zero grades a failed run as an empty response, as the
OpenCode agent does.

Rollout collection now reaches agents through environment servers, so each SWE
wiring config declares <server>_claude_code_environment_server beside the
agent; the name differs from the OpenCode wiring's <server>_environment_server
because a training run loads both.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Signed-off-by: Tugrul Konuk <tkonuk@nvidia.com>
…nset

BaseVerifyResponse always carries the field; the end-to-end test asserted its absence instead of its value.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Signed-off-by: Tugrul Konuk <tkonuk@nvidia.com>
One call in app.py and five test lines were over the formatter width.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Signed-off-by: Tugrul Konuk <tkonuk@nvidia.com>
@ertkonuk
ertkonuk requested a review from a team as a code owner October 5, 2026 20:35
@copy-pr-bot

copy-pr-bot Bot commented Oct 5, 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.

@ertkonuk ertkonuk changed the title Tkonuk/claude code sandboxed agent claude code sandboxed agent Oct 5, 2026
This reverts commit e459b7f.

Signed-off-by: Tugrul Konuk <tkonuk@nvidia.com>
… by position, not content"

This reverts commit ffc40c2.

Signed-off-by: Tugrul Konuk <tkonuk@nvidia.com>
@yaoyu-33 yaoyu-33 added 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 labels Oct 5, 2026
@github-actions github-actions Bot added the sla:triage-overdue Review assignment is over the one-business-day SLA label Oct 6, 2026
@zyzhou5

zyzhou5 commented Oct 9, 2026

Copy link
Copy Markdown
Contributor

@ertkonuk Could you fill in the PR description with what changed and how you validated it, including any rollout results?

@zyzhou5 zyzhou5 added waiting-on-customer Waiting on the original author to respond and removed needs-review PR is ready for code review and waiting on a reviewer labels Oct 13, 2026
@oyilmaz-nvidia

Copy link
Copy Markdown
Contributor

@ertkonuk Can you please fill in the PR description? It's been a week since the PR was created and we started to close the PRs that doesn't have any activity in a week.

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 sla:triage-overdue Review assignment is over the one-business-day SLA waiting-on-customer Waiting on the original author to respond

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants