Skip to content

feat(sandbox): add localhost forwards to the CLI and SDK - #1124

Merged
DamianB-BitFlipper merged 3 commits into
mainfrom
feature/sandbox-localhost-forwards
Oct 29, 2026
Merged

DamianB-BitFlipper merged 3 commits into
mainfrom
feature/sandbox-localhost-forwards

Conversation

@DamianB-BitFlipper

@DamianB-BitFlipper DamianB-BitFlipper commented Oct 28, 2026 •

Copy link
Copy Markdown
Contributor

What

Adds CLI and SDK support for sandbox localhost forwards (platform: PrimeIntellect-ai/platform#7138). A forward makes a VM sandbox's own 127.0.0.1:PORT / [::1]:PORT reach the same port on a LAN peer. Docker Compose services that share one network namespace (network_mode: "service:X", localhost URLs) can then run as separate sandboxes.

The forwards live in sandboxd, inside the sandbox. The SDK calls GET/POST {gateway}/{user_ns}/{job_id}/network/local-forwards through sandbox-gateway, the same way read_file and upload_file already work. There's no control-plane endpoint, and changes apply before the call returns.

CLI

prime sandbox network localhost APP_ID 5432:DB_ID   # inside APP_ID, localhost:5432 reaches DB_ID's port 5432
prime sandbox network localhost APP_ID              # show
prime sandbox network localhost APP_ID --clear      # remove all

Each call replaces the whole set; pass several PORT:PEER arguments to forward several ports. Both sandboxes must share a LAN network whose rules allow the port; otherwise connections are reset. -o json is supported.

SDK (SandboxClient and AsyncSandboxClient)

  • get_localhost_forwards(sandbox_id) -> List[LocalhostForward]
  • set_localhost_forwards(sandbox_id, forwards) -> List[LocalhostForward]

Errors:

  • 400 (invalid set) and 409 (a port is already bound in the sandbox) raise APIError with sandboxd's message.
  • 404 means the sandbox predates the feature, so the user is told to recreate it.
  • 401 re-authenticates once and retries.

Merge order

Merge after platform#7138's sandboxd is deployed. Until then, sandboxes answer 404.

Tests

  • prime-sandboxes tests/test_egress_policy.py passes (51). The tests mock the gateway: they check the sync POST payload, 409 and 404 errors, async GET, and the port range.
  • The full prime-sandboxes suite passes (409, 33 skipped).
  • prime tests/test_sandbox_network_lan.py tests/test_sandbox_cli.py passes (64).
  • ruff and ty are clean.

🤖 Generated with Claude Code


Note

Medium Risk
Changes sandbox networking behavior via in-VM forwards and gateway calls; misconfiguration could break app connectivity, but scope is additive with explicit replace semantics and depends on deployed sandboxd.

Overview
Adds localhost forwards so a VM sandbox can treat its own loopback ports as tunnels to the same port on a LAN peer (PEER.sandbox.internal), enabling multi-sandbox setups that behave like shared-network Compose stacks.

The SDK introduces LocalhostForward plus get_localhost_forwards / set_localhost_forwards on sync and async clients. Updates go through sandbox-gateway to sandboxd (GET/POST …/network/local-forwards), with full replace semantics, 401 retry, and clear errors when the sandbox is too old (404) or the request fails.

The CLI adds prime sandbox network localhost to show, replace (PORT:PEER, repeatable), or --clear forwards, with table/json output and validation (malformed specs, duplicate ports). Docs in examples/README.md document the workflow and LAN rule requirement.

Tests cover gateway wiring, error mapping, model validation, and CLI parsing/invocation.

Reviewed by Cursor Bugbot for commit 65bd3fc. Bugbot is set up for automated code reviews on this repo. Configure here.

`prime sandbox network localhost SANDBOX_ID PORT:PEER ...` replaces a VM
sandbox's localhost forwards (show with no forwards, --clear to remove).
Each forward makes the sandbox's 127.0.0.1:PORT reach the same port on a
LAN peer. SandboxClient and AsyncSandboxClient gain
get_localhost_forwards / set_localhost_forwards.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Oct 28, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-10-28T22:48:10.782492Z 58c900f PR opened
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

DamianB-BitFlipper and others added 2 commits October 28, 2026 21:38
The platform REST endpoint is gone; sandboxd serves GET/POST
/network/local-forwards behind the sandbox gateway and applies the
replacement synchronously. get/set_localhost_forwards now return the
current List[LocalhostForward] (wire field peer_sandbox_id), and
LocalhostForwardsStatus is removed.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@DamianB-BitFlipper
DamianB-BitFlipper merged commit b76590c into main Oct 29, 2026
27 checks passed
@DamianB-BitFlipper
DamianB-BitFlipper deleted the feature/sandbox-localhost-forwards branch October 29, 2026 15:42
mikasenghaas added a commit to PrimeIntellect-ai/verifiers that referenced this pull request Nov 2, 2026
## Summary

- Raise the `prime-sandboxes` floor from `>=0.5.1` to `>=0.5.3` and
relock (`uv.lock`: 0.5.1 → 0.5.3).
- Supersedes #3033, which bumps to 0.5.2. That version still caps live
processes at 24h.

### SDK changes pulled in (0.5.1 → 0.5.3)

0.5.3:
- **fix(sandboxes): stop capping live processes at 24h**
(PrimeIntellect-ai/prime#1142). `open_process` sent a fixed 24h stream
deadline, and the sandbox ended the process when it expired.
`open_process(timeout=None)` now sends the largest Connect deadline
(about 115 days). The process then lives as long as its sandbox.
`PrimeBackend.exec` passes no `timeout`, so it gets the uncapped default
with no code change.

0.5.2:
- feat(sandbox): add localhost forwards to the CLI and SDK
(PrimeIntellect-ai/prime#1124)
- feat(sandboxes): add pause and resume to the SDK and CLI
(PrimeIntellect-ai/prime#1056)
- fix(cli): write credential files owner-only
(PrimeIntellect-ai/prime#1130). The SDK writes `sandbox_auth_cache.json`
with mode 0600 and its directory with mode 0700.

## Verification

Before (0.5.1): a long agent segment on Prime hit the SDK's 24h stream
cap. The ACP runner's stdout closed, and the trace stopped as
`harness_error` (`EOFError: ACP process closed its stdout`) instead of
`agent_timeout`.

After (0.5.3):
- `prime_sandboxes.sandbox._LIVE_PROCESS_NO_TIMEOUT_MS == 9999999999`,
the default for every `open_process` stream.
- `pytest tests/unit -k "prime or runtime"` passes.
- `PRIME_API_KEY=... pytest tests/unit/test_runtimes.py -k prime` passes
against live Prime (10 tests, including `test_exec` on a live process).

🤖 Generated with [Claude Code](https://claude.com/claude-code)

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Medium Risk**
> Only a dependency bump locally, but it changes long-running process
behavior on the production Prime sandbox path where agent rollouts
depend on stable streams.
> 
> **Overview**
> Raises the **`prime-sandboxes`** floor from **`>=0.5.1`** to
**`>=0.5.3`** in `pyproject.toml` and refreshes **`uv.lock`** so
installs resolve to 0.5.3.
> 
> There are **no application code changes** in this repo; verifiers
picks up upstream SDK behavior for the **Prime runtime**
(`PrimeBackend`). The main motivation is **0.5.3’s fix** that stops
long-lived sandbox processes from dying when `open_process` used a fixed
~24h stream deadline—runs that previously failed with harness stdout
**`EOFError`** should now stay alive for the life of the sandbox.
**0.5.2** also adds pause/resume, localhost forwards, and tighter
credential file permissions on the SDK side.
> 
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
18b4d05. Bugbot is set up for automated
code reviews on this repo. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->

<!-- Macroscope's pull request summary starts here -->
<!-- Macroscope will only edit the content between these invisible
markers, and the markers themselves will not be visible in the GitHub
rendered markdown. -->
<!-- If you delete either of the start / end markers from your PR's
description, Macroscope will append its summary at the bottom of the
description. -->
> [!NOTE]
> ### Bump minimum `prime-sandboxes` to 0.5.3
> Raises the dependency floor from 0.5.1 to 0.5.3 in
[pyproject.toml](https://github.com/PrimeIntellect-ai/verifiers/pull/3043/files#diff-50c86b7ed8ac2cf95bd48334961bf0530cdc77b5a56f852c5c61b89d735fd711)
and refreshes
[uv.lock](https://github.com/PrimeIntellect-ai/verifiers/pull/3043/files#diff-84321598744d84dbee2318e634c74c9aae39a1c253f1c4bd17ebf9ef2f807b11).
>
> <!-- Macroscope's review summary starts here -->
>
> <sup><a href="https://app.macroscope.com">Macroscope</a> summarized
18b4d05.</sup>
> <!-- Macroscope's review summary ends here -->
>
<!-- Macroscope's pull request summary ends here -->

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
mikasenghaas added a commit to PrimeIntellect-ai/prime-rl that referenced this pull request Nov 2, 2026
## Summary

- Bump `prime-sandboxes` 0.5.1 → 0.5.3 so live sandbox processes are no
longer capped at 24h (via PrimeIntellect-ai/verifiers#3043).
- Bump `deps/verifiers` `60290d4` → `bccc2c5` (verifiers main, with
PrimeIntellect-ai/verifiers#3043 merged).
- Require `prime-runs[train]>=0.1.5` from PyPI. This drops the
`prime-runs` git source and the `prime-traces` git override, both pinned
to `adf8d25c`. The new verifiers requires `prime-runs>=0.1.5`
(PrimeIntellect-ai/verifiers#3001), and the old git pin no longer
resolves. 0.1.5 contains `adf8d25c`, so it includes
PrimeIntellect-ai/prime#1109. `uv.lock`: `prime-runs` 0.1.4 (git) →
0.1.5, `prime-traces` 0.0.10 (git) → 0.0.11.

### Why

On Prime, the SDK sent a fixed 24h deadline on every live process
stream, and the sandbox ended the process when it expired. A long agent
segment then lost its ACP process. The trace stopped as `harness_error`
(`EOFError: ACP process closed its stdout`) instead of `agent_timeout`,
so `agent_timeout` undercounted real 24h cap hits.

### prime-sandboxes changes (0.5.1 → 0.5.3)

0.5.3:
- fix(sandboxes): stop capping live processes at 24h
(PrimeIntellect-ai/prime#1142)

0.5.2:
- feat(sandbox): add localhost forwards to the CLI and SDK
(PrimeIntellect-ai/prime#1124)
- feat(sandboxes): add pause and resume to the SDK and CLI
(PrimeIntellect-ai/prime#1056)
- fix(cli): write credential files owner-only
(PrimeIntellect-ai/prime#1130); the SDK auth cache is written 0600

### verifiers changes (`60290d4` → `bccc2c5`)

Fixes and features:
- fix(serve): discard kept episodes when clients disconnect
(PrimeIntellect-ai/verifiers#2997)
- Reuse interception tunnels for task-scoped MCP servers
(PrimeIntellect-ai/verifiers#3006)
- Run Prime task services as native VMs and fix Harbor setup
(PrimeIntellect-ai/verifiers#2910)
- Run Compose services as native Prime VMs
(PrimeIntellect-ai/verifiers#2918)
- Accept Harbor Compose tasks on native VMs
(PrimeIntellect-ai/verifiers#2999)
- Add a native Compose integration test on Prime
(PrimeIntellect-ai/verifiers#3010)
- fix(harbor): reject ignored verifier user overrides
(PrimeIntellect-ai/verifiers#3014)
- Honor configured disk size for native Compose sidecars
(PrimeIntellect-ai/verifiers#3018)
- Size native Compose disks per service
(PrimeIntellect-ai/verifiers#3020)
- fix: use apk-installed Node and npm on Alpine
(PrimeIntellect-ai/verifiers#3004)
- fix: retry Node downloads before extracting
(PrimeIntellect-ai/verifiers#3005)
- fix(CVE-2026-111497) in Brotli and Node
(PrimeIntellect-ai/verifiers#2998)

Dependency pins:
- bump prime-sandboxes to 0.5.3 (PrimeIntellect-ai/verifiers#3043)
- chore: require prime-runs 0.1.5 from PyPI
(PrimeIntellect-ai/verifiers#3001)

Harness versions:
- Bump Codex to 0.166.0 and codex-acp to 2.5.0
(PrimeIntellect-ai/verifiers#3021)
- Bump DeepSeek harness to 0.2.1-rc.5 (PrimeIntellect-ai/verifiers#3023)
- Bump mini-swe-agent's LiteLLM dependency to 1.106.6
(PrimeIntellect-ai/verifiers#3031)
- Bump Hermes Agent to v0.22.5 (PrimeIntellect-ai/verifiers#3024)
- Bump Claude Code to 2.1.314 and claude-agent-acp to 0.99.1
(PrimeIntellect-ai/verifiers#3022)
- Bump Kimi Code to 2.4.1 (PrimeIntellect-ai/verifiers#3025)
- Bump OpenCode to 2.2.5 (PrimeIntellect-ai/verifiers#3026)
- Bump OpenClaw to 2026.10.9 (PrimeIntellect-ai/verifiers#3027)
- Bump Prime Agent to 0.10.2 (PrimeIntellect-ai/verifiers#3028)
- Bump nano-rlm to e4d4407f (PrimeIntellect-ai/verifiers#3029)
- Bump Terminus 2 to Harbor 0.25.0 (PrimeIntellect-ai/verifiers#3030)

Dependabot lockfile bumps in verifiers (they do not change prime-rl's
lock):
- urllib3 2.7.0 → 2.8.0 (PrimeIntellect-ai/verifiers#2733), pyjwt 2.13.0
→ 2.15.0 (PrimeIntellect-ai/verifiers#2735), opentelemetry-api 1.44.0 →
1.45.1 (PrimeIntellect-ai/verifiers#2964), authlib 1.7.2 → 1.9.1
(PrimeIntellect-ai/verifiers#2990), msgpack 1.2.1 → 1.2.3
(PrimeIntellect-ai/verifiers#2991), litellm 1.98.0 → 1.100.4
(PrimeIntellect-ai/verifiers#2992), dnspython 2.8.0 → 2.9.0
(PrimeIntellect-ai/verifiers#2993), filelock 3.32.4 → 4.2.1
(PrimeIntellect-ai/verifiers#3002), virtualenv 21.14.12 → 21.14.13
(PrimeIntellect-ai/verifiers#3008), joserfc 1.7.4 → 1.7.6
(PrimeIntellect-ai/verifiers#3017), oauthlib 3.3.1 → 4.0.0
(PrimeIntellect-ai/verifiers#3035)

## Verification

- `uv sync --frozen --all-packages --all-extras` installs
`prime-sandboxes` 0.5.3.
`prime_sandboxes.sandbox._LIVE_PROCESS_NO_TIMEOUT_MS == 9999999999` is
the default deadline for every `open_process` stream.
- `uv.lock` changes only `prime-sandboxes`, `prime-runs` and
`prime-traces` (plus a uv-written reorder of the `exclude-newer-package`
table).
- `pytest tests/unit --ignore=tests/unit/train`: 837 passed, 1 xfailed.
- `tests/unit/train` (RTX PRO 6000 Blackwell, SM120):
`qwen3_8_flash_next` and `test_fp8_grouped_gemm` show the same failures,
and `test_fused_lm_head.py::test_inject_prime_lm_head_vanilla` kills the
process, on this branch and on `main` (`823ed27`). These GPU kernel
tests do not touch this diff.
- verifiers#3043: the live Prime runtime tests
(`tests/unit/test_runtimes.py -k prime`, including `test_exec` on a live
process) pass on 0.5.3.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants