cd /news/ai-infrastructure/show-hn-sandrpod-run-the-unmodified-… · home topics ai-infrastructure article
[ARTICLE · art-118886] src=github.com ↗ pub= topic=ai-infrastructure verified=true sentiment=· neutral

Show HN: SandrPod – run the unmodified E2B SDK against your own infrastructure

SandrPod, an open-source, self-hosted control plane for AI agent code execution, launched v0.5.10, enabling developers to run unmodified E2B SDK code on their own infrastructure across 8 clouds including Aliyun and Tencent, Docker, or bare machines. The project provides a one-command Docker setup, a CLI, and native REST/Python/TS APIs, with reverse-tunnel workers requiring no inbound ports.

read10 min views1 publishedSep 2, 2026
Show HN: SandrPod – run the unmodified E2B SDK against your own infrastructure
Image: Michielbdejong (auto-discovered)

Self-hosted execution infrastructure for AI agents.

Run agent code on any cloud, any machine — or none at all. Speak any SDK. Keep full control.

Your clouds. Your machines. Your rules.

One command brings up the control plane and a Docker worker from the published images — no Go toolchain, no build, no cloning the repo.

curl -O https://raw.githubusercontent.com/sandrpod/sandrpod/main/docker/docker-compose.yml
docker compose up -d

That pulls ghcr.io/sandrpod/{server,poder,toolbox}

and starts: the control plane on localhost:8080

and one Docker worker (Poder) that dials back over a reverse tunnel — no inbound ports on the worker.

First run downloads ~170 MB here (server + worker). The sandbox runtime (

toolbox

, ~530 MB) is pulled by the worker the first time you create a sandbox, so step 2 below is the slow one. After that, both steps take seconds.

Check it:

curl localhost:8080/health          # {"status":"ok",...}
curl localhost:8080/api/v1/poders   # wait for one worker to show "state":"ONLINE"

/health

answers as soon as the control plane binds, which is before the worker has finished registering. The second command is the one that tells you the stack is actually ready.

⚠️ This dev stack runs withauthentication disabled(anonymous admin) — fine on localhost. Before exposing it, setSANDRPOD_TOKEN

(see[docs/AUTH_AND_KEYS.md]).

pipx install sandrpod-cli              # recommended — isolated, nothing to activate

sandrpod-cli --api-url http://localhost:8080 create demo --provider local
sandrpod-cli --api-url http://localhost:8080 execute demo "echo hello from SandrPod; python3 -c 'print(6*7)'"

Real output from a cold run (no cached images) against v0.5.10:

Sandbox:  demo
Job ID:   job-1788150453342465216-7j5di2LP
Status:   provisioning
State:    PENDING
State:    RUNNING
Sandbox 'demo' is ready
hello from SandrPod
42

SandrPod is the control plane for AI agent code execution — open source and self-hosted. It turns your own infrastructure into a fleet of on-demand sandboxes that agents create, run code in, and tear down, while you keep ownership of where that code runs, what it can touch, and where the data lives.

Hosted sandbox services make you rent their runtime in their region. SandrPod inverts that: you bring the substrate — any cloud, plain Docker, or a bare machine — and SandrPod is the thin, portable layer that schedules, tunnels, and governs execution across it. It rests on three pillars:

Run anywhere you own— 8 clouds (incl. Aliyun & Tencent), Docker, or a machine with no Docker at all.** Speak any SDK**— a native REST/Python/TS API, LangChain/deepagents, and the** unmodified E2B SDKas a drop-in. Stay in control**— reverse-tunnel workers with zero inbound ports, an opt-in permission gate + decision audit, and self-hosted data that never leaves your infra.

One binary schedules sandboxes across whatever infrastructure you have:

AWS · GCP · Azure · Aliyun · Tencent · DigitalOcean · Hetzner · Oracle — plus plain Docker, or a bare machine with no Docker via sandrpod-agent

.

Aliyun and Tencent make China-region and data-residency deployments first-class — something hosted services don't offer. Each provider has a guide under docs/ (

AWS,

GCP,

Aliyun,

Tencent, …). Remote exec uses each cloud's managed run-command API where it exists (AWS SSM, Aliyun CloudAssist, Azure Run Command, Tencent TAT, Oracle Instance Agent) and an ephemeral-key SSH path elsewhere (GCP, DigitalOcean, Hetzner).

SandrPod isn't tied to one client. It exposes a native REST API and Python/TS SDKs, a first-class LangChain/deepagents backend, and the full E2B wire protocol — so the unmodified e2b

/ e2b-code-interpreter

SDKs work against it with nothing but two env vars. Bring the ecosystem you already use; migrate nothing.

Zero inbound ports. Workers dialoutto the control plane over a WebSocket reverse tunnel — run them behind NAT, in a private subnet, or on a laptop.Governance, not just isolation. Opt-in employee-PC mode adds a per-machine permission gate (path consent, command denylist, PTY consent) and a decision audit pipeline (NDJSON + central HTTP upload) — turning "run agent code" into "governwhat agents may touch on real machines."Your data stays yours. Self-hosted, Apache 2.0, no phone-home.

| Hosted (E2B, Modal, …) | SandrPod | | |---|---|---| License | Closed | Apache 2.0, open source | Where it runs | Their infra / region | Your cloud, Docker, or bare metal | Clouds | Vendor-managed | AWS · GCP · Azure · Aliyun · Tencent · DO · Hetzner · Oracle | China regions | ✗ | ✓ Aliyun + Tencent | No-Docker mode | — | sandrpod-agent : any machine becomes a sandbox | SDKs | Their SDK | Native + LangChain + drop-in E2B | Inbound ports on workers | n/a | None (reverse tunnel) | Governance / audit | — | Opt-in permission gate + decision audit | Data residency | Their region | Your account, your region |

Recorded live against a SandrPod deployment: the package is the one from PyPI, the only change is which host it points at. Source: assets/e2b-demo.py.

One example of "speak any SDK": already have code on the E2B SDK? Point it at your SandrPod and it just works — Sandbox.create

, files.*

, commands.*

(foreground/background/PTY), run_code

, watch_dir

, get_metrics

, ``

/resume

:

import os
os.environ["E2B_API_KEY"]     = "e2b_your_key"          # issued by your SandrPod
os.environ["E2B_API_URL"]     = "https://sandbox.you.com"   # control plane
os.environ["E2B_SANDBOX_URL"] = "https://sandbox.you.com"   # per-sandbox envd

from e2b import Sandbox                # the real, unmodified e2b SDK
sbx = Sandbox.create()
sbx.files.write("/tmp/hi.txt", "hello from my own cloud")
print(sbx.commands.run("cat /tmp/hi.txt").stdout)   # → hello from my own cloud

from e2b_code_interpreter import Sandbox as CI
ci = CI.create()
print(ci.run_code("import numpy as np; np.arange(6).sum()").text)   # → 15

For a zero-config drop-in (no env vars, just a domain), run the gateway behind a wildcard domain — SANDRPOD_E2B_DOMAIN=sandbox.you.com

  • *.sandbox.you.com

DNS

  • TLS. Full surface, wire-protocol details, and the coverage matrix (verified against the real, unmodified E2B SDK over a real container) are in.docs/E2B_COMPAT.md
E2B SDK ──┐
Native SDK ├─→ API Server (Control Plane, :8080)
LangChain ─┤         ↕ WebSocket + yamux reverse tunnel
CLI ───────┘    Poder (Worker) ──→ Toolbox (Sandbox container)

                sandrpod-agent  ──→ (direct mode, any machine as a sandbox)
Component Description
API Server
The control plane: native REST + E2B-compatible gateway, sandbox CRUD, scheduling, tunnel proxying
Poder
Worker node. Persistent WebSocket tunnel to the control plane; manages Docker container lifecycle
sandrpod-agent
Registers the local machine directly as a sandbox with an embedded Toolbox — no Docker required
sandrpod-tray
Optional user-session GUI for employee-PC mode: tray icon + consent prompts + local settings page
Toolbox
Execution service inside each sandbox. PTY, file ops, background processes, sessions

Employee-PC mode (opt-in): whensandrpod-agent

runs on a real employee laptop rather than a server, enable a per-PC permission gate (path consent + command denylist + PTY consent) and a decision-audit pipeline that ships every allow/deny/warn event to a central HTTP endpoint. Both are off by default (--permission-mode=off

) — see.[docs/PERMISSION_AND_AUDIT.md]

…or with plain curl #

(no install)

curl -X POST localhost:8080/api/v1/sandboxes \
  -d '{"name":"demo","provider_type":"local"}'
curl -X POST "localhost:8080/api/v1/sandboxes/execute?sandbox=demo" \
  -d '{"code":"print(6*7)","language":"python"}'
python
from langchain_sandrpod import SandrPodClient
sb = SandrPodClient(api_url="http://localhost:8080").get_sandbox("demo")
print(sb.execute("echo hello from SandrPod").output)

from e2b import Sandbox
print(Sandbox.create().commands.run("echo hello from SandrPod").stdout)

Other ways to run it #

Production, with TLS and a real domain— the reference deployment: PostgreSQL, a wildcard certificate, and the E2B surface on.docker compose -f docker/docker-compose.prod.yml up -d --wait

, walked through end to end (DNS, certificate, renewal, acceptance sweep) in— or as a narrative, with the two failures it took to get there, indocs/PRODUCTION_DEPLOYMENT.mdthis writeup.PostgreSQL only(no TLS termination):docker compose -f docker/docker-compose.pg.yml up -d

— seedocs/MULTI_INSTANCE_DEPLOYMENT.mdto scale out.Build from source(contributors):docker compose -f docker/docker-compose.local.yml up -d --build

From Go directly:go run ./cmd/server -port 8080 -db sqlite:./data/sandrpod.db

, then add a worker with thedocker run …/poder

one-liner orgo run ./cmd/poder -api-url=http://localhost:8080

.No Docker at all— turn any machine into a sandbox:go run ./cmd/agent -api-url=http://localhost:8080 -name=my-machine

The default docker-compose.yml

persists to SQLite (a sandrpod-data

volume), so sandboxes and tokens survive a restart.

sandrpod-tray serve                       # user-session tray + consent dialogs (🛡)
go run ./cmd/agent -api-url=http://localhost:8080 -name=my-laptop \
  -permission-mode=prompt \
  -audit-upload-url=https://your-platform/api/audit/decisions/batch

Permission modes: off

(default) | prompt

(consent dialog outside work_dir

) | strict

(silent deny outside work_dir

). Full architecture, permissions.json

schema, tray CLI, and audit protocol: ** docs/PERMISSION_AND_AUDIT.md**.

pip install langchain-sandrpod
python
from langchain_sandrpod import SandrPodClient
from deepagents import create_deep_agent
from langchain_openai import ChatOpenAI

model = ChatOpenAI(model="gpt-4o", temperature=0)
client = SandrPodClient(api_url="http://localhost:8080")

sb = client.get_sandbox("my-sandbox")
agent = create_deep_agent(model=model, backend=sb)
result = agent.invoke({"messages": [{"role": "user", "content": "Write a quicksort and run it"}]})

with client.sandbox("temp-sb") as sb:
    agent = create_deep_agent(model=model, backend=sb)
    result = agent.invoke({"messages": [...]})

The backend also exposes richer per-sandbox capabilities directly:

sb.run_code("x = 40", context="ctx1")          # stateful Jupyter-style kernel
sb.run_code("x + 2", context="ctx1")["text"]   # → "42" (x persisted)
sb.metrics()                                    # {cpu_count, cpu_used_pct, mem_*, disk_*}
with sb.watch_dir("/workspace") as w:           # filesystem watch
    events = w.get_new_events()

See pkg/sdk/python/langchain_sandrpod/examples/ for full examples.

pipx install sandrpod-cli    # or: uv tool install sandrpod-cli
sandrpod-cli config set-url http://localhost:8080

sandrpod-cli list
sandrpod-cli create my-sandbox --provider local --image ghcr.io/sandrpod/toolbox:latest
sandrpod-cli create gpu-box --provider gcp --region asia-east1-a --instance-type e2-medium
sandrpod-cli execute my-sandbox "ls /workspace"     # one-shot (stateless)
sandrpod-cli stream my-sandbox "make build"         # real-time streamed output
sandrpod-cli run my-sandbox "z = 10" --context c1   # stateful kernel — z persists in context c1
sandrpod-cli stats my-sandbox                       # live CPU / memory / disk
sandrpod-cli fs watch my-sandbox /workspace         # print filesystem events
sandrpod-cli shell my-sandbox                       # interactive PTY
sandrpod-cli delete my-sandbox

sandrpod-cli poder list
sandrpod-cli poder delete <poder-id>

SandrPod speaks two HTTP surfaces: its own native REST API, and — when the E2B gateway is enabled — the full E2B control-plane + envd

protocol.

Native API

Method Path Description
GET /api/v1/sandboxes
List sandboxes
POST /api/v1/sandboxes
Create sandbox
DELETE /api/v1/sandboxes/{name}
Delete sandbox
POST /api/v1/sandboxes/execute
Execute code
GET /api/v1/sandboxes/{name}/toolbox/*
Proxy to Toolbox (file upload/download, etc.)
GET /api/v1/poders
List Poder nodes
DELETE /api/v1/poders/{id}
Delete a Poder record

E2B-compatible APIPOST /sandboxes

, GET /sandboxes/{id}

, /sandboxes/{id}/{,resume,metrics,connect}

, and the envd

Filesystem/Process connect-RPC services. See docs/E2B_COMPAT.md.

make build-all

go build -o server        ./cmd/server
go build -o poder         ./cmd/poder
go build -o agent         ./cmd/agent
go build -o sandrpod-tray ./cmd/sandrpod-tray   # CGO required

CGO_ENABLED=0 GOOS=linux   GOARCH=amd64 go build -ldflags="-s -w" -o dist/server-linux-amd64 ./cmd/server
CGO_ENABLED=0 GOOS=linux   GOARCH=amd64 go build -ldflags="-s -w" -o dist/sandrpod-agent-linux-amd64 ./cmd/agent
CGO_ENABLED=0 GOOS=darwin  GOARCH=arm64 go build -ldflags="-s -w" -o dist/sandrpod-agent-darwin-arm64 ./cmd/agent
CGO_ENABLED=0 GOOS=windows GOARCH=amd64 go build -ldflags="-s -w" -o dist/sandrpod-agent-windows-amd64.exe ./cmd/agent

docker buildx build --platform linux/amd64 -f docker/Dockerfile.poder   -t ghcr.io/sandrpod/poder:latest   --load .
docker buildx build --platform linux/amd64 -f docker/Dockerfile.toolbox -t ghcr.io/sandrpod/toolbox:latest --load .

Longer pieces, with the commands and the failures they were measured from:

Self-hosting an E2B-compatible sandbox stack, from an empty server— one VM, one domain, four containers, and the unmodified E2B SDK checked function by function. 48 of 50 calls pass; the two that do not are named.Two ways to give a deepagents agent a sandbox you ownlangchain-e2b

andlangchain-sandrpod

down the same twelve assertions. Both pass. Testing both surfaced two real defects — both of them mine to fix — and a third finding that turned out to be a deliberate contract I had misread as a bug.

More at blog.sandrpod.com.

Deploying this inside a company, or hitting something the docs don't cover? Open an issue, email me at zhaochj@126.com, or find me on X as @itscjzhao.

Apache 2.0

── more in #ai-infrastructure 4 stories · sorted by recency
── more on @sandrpod 3 stories trending now
sponsored brought to you by zahid.host 4,200+ EU-deployed projects
reading about agents? ship yours in a single git push.

Run your AI side-project on zahid.host

EU-based hosting, git-push deploys, automatic HTTPS, no cold starts. Free tier with a custom domain — perfect for shipping the agent you just read about.

$git push zahid main
Live at https://your-agent.zahid.host
Get free account → Pricing
from €0/mo · no card required
LIVE [news/show-hn-sandrpod-run…] indexed:0 read:10min 2026-09-02 ·