feat: add E2B cloud sandbox environment#792
feat: add E2B cloud sandbox environment#792JunYeopLee wants to merge 6 commits intoSWE-agent:mainfrom
Conversation
Add `E2BEnvironment`, a new environment backend that runs commands inside [E2B](https://e2b.dev) cloud sandboxes. Unlike the Docker and Modal backends, it requires no local Docker daemon — the sandbox runs entirely in the cloud. Key design decisions: - **Automatic template management**: The first time a Docker image is used, `E2BTemplateManager` converts it into a persistent E2B template via `Template.build()`. Subsequent runs reuse the cached template, so the build cost is paid only once per unique image. - **Deterministic template naming**: `_image_to_template_name()` produces a stable, collision-resistant name (sha256 8-char suffix) that stays within E2B's 63-character, alphanumeric-plus-hyphen limit. - **Thread-safe build timeout**: Template builds run in a `ThreadPoolExecutor` (not `signal.alarm`) so that the timeout works correctly when called from worker threads (e.g., parallel SWE-bench runs). - **SWE-bench integration**: `get_sb_environment()` in `swebench.py` now injects the instance image for `e2b` the same way it does for `docker` and `swerex_modal`. Changes: - `src/minisweagent/environments/extra/e2b.py` — new environment class - `src/minisweagent/environments/__init__.py` — register `"e2b"` key - `src/minisweagent/run/benchmarks/swebench.py` — inject image for e2b - `pyproject.toml` — add `e2b` optional dependency (`e2b>=1.0.0`) - `tests/environments/extra/test_e2b.py` — 18 unit tests (all passing) - `docs/` — update environments reference and README
for more information, see https://pre-commit.ci
Add a module-level _active_sandboxes set and an atexit handler (_cleanup_all_sandboxes) that kills all live sandboxes when the interpreter exits. This ensures sandboxes are cleaned up on Ctrl+C or unhandled exceptions where __del__ may not be reliably called. - __init__ adds self to _active_sandboxes after sandbox creation - stop() removes self from _active_sandboxes before calling sandbox.kill() - atexit handler iterates over a snapshot of the set to avoid mutation issues Two additional tests cover the registry and cleanup behaviour.
E2B_ACCESS_TOKEN / access_token is not recognised by the E2B SDK. Remove the config field, all call-site usages (Template.build, Sandbox.create), the serialize exclusion, and the corresponding tests. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
get_or_build() was short-circuiting to the else branch without consulting skip_cache, making force-rebuild impossible despite the field documenting "force-rebuild even if it already exists". Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
Great! Happy to include that. I'm gonna look through things in detail soon. |
|
Hello @klieret, nice to meet you. I’ve run some test executions using the setup below: source .env
# OPENAI_API_KEY=
# E2B_API_KEY=uv run mini-extra swebench \
--model openai/gpt-5-nano \
--split test \
--workers 4 --environment-class e2b --output ./results
As shown in the screenshot, the execution is working as expected. I’ve also attached the result file for reference. Please let me know if there are any additional checks or scenarios you’d like me to validate. |
SWE-bench Docker images have /testbed owned by root, but E2B sandboxes run commands as user (UID 1000) by default, causing permission denied. Add user="root" to commands.run() to match Docker behavior. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
9159fb4 to
32d1f91
Compare
|
Awesome, let me review in detail today! |
|
(Also I sometimes announce new features/tag new contributors on twitter/linkedin, do you have an account that I should mention?) |
|
@klieret Sounds great! Here are my linkedin/X profile. https://www.linkedin.com/in/leejunyeop/ Thanks :) |

Summary
This PR adds
E2BEnvironment, a new environment backend that executes commands inside E2B cloud sandboxes.Key design decisions
Automatic template management
The first time a Docker image is used,
E2BTemplateManagerconverts it into a persistent E2B template viaTemplate.build(). Subsequent runs reuse the cached template, so the one-time build cost is paid only once per unique image.Deterministic template naming
_image_to_template_name()maps Docker image names to stable, collision-resistant E2B template names using a sha256 8-character suffix. The result always stays within E2B's 63-character, alphanumeric-plus-hyphen limit.Thread-safe build timeout
Template builds are wrapped in a
ThreadPoolExecutor(rather thansignal.alarm) so that the timeout works correctly when invoked from worker threads — e.g., during parallel SWE-bench evaluation runs.SWE-bench integration
get_sb_environment()inswebench.pynow injects the per-instance image fore2bthe same way it already does fordockerandswerex_modal.Changes
src/minisweagent/environments/extra/e2b.pyE2BEnvironmentConfig,E2BTemplateManager,E2BEnvironment)src/minisweagent/environments/__init__.py"e2b"key in the environment mappingsrc/minisweagent/run/benchmarks/swebench.pye2benvironment classpyproject.tomle2boptional dependency (e2b>=1.0.0)tests/environments/extra/test_e2b.pydocs/advanced/environments.mde2bentry to the environment listdocs/reference/environments/e2b.mdE2BEnvironmentREADME.mdUsage
Install the extra and set the API key:
Run SWE-bench evaluation via E2B:
mini-extra swebench \ --subset verified \ --split test \ --workers 50 \ --environment-class e2bOr in a YAML config:
Test plan
E2BEnvironmentConfig,_image_to_template_name,execute()(dict/string action, non-zero exit, exception,Submitteddetection),serialize()(structure, credential exclusion),stop()(normal, missing sandbox, exception-tolerant)