Agent Sandbox
Envd Sandbox
This example demonstrates running envd — E2B’s in-sandbox daemon — as the container entrypoint inside an agent-sandbox. envd exposes an E2B-compatible REST and gRPC API on port 49983, providing filesystem operations, process execution, environment management, and metrics.
Overview
envd is the data-plane daemon that runs inside every E2B sandbox. It provides:
- Filesystem API — upload, download, list, stat, watch files
- Process API — start, connect, stream I/O (with PTY support)
- REST endpoints —
/health,/metrics,/init,/envs,/freeze,/unfreeze - Port forwarding — auto-discovers and forwards localhost ports
This example builds envd from the upstream e2b-dev/infra source and runs it in a standard Linux container with the --isnotfc flag (skipping Firecracker MMDS polling). No KVM or kata-deploy is required.
The kvcache-ai/AgentENV project uses envd in a similar way, packaging it into an ext4 tools drive attached to Firecracker microVMs for their AI agent RL training platform.
Architecture
Client SDK (Python / Go / TS / curl)
│
│ HTTP / gRPC (port 49983)
│ ─── kubectl port-forward ───┐
▼ │
┌─────────────────────────────────────┐
│ envd Pod (standard Linux container)│
│ │
│ REST API: │
│ GET /health │
│ GET /metrics │
│ POST /init │
│ GET /envs │
│ GET /files (download) │
│ POST /files (upload) │
│ │
│ gRPC (ConnectRPC): │
│ filesystem.{Stat,ListDir,...} │
│ process.{Start,Connect,...} │
│ │
│ Port Scanner + Forwarder │
└─────────────────────────────────────┘
▲
│
agent-sandbox controller
Prerequisites
- Kubernetes cluster with agent-sandbox controller installed (quickstart)
kubectlconfigured to access the cluster- Docker (or other OCI builder) to build the envd image
Step 1 — Build and push the envd image
cd examples/envd-sandbox
# Build (default uses a pinned envd commit; override with --build-arg ENVD_VERSION=<ref>)
export IMAGE=<your-registry>/envd-sandbox:latest
docker build -t ${IMAGE} .
# Push (for Kind, use: kind load docker-image ${IMAGE})
docker push ${IMAGE}
Step 2 — Create the Sandbox
envsubst < sandbox-envd.yaml | kubectl apply -f -
kubectl get sandbox envd-example
Step 3 — Verify the pod is running
kubectl get pod -l sandbox=envd
kubectl logs -l sandbox=envd
# Should show envd startup banner and "listening on :49983"
Step 4 — Run the verification scripts
First, set up port-forwarding:
POD=$(kubectl get pod -l sandbox=envd -o jsonpath='{.items[0].metadata.name}')
kubectl port-forward pod/$POD 49983:49983 &
PF_PID=$!
trap 'kill $PF_PID 2>/dev/null' EXIT
export SANDBOX_BASE_URL=http://127.0.0.1:49983
# Wait for readiness
for i in $(seq 1 30); do
curl -sf ${SANDBOX_BASE_URL}/health >/dev/null 2>&1 && break
sleep 0.2
done
Then run any of the four client scripts:
Python
pip install -r requirements.txt
python test_client.py
Shell (curl + jq)
chmod +x test_client.sh
./test_client.sh
Go
go run test_client.go
TypeScript
npx tsx test_client.ts
All four scripts test the same operations:
- health —
GET /health→ 204 - init —
POST /init→ 204 (initializes sandbox withdefaultUser: userfor subprocess execution) - files — upload + download round-trip via
POST/GET /files - metrics —
GET /metrics→ JSON with system stats (ts,cpu_count,mem_total, etc.)
Security Considerations
WARNING: envd in
--isnotfcmode runs without authentication. Do NOT expose port 49983 to a public network.
Security model (following e2b-dev design):
- envd runs as root: Required for PTY allocation, process management, and cgroup operations.
- User code runs as non-root: The
/initrequest setsdefaultUser: "user"(uid 1000), so all user-spawned processes execute as an unprivileged user. This limits blast radius if user code is malicious.
The included sandbox-envd.yaml applies a default-deny ingress NetworkPolicy that restricts access to port 49983 to pods labeled access: envd-client. This prevents unauthorized workloads in the cluster from reaching the envd API.
Production hardening checklist
- NetworkPolicy: The default manifest includes a deny-all ingress policy. Adjust the
podSelectorto match your cluster’s access control model (e.g., allow only the sandbox-router pod). - Pin envd version: The Dockerfile pins
ENVD_VERSIONto a specific upstream commit. To update, override at build time:docker build --build-arg ENVD_VERSION=<commit-or-tag> -t ${IMAGE} . - Token authentication: To enable authenticated access, send an initial
POST /initrequest with anaccessTokenfield to bootstrap the daemon’s token. Subsequent requests must include theX-Access-Tokenheader. Do not setE2B_ACCESS_TOKENas an environment variable — the token is configured via the/initbootstrap flow. - Non-root subprocesses: The Dockerfile creates a
user(uid 1000) and the test clients setdefaultUser: "user"in/init. All user code runs as this unprivileged user by default. - Ephemeral storage: envd writes to the container’s rootfs; pod restart wipes all state.
Troubleshooting
| Symptom | Cause | Fix |
|---|---|---|
Pod stuck in CrashLoopBackOff |
envd cannot reach MMDS (missing --isnotfc) |
Verify the Dockerfile CMD includes --isnotfc |
failed to create cgroup in logs |
cgroup v2 not available in container | Ensure --no-cgroups flag is set in CMD |
connection refused on port 49983 |
envd not yet ready | Wait for readiness probe; check kubectl logs |
| File upload returns 500 | Path resolution issue | File paths resolve relative to /home/user; use relative paths or absolute paths under /home/user/ |
| Port-forward drops | Pod restarted | Re-run kubectl port-forward |
Cleanup
kubectl delete -f <(envsubst < sandbox-envd.yaml)
# Or individually:
# kubectl delete sandbox envd-example
# kubectl delete networkpolicy envd-deny-ingress
Related
- envd source — upstream E2B daemon
- kvcache-ai/AgentENV — envd in Firecracker microVMs
- E2B docs — E2B sandbox platform documentation
- firecracker-sandbox — VM-isolated sandbox with a similar API contract