Skip to main content

external-sandbox-container

A Python execution server for coding agents, managed with uv. It implements the shared external sandbox protocol, alongside external-sandbox-v86 and external-sandbox-quicksand, and executes commands in a Linux container managed by Apple's container CLI. This version implements Apple Container only.

The experiment: keep the coding-agent integration and client protocol constant, and change the execution sandbox. Claude Code uses the existing shell-prefix client at /exec/ws. Codex uses its exec-server protocol at /codex, including filesystem operations and native apply_patch.

Pi uses the shared Pi extension, which routes its shell, file, and search tools plus !/!! commands through /exec/ws. Set --sandbox-url http://127.0.0.1:8687 for this backend.

Start

Requirements: an Apple silicon Mac with Apple's container installed and running, and uv. The first start builds the development tools image, which needs host network access; later starts reuse it. --prepare-image builds it and exits.

container system start
uvx external-sandbox-container --preserve-paths \
  --mount-rw project=/absolute/path/to/project \
  --mount-ro reference=/absolute/path/to/reference

uvx downloads and runs the latest release from PyPI. To install the command permanently, use uv tool install external-sandbox-container. From a source checkout, use uv run external-sandbox-container instead.

The server defaults to 127.0.0.1:8687, so it can run alongside the v86 server on port 8686 and the Quicksand server on port 8688. It creates its own container with two CPUs, 512 MiB of memory, and --network none. Stop the server with Ctrl-C to remove that container. Files in writable mounts persist on the host; other container changes are disposable. Host changes to mounted files remain visible.

The mounts appear at /mnt/project and /mnt/reference in Linux. --preserve-paths also makes their original host paths available inside the container, for clients that send absolute paths. The first mount is the default working directory; without mounts, it is /workspace.

Run uvx external-sandbox-container --help for image, resource, and container CLI options. --container-bin selects a particular Apple container executable.

Export setup files

Use --write-setup DIR to copy the bundled setup files into a directory:

uvx external-sandbox-container --write-setup ./sandbox-config

The command creates the directory if needed, writes the files below, and exits without starting a server or building a container image. Apple Container does not need to be running for this step.

File Purpose
Containerfile Image recipe with Python, Bash, Node.js/npm, uv/uvx, Git, curl, ripgrep, jq, and other development tools.
proxy.json Starter policy allowing only GET/HEAD requests to https://example.com; edit it for your required destinations.

Rerunning the command accepts files whose contents are unchanged. It refuses to overwrite edited files, directories in place of files, or symlinks at the destination or output filenames; use a new destination if you have customized the setup. Conflicts are checked before any files are written.

See image details for the exported image recipe and agent setup for connecting coding agents. Claude shell-prefix helpers live in the shared external-sandbox integration; --write-setup exports only the image recipe and proxy policy.

Browser terminal

Open http://127.0.0.1:8687/ to run commands through the existing WebSocket API. Output appears as it arrives. While a command runs, the input box sends lines to its stdin; Send EOF closes stdin and Cancel stops the command. The page also provides command history, a working-directory field, a time limit, and examples for streaming output, interactive input, and HTTPS access.

Each run starts a new shell in the same container. Files persist between runs; use the working-directory field instead of expecting a previous cd to carry over. This uses pipes, not a PTY. For a Python REPL, run python3 -u -i. See terminal controls and behavior.

The HTML, CSS, JavaScript, and frontend tests are a pinned bundle from the independent external-sandbox-ui project. Normal installs include all runtime assets. See shared UI development for the update command, integrity checks, and packaging details.

Try the existing API

curl -sS http://127.0.0.1:8687/health
curl -sS http://127.0.0.1:8687/exec \
  -H 'Content-Type: application/json' \
  --data '{"command":"uname -s; printf hello; printf problem >&2; exit 7"}'

POST /exec returns stdout, stderr, exitCode, signal, timedOut, outputLimitExceeded, and durationMs. A nonzero program exit is a successful HTTP request with a nonzero exitCode. GET /mounts returns mount mappings for the existing client's working-directory translation.

The shared Claude Code integration and Codex setup instructions are maintained in external-sandbox. Use EXTERNAL_SANDBOX_API_URL=http://127.0.0.1:8687 for Claude Code and ws://127.0.0.1:8687/codex for Codex, with the mounted project paths described in agent setup.

See agent setup, protocol and deliberate differences, and a repeatable team demo.

Controlled network access

The container remains offline unless you opt into a host-enforced HTTP(S) proxy. Using the starter policy exported by --write-setup above:

uvx external-sandbox-container --proxy-config ./sandbox-config/proxy.json

This policy permits GET/HEAD requests to https://example.com only. Open http://127.0.0.1:8687/proxy to edit the policy and inspect recent requests. Changes in the UI apply to the running server; save your JSON separately to reuse it after restarting. See proxy setup and security.

Commands receive ordinary proxy environment variables and a public CA certificate. A small guest listener relays traffic over the existing command pipe to the proxy in the host Python process. The container still uses --network none; removing proxy settings cannot enable direct network access.

examples/proxy.json also demonstrates substituting a placeholder with an API key from the host environment. It requires OPENAI_API_KEY on the host before startup. Real keys are not provisioned to the container or displayed by the management UI. An allowed upstream can transform and echo a credential despite literal response redaction; use credential rules only with trusted services and narrow their methods and paths. See proxy scope.

Scope

  • Submitted commands and Codex filesystem operations run inside the container. The host launches the container CLI with argument arrays; it does not evaluate submitted command text in a host shell.
  • The default image runs as UID 0 inside the guest, with all Linux capabilities dropped. The environment's USER=agent label does not change the kernel UID.
  • Mounts deliberately expose selected host directories. Read-write mounts allow immediate host changes; read-only mounts use the runtime's read-only setting. A pre-existing host hardlink in a writable mount remains editable even if another name for the same file is in a read-only mount; avoid that alias if the file must stay unchanged. This backend does not reproduce v86's per-inode hardlink restrictions.
  • Container networking is disabled. Optional HTTP(S) egress travels over the command pipe to the host proxy, which enforces the allow-list and substitutes credentials. Image acquisition occurs on the host.
  • Codex and Claude themselves, model traffic, and host extensions remain on the host. Claude's native Read/Edit tools are not redirected by a shell prefix.
  • Codex is configured with include_local = false. Its local-only !command shortcut must fail. Do not add a local executor to make it work.
  • The execution listener is for trusted local clients. The browser terminal requires a same-origin WebSocket and a per-run token; other execution routes reject browser Origin requests and cross-site Fetch Metadata. The proxy management UI has its own token. Trusted local command-line clients retain their existing API access.

This demonstrates interchangeable execution routes, not a claim that every operation performed by an agent is contained. Isolation and filesystem details differ between Apple's container runtime and the v86 prototype.

The default image adds Node.js 24 LTS/npm, uv/uvx, ripgrep (rg), jq, patch, unzip, curl, Git, procps (ps), and CA certificates to Python and Bash, using this Containerfile. --image selects any other image that provides python3 and bash, such as the smaller python:3.13-slim. See image details.

Test

The proxy baseline passed 220 tests, including real Apple Containers, the unchanged Python client, and Codex CLI 0.154.0. The terminal update passed 250 Python tests and 15 JavaScript tests; the two separately configured Codex tests were not repeated in that run. The expanded tool image subsequently passed 254 Python tests, including Node and uv requests through the managed proxy. See verification for the tested image digests, package checks, and reproducible commands.

uv run pytest -m 'not integration'
node --test tests/test_terminal_js.mjs

Client compatibility checks are optional because the client is maintained separately. Set EXTERNAL_SANDBOX_CLIENT to its absolute path to enable those checks:

EXTERNAL_SANDBOX_CLIENT=/absolute/path/to/external-sandbox/claude-code/external_sandbox_exec.py \
  uv run pytest -q tests/test_legacy_client.py

RUN_APPLE_CONTAINER_TESTS=1 \
EXTERNAL_SANDBOX_CLIENT=/absolute/path/to/external-sandbox/claude-code/external_sandbox_exec.py \
  uv run pytest -q tests/test_real_clients.py

Tests marked integration use the real container runtime or installed agent CLI. See verification instructions. The Codex CLI fixture uses deterministic loopback model responses and an isolated temporary configuration; it does not call a paid model or change user configuration.

The Codex adapter targets the experimental protocol exercised with codex-cli 0.164.0. Other versions require compatibility testing.

Metadata

Release files for external-sandbox-container 0.1.2

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for external-sandbox-container 0.1.2
File Size Uploaded Provenance Actions
external_sandbox_container-0.1.2.tar.gz 219.2 kB With provenance Details for external_sandbox_container-0.1.2.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for external-sandbox-container 0.1.2
File Interpreter ABI Platform Actions
external_sandbox_container-0.1.2-py3-none-any.whl Python 3 none any Details for external_sandbox_container-0.1.2-py3-none-any.whl

Total release size: 297.9 kB

Release files / external_sandbox_container-0.1.2.tar.gz

Download URL external_sandbox_container-0.1.2.tar.gz
Size 219.2 kB
Tags Source
SHA-256 checksum
How to use checksums
a553f30c6f3c3e5707e5f6cd7bddf00e5baa0372872065a070820975a3db2ded
BLAKE2b-256 checksum
How to use checksums
11059d9f440600f5fe1d598a24ceb10db958ae0196cad3da4b4dcd7310981379
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.16

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Nov 6, 2026.

Transparency log

Release files / external_sandbox_container-0.1.2-py3-none-any.whl

Download URL external_sandbox_container-0.1.2-py3-none-any.whl
Size 78.7 kB
Tags Python 3
SHA-256 checksum
How to use checksums
f5a65f564cbddf6dc13db50635cd91d2149d24942eba81ee6ade5485b93d21bb
BLAKE2b-256 checksum
How to use checksums
f861179501b9d57c975df5025ee5af4770146a22dc38cda80b3adb74df6037db
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.16

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Nov 6, 2026.

Transparency log

Security for external-sandbox-container 0.1.2

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

Full provenance

Both files in this release have been uploaded with provenance metadata.

Select from 2 files

Attestation for external_sandbox_container-0.1.2.tar.gz

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Nov 6, 2026.

Transparency log

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Release history Release notifications | RSS feed

This release

0.1.2 This release

2 release files Full provenance

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page