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.Sandboxcreate_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 via sandbox_service and 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

Component File Role
execd – HTTP router [components/execd/pkg/web/router.go](https://github.com/alibaba/OpenSandbox/blob/main/components/execd/pkg/web/router.go) Registers all execd routes (/files, /code, /command, /metrics).
execd – Controllers [components/execd/pkg/web/controller/filesystem.go](https://github.com/alibaba/OpenSandbox/blob/main/components/execd/pkg/web/controller/filesystem.go) (and code_interpreting.go, command.go, metric.go) Implements the actual sandbox file/command logic.
Server – Lifecycle API [server/src/api/lifecycle.py](https://github.com/alibaba/OpenSandbox/blob/main/server/src/api/lifecycle.py) Handles sandbox CRUD, pause/resume, endpoint discovery, and proxying.
Server – Sandbox Service [server/src/services/k8s/kubernetes_service.go](https://github.com/alibaba/OpenSandbox/blob/main/server/src/services/k8s/kubernetes_service.go) (Docker equivalent in docker.py) Launches the sandbox container and injects the execd binary.
Python SDK – Sandbox Service [sdks/sandbox/python/src/opensandbox/sync/services/sandbox.py](https://github.com/alibaba/OpenSandbox/blob/main/sdks/sandbox/python/src/opensandbox/sync/services/sandbox.py) Provides create(), get_endpoint(), and high-level sandbox object.
Python SDK – Filesystem Adapter [sdks/sandbox/python/src/opensandbox/sync/adapters/filesystem_adapter.py](https://github.com/alibaba/OpenSandbox/blob/main/sdks/sandbox/python/src/opensandbox/sync/adapters/filesystem_adapter.py) Builds execd URLs and calls /files endpoints.
Python SDK – Command Adapter [sdks/sandbox/python/src/opensandbox/sync/adapters/command_adapter.py](https://github.com/alibaba/OpenSandbox/blob/main/sdks/sandbox/python/src/opensandbox/sync/adapters/command_adapter.py) Builds execd URLs and calls /command endpoints.
OpenAPI spec for execd [specs/execd-api.yaml](https://github.com/alibaba/OpenSandbox/blob/main/specs/execd-api.yaml) Contract that both execd and SDK adapters follow.

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} in server/src/api/lifecycle.py.
  • Direct vs. proxied: By default, the SDK connects directly to execd for performance. Alternatively, setting use_server_proxy=True routes traffic through the server's proxy_sandbox_endpoint_request handler.
  • 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:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →