ez-devbox is a small CLI for running coding agents in disposable E2B sandboxes without rebuilding the same shell glue every time.
The closest alternative is usually a homegrown setup: create an E2B sandbox, clone the repo, copy auth files, run setup commands, start tmux, SSH in, launch OpenCode/Codex/Claude Code, remember the sandbox ID, and reattach later. This tool packages that workflow into repeatable commands and config.
- A workflow layer on top of E2B sandboxes.
- A way to launch and reconnect to OpenCode, Codex, Claude Code, or a shell in the same sandbox.
- A config-driven bootstrapper for cloning repos, setting branches, installing dependencies, and starting in the right working directory.
- A controlled way to pass selected env vars and sync local tool auth/config into the sandbox.
- Optional tunnel setup for reaching local MCP servers, Docker containers, or other services from the sandbox.
Use ez-devbox if your current workflow looks like git worktree + tmux + SSH + custom E2B scripts + copied config files, and you want that to be less manual.
It handles the repetitive parts:
- create or connect to an E2B sandbox
- clone/bootstrap one or more repos
- launch the selected agent mode
- keep SSH sessions persistent with
tmuxwhere needed - save last-run state so
resumecan reattach - sync selected OpenCode, Codex, Claude Code, and GitHub CLI auth/config during
create - optionally expose local services to the sandbox through managed tunnels
git worktree+tmux+ SSH: flexible and simple, but you write the lifecycle glue yourself.ez-devboxkeeps the same terminal-first feel while adding sandbox creation, config sync, bootstrap, and resume state.- Raw E2B SDK/CLI scripts: good if you want total control.
ez-devboxis for the repeated agent workflow around E2B, not for replacing E2B itself. - Daytona, Coder, Codespaces, DevPod: infrastructure or dev-environment platforms. They can be useful underneath or alongside this kind of workflow, but
ez-devboxis focused on launching and reattaching coding-agent sessions with your local config and auth expectations. - Full agent platforms: better if you want task queues, PR automation, dashboards, or autonomous background work.
ez-devboxis deliberately closer to "give me a clean remote box and attach my agent shell."
ssh-opencode: SSH into the sandbox and attach the OpenCode TUI to a persistent in-sandboxopencode servebackend.ssh-codex: SSH into the sandbox and attach Codex inside a persistenttmuxsession.ssh-claude: SSH into the sandbox and attach Claude Code inside a persistenttmuxsession.web: startopencode serveand print the URL.ssh-shell: SSH into an interactive shell inside a persistenttmuxsession.
Prereqs: Node.js 20+, E2B_API_KEY, and a ez-devbox.config.toml (local or global). Docker/cloudflared only if you use tunnel features.
Choose one:
npm install --save-dev ez-devbox
npx ez-devbox --helpor one-off run without install:
npx ez-devbox --helpor global install:
npm install -g ez-devbox
ez-devbox --help
# Short alias after global install:
ezdb --helpYou can set variables in your shell or put them in a local .env file.
Quick start:
cp .env.example .envMinimum required:
E2B_API_KEY: required for any real sandbox operation (create,connect,list,wipe, live e2e).
Common optional vars:
FIRECRAWL_API_URL: used by your own tooling/workloads inside the sandbox (for example tunneled MCP/API endpoints).FIRECRAWL_API_KEY: forwarded only if configured throughenv.pass_through.GITHUB_TOKEN/GH_TOKEN: used for GitHub auth flows (especially when[gh].enabled = true).OPENCODE_SERVER_PASSWORD: used forwebmode auth.
Template file:
.env.exampleincludes the expected keys.
- Create
.envand set at least:
cp .env.example .envE2B_API_KEY=your_key_here- Create/edit
ez-devbox.config.toml.
Config lookup order:
- Local:
./ez-devbox.config.toml(from the directory where you runez-devbox) - Global: user config file
- macOS/Linux:
~/.config/ez-devbox/ez-devbox.config.toml - Windows:
%APPDATA%\\ez-devbox\\ez-devbox.config.toml
- macOS/Linux:
If neither file exists and you're in an interactive terminal, ez-devbox prompts you to create a starter config locally or globally, then continues with it. In non-interactive environments, it exits with an error listing both expected paths.
If you do not already have one, create a starter config:
cat > ez-devbox.config.toml <<'EOF'
[sandbox]
template = "opencode"
name = "ez-devbox"
[project]
mode = "single"
active = "prompt"
[[project.repos]]
name = "your-repo"
url = "https://github.com/your-org/your-repo.git"
setup_command = "npm install"
EOFThen set each repo's setup_command as needed. For the full field reference, see docs/launcher-config-reference.md.
- Run commands (
npxif not globally installed):
npx ez-devbox create
npx ez-devbox connectUse npx ez-devbox ... if the CLI is not globally installed. After global install, ezdb is also available as a short alias for ez-devbox.
| Goal | Command |
|---|---|
| Help | ez-devbox --help |
| Create sandbox + launch mode | ez-devbox create --mode web |
| List sandboxes | ez-devbox list |
| Connect to existing sandbox | ez-devbox connect --sandbox-id <sandbox-id> |
| Resume last sandbox/mode | ez-devbox resume |
| Run command in sandbox | ez-devbox command --sandbox-id <sandbox-id> -- pwd |
| JSON output for automation | ez-devbox list --json |
| Wipe one sandbox | ez-devbox wipe |
| Wipe all sandboxes | ez-devbox wipe-all --yes |
Use --json on automation-facing commands for stable machine-readable output:
list:{ "sandboxes": [...] }command: command result envelope (sandboxId,command,cwd,stdout,stderr,exitCode)create/connect: launch result envelope (mode, command/url when present, workingDirectory, setup summary)
Tip: optional fields are omitted when undefined (for example url is absent for SSH modes).
- Use
--verboseto show detailed operational logs duringcreate/connect(startup mode resolution, sandbox lifecycle steps, create-time tooling sync progress, bootstrap progress, SSH/tunnel setup details). - Interactive pickers/prompts still show as normal.
- Without
--verbose, ez-devbox keeps output focused on prompts and final command results.
ez-devbox.config.toml: ez-devbox behavior (sandbox, startup, project, env pass-through, tooling auth sync, tunnel). Resolved from local-first then global fallback..env: secrets and local env values- last-run state: by default stored at
${TMPDIR}/ez-devbox/last-run/cwd-state/<sha1(cwd)>/.ez-devbox-last-run.json(legacy.agent-box-last-run.jsonin the current directory is still read only for persisted-data compatibility) docs/launcher-config-reference.md: fullez-devbox.config.tomlfield reference
For non-local upstream services, define explicit tunnel targets (port -> upstream URL):
[tunnel]
[tunnel.targets]
"3002" = "http://10.0.0.20:3002"This keeps the same EZ_DEVBOX_TUNNEL_* env output while pointing cloudflared at a remote host/service.
When tunnel.targets is present, its keys are the authoritative tunneled ports (you do not need tunnel.ports).
Target URLs cannot include credentials, path, query, or fragment.
On create, ez-devbox prints a warning that tunnel URLs are effectively bearer links: anyone with the URL can reach the forwarded service.
authorization header is missing/ 401 errors:- make sure
.envexists and containsE2B_API_KEY.
- make sure
wipe-all requires --yes in non-interactive terminals:- add
--yesin CI/scripts.
- add
- Multiple sandboxes in non-interactive runs:
- pass
--sandbox-id <id>explicitly.
- pass
- Tunnel command issues:
- ensure
cloudflaredis installed, or Docker is available for fallback.
- ensure
See docs/launcher-config-reference.md.