Communication Flow Between the OpenSandbox SDK, Server, and execd Component: A Complete Guide
The SDK communicates with the OpenSandbox server to create sandboxes and discover endpoints, then talks directly to the execd daemon inside the sandbox for file, command, and metrics operations.
The communication flow between the SDK, the OpenSandbox server, and the execd component forms the backbone of the alibaba/OpenSandbox architecture. This article breaks down how the Python SDK orchestrates sandbox lifecycles through the FastAPI server, how the server launches and tracks the execd daemon, and how the SDK establishes direct connections to execd for low-latency I/O operations.
High-Level Architecture Overview
Three primary participants coordinate to provide secure, isolated execution environments:
| Participant | Primary Responsibility | Key API Surface |
|---|---|---|
| SDK (Python/JS) | User-facing client library. Manages sandbox lifecycle and execd I/O. | opensandbox.sandbox.Sandbox → create_sandbox(), get_sandbox_endpoint(), run_command() |
| OpenSandbox Server | FastAPI service orchestrating Docker/Kubernetes containers and endpoint discovery. | server/src/api/lifecycle.py – /sandboxes, /sandboxes/{id}/endpoint/{port}, /sandboxes/{id}/proxy/... |
| execd | Lightweight Go daemon running inside each sandbox. Handles file, command, and metrics requests. | components/execd/pkg/web/router.go – Gin router registering /files, /code, /command, /metrics |
The flow follows this pattern:
SDK → Server (lifecycle) → sandbox container (execd)
↘ Server returns execd endpoint ↘ SDK calls execd API (direct or via Server proxy)
Step-by-Step Communication Sequence
SDK Creates a Sandbox via the Server
The communication flow begins when the SDK requests a new sandbox:
from opensandbox import Sandbox
sandbox = await Sandbox.create(
image="ghcr.io/opensandbox/platform:latest"
)
Under the hood, the SDK sends a POST /v1/sandboxes request to the Server. In server/src/api/lifecycle.py, the create_sandbox implementation invokes the sandbox_service to launch a container (Docker or Kubernetes pod) that runs the execd binary. The Server records metadata (ID, image, state) and returns the sandbox ID to the SDK.
SDK Discovers the execd Endpoint
Before performing I/O, the SDK must resolve the execd network location:
endpoint = await sandbox.get_endpoint(port=8080) # default execd port
The SDK calls GET /v1/sandboxes/{sandbox_id}/endpoints/8080. The Server looks up the sandbox runtime, obtains the internal IP and port where execd listens, and returns an Endpoint model containing {endpoint: "10.0.2.15:8080", headers: {...}}. This logic resides in server/src/api/lifecycle.py within the get_sandbox_endpoint function.
SDK Communicates Directly with execd
Once the endpoint is known, the SDK bypasses the Server for performance-critical operations. All execd-related adapters (FilesystemAdapter, CommandAdapter, HealthAdapter, MetricsAdapter) receive the SandboxEndpoint object and construct URLs using the helper _get_execd_url.
For example, uploading a file:
await sandbox.filesystem.upload_file(
local_path="script.py",
remote_path="/home/user/script.py"
)
The FilesystemAdapter in sdks/sandbox/python/src/opensandbox/sync/adapters/filesystem_adapter.py sends an HTTP POST /files/upload request directly to the execd host. The execd daemon, via its Gin router in components/execd/pkg/web/router.go, dispatches the request to controller.FilesystemController, which performs the file operation inside the sandbox's filesystem.
Similarly, running a command:
result = await sandbox.command.run(
command="python /home/user/script.py",
background=False,
)
This invokes CommandAdapter.run_command, which POSTs to /command on the execd instance, as defined in components/execd/pkg/web/router.go and implemented in the code interpreting controller.
Optional Server Proxy Path
If direct internal IP access is undesirable, the SDK can route traffic through the Server:
proxy_ep = await sandbox.get_endpoint(port=8080, use_server_proxy=True)
When use_server_proxy=True, the Server's get_sandbox_endpoint (lines 12-17 in server/src/api/lifecycle.py) rewrites the endpoint field to a proxy URL like /sandboxes/{id}/proxy/{port}. Subsequent SDK calls use this URL, and the Server's proxy_sandbox_endpoint_request handler (lines 31-73) forwards the request to the real execd host, filtering hop-by-hop headers and streaming the response back.
Lifecycle Changes and Reconnection
When the SDK pauses a sandbox:
await sandbox.pause()
The SDK sends POST /v1/sandboxes/{id}/pause to the Server. The Server pauses the container; execd remains in memory but becomes unreachable.
Upon resuming:
await sandbox.resume()
The SDK calls POST /v1/sandboxes/{id}/resume. The Server restarts the container, re-resolves the execd endpoint, and the SDK re-creates its adapters with the new endpoint (see resume_sandbox in server/src/api/lifecycle.py).
Code Implementation Details
Python SDK Example
The Python SDK abstracts the communication flow through the Sandbox class in sdks/sandbox/python/src/opensandbox/sync/services/sandbox.py:
from opensandbox import Sandbox
async def workflow():
# Lifecycle: Server communication
sandbox = await Sandbox.create(image="python:3.11")
# Endpoint discovery: Server communication
endpoint = await sandbox.get_endpoint(port=8080)
# I/O operations: Direct execd communication
await sandbox.filesystem.write_file("/app/main.py", "print('hello')")
result = await sandbox.command.run("python /app/main.py")
# Cleanup: Server communication
await sandbox.delete()
Server Lifecycle API
The FastAPI server exposes the coordination layer in server/src/api/lifecycle.py. Key functions include:
create_sandbox: Launches containers viasandbox_serviceand injects the execd binary.get_sandbox_endpoint: Resolves the internal IP:port of execd and optionally returns a proxy URL.proxy_sandbox_endpoint_request: Forwards SDK requests to execd when using the server proxy mode.resume_sandbox: Re-resolves execd endpoints after container restart.
execd Router Implementation
The execd daemon uses Gin to route SDK requests to the appropriate controllers. In components/execd/pkg/web/router.go:
func RegisterRoutes(r *gin.Engine, ctrl *controller.Controller) {
// Filesystem operations
r.POST("/files/upload", ctrl.Filesystem.UploadFile)
r.GET("/files/download", ctrl.Filesystem.DownloadFile)
// Command execution
r.POST("/command", ctrl.CodeInterpreting.RunCommand)
// Health and metrics
r.GET("/health", ctrl.Health.Check)
r.GET("/metrics", ctrl.Metrics.GetMetrics)
}
This router handles the direct SDK-to-execd communication that occurs after endpoint discovery.
Key Source Files Reference
Summary
- Two-phase communication: The SDK first communicates with the OpenSandbox server for lifecycle management (create, pause, resume) and endpoint discovery, then communicates directly with the execd daemon for file, command, and metrics operations.
- Endpoint discovery: The server resolves the internal IP and port of the execd container and returns it via
GET /v1/sandboxes/{id}/endpoints/{port}inserver/src/api/lifecycle.py. - Direct vs. proxied: By default, the SDK connects directly to execd for performance. Alternatively, setting
use_server_proxy=Trueroutes traffic through the server'sproxy_sandbox_endpoint_requesthandler. - Lifecycle resilience: When a sandbox resumes after pausing, the server re-resolves the execd endpoint in
resume_sandbox, and the SDK adapters update their connection strings accordingly.
Frequently Asked Questions
Does the SDK always communicate directly with execd?
No. While the default mode uses direct communication for low-latency I/O, the SDK can optionally route all execd traffic through the OpenSandbox server. When calling get_endpoint(port=8080, use_server_proxy=True), the server returns a proxy URL like /sandboxes/{id}/proxy/8080 instead of the direct IP, and the proxy_sandbox_endpoint_request function in server/src/api/lifecycle.py forwards requests to the execd daemon.
What happens to execd when a sandbox is paused?
When the SDK calls pause(), the OpenSandbox server pauses the underlying container (Docker or Kubernetes pod). The execd process remains in memory but becomes unreachable because the container's network stack is frozen. The SDK loses its connection to the execd endpoint. Upon resume(), the server restarts the container, re-resolves the potentially new IP address in resume_sandbox, and returns the updated endpoint to the SDK, which then reinitializes its adapters.
How does the server handle execd endpoint discovery in Kubernetes?
In server/src/services/k8s/kubernetes_service.go, the server creates a pod running the sandbox image with the execd binary injected. When the SDK requests the endpoint via GET /v1/sandboxes/{id}/endpoints/{port}, the server queries the Kubernetes API to obtain the pod's cluster IP or node IP and the mapped container port. It returns this address in the Endpoint model. If use_server_proxy is enabled, the server instead returns a proxy path that routes through the OpenSandbox API.
Can I use the OpenSandbox server as a reverse proxy for all execd traffic?
Yes, but with performance considerations. The server exposes a proxy route at /v1/sandboxes/{id}/proxy/{port} implemented in proxy_sandbox_endpoint_request within server/src/api/lifecycle.py. This handler forwards HTTP requests to the execd daemon, filters hop-by-hop headers, and streams responses back. While this simplifies network security by exposing only the server endpoint, it adds an extra network hop compared to direct SDK-to-execd communication.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →