This Python client provides a simple, high-level interface for creating and interacting with sandboxes managed by the Agent Sandbox controller. It's designed to be used as a context manager, ensuring that sandbox resources are properly created and cleaned up.
It supports a scalable, cloud-native architecture using Kubernetes Gateways and a specialized Router, while maintaining a convenient Developer Mode for local testing.
The client operates in four modes:
- Production (Gateway Mode): Traffic flows from the Client -> Cloud Load Balancer (Gateway) -> Router Service -> Sandbox Pod. This supports high-scale deployments.
- Development (Tunnel Mode): Traffic flows from Localhost ->
kubectl port-forward-> Router Service -> Sandbox Pod. This requires no public IP and works on Kind/Minikube. - In-Cluster Mode: The client connects directly to the sandbox pod (via pod IP or cluster DNS), bypassing the router. Intended for workloads running inside the cluster.
- Advanced / Internal Mode: The client connects directly to a provided
api_url, bypassing discovery. This is useful when connecting through a custom domain or a manually specified router URL.
- A running Kubernetes cluster.
- The Agent Sandbox Controller installed.
kubectlinstalled and configured locally.
Before using the client, you must deploy the sandbox-router. This is a one-time setup.
-
Build and Push the Router Image:
For both Gateway Mode and Tunnel Mode, follow the instructions in sandbox-router to build, push, and apply the router image and resources.
-
Create a Sandbox Template:
Ensure a
SandboxTemplateexists in your target namespace. The test_client.py uses the python-runtime-sandbox image.kubectl apply -f python-sandbox-template.yaml
-
Create a virtual environment:
python3 -m venv .venv source .venv/bin/activate -
Install Agent Sandbox Client
-
Option 1: Install from PyPI (Recommended):
The package is available on PyPI as
k8s-agent-sandbox.pip install k8s-agent-sandbox
If you are using tracing with GCP, install with the optional tracing dependencies:
pip install "k8s-agent-sandbox[tracing]" -
Option 2: Install from source via git:
# Replace "main" with a specific version tag (e.g., "v0.1.0") from # https://github.com/kubernetes-sigs/agent-sandbox/releases to pin a version tag. export VERSION="main" pip install "git+https://github.com/kubernetes-sigs/agent-sandbox.git@${VERSION}#subdirectory=clients/python/agentic-sandbox-client"
Note: This package uses
setuptools-scmfor dynamic versioning. For Option 2 and Option 3, when installing locally, you may notice the version increment if your local repository has uncommitted changes or is ahead of the last tagged release. This is expected behavior to ensure unique versioning during development. -
Option 3: Install from source in editable mode:
If you have not already done so, first clone this repository:
cd ~ git clone https://github.com/kubernetes-sigs/agent-sandbox.git cd agent-sandbox/clients/python/agentic-sandbox-client
And then install the agentic-sandbox-client into your activated .venv:
pip install -e .If you are using tracing with GCP, install with the optional tracing dependencies:
pip install -e ".[tracing]"
-
Use this when running against a real cluster with a public Gateway IP. The client automatically discovers the Gateway.
from k8s_agent_sandbox import SandboxClient
from k8s_agent_sandbox.models import SandboxGatewayConnectionConfig
# Connect via the GKE Gateway
client = SandboxClient(
connection_config=SandboxGatewayConnectionConfig(
gateway_name="external-http-gateway", # Name of the Gateway resource
)
)
sandbox = client.create_sandbox(template="python-sandbox-template", namespace="default")
try:
print(sandbox.commands.run("echo 'Hello from Cloud!'").stdout)
finally:
sandbox.terminate()Use this for local development or CI. The client automatically opens a secure tunnel to the
Router Service using kubectl.
from k8s_agent_sandbox import SandboxClient
from k8s_agent_sandbox.models import SandboxLocalTunnelConnectionConfig
# Automatically tunnels to svc/sandbox-router-svc
client = SandboxClient(
connection_config=SandboxLocalTunnelConnectionConfig()
)
sandbox = client.create_sandbox(template="python-sandbox-template", namespace="default")
try:
print(sandbox.commands.run("echo 'Hello from Local!'").stdout)
finally:
sandbox.terminate()Use this when the client runs inside the cluster (for example, another pod in the same cluster). The client connects directly to the sandbox runtime pod, bypassing the sandbox router.
The default is cluster DNS (use_pod_ip=False). Omit the argument or pass use_pod_ip=False
to use it; set use_pod_ip=True only when you want the pod IP path.
Option A: Direct Pod IP — SandboxInClusterConnectionConfig(use_pod_ip=True)
- Uses the pod IP from the Sandbox status for low-latency, direct connections without relying on cluster DNS resolution.
Option B: Cluster DNS — SandboxInClusterConnectionConfig(use_pod_ip=False)
- Uses a stable DNS-style endpoint (typically
http://{sandbox_id}.{namespace}.svc.cluster.local:{server_port}). Prefer this when you want stable DNS-based routing across pod lifecycle events.
from k8s_agent_sandbox import SandboxClient
from k8s_agent_sandbox.models import SandboxInClusterConnectionConfig
# Choose one connection_config (default = cluster DNS):
# SandboxInClusterConnectionConfig() # same as use_pod_ip=False
# Option A — direct pod IP (low latency):
# SandboxInClusterConnectionConfig(use_pod_ip=True)
connection_config = SandboxInClusterConnectionConfig()
client = SandboxClient(connection_config=connection_config)
sandbox = client.create_sandbox(template="python-sandbox-template", namespace="default")
try:
print(sandbox.commands.run("echo 'Hello from in-cluster!'").stdout)
finally:
sandbox.terminate()Use SandboxDirectConnectionConfig to bypass discovery entirely. Useful for:
- Internal Agents: Running inside the cluster (e.g. router Service DNS).
- Custom Domains: Connecting via HTTPS (e.g.,
https://sandbox.example.com).
from k8s_agent_sandbox import SandboxClient
from k8s_agent_sandbox.models import SandboxDirectConnectionConfig
client = SandboxClient(
connection_config=SandboxDirectConnectionConfig(
api_url="http://sandbox-router-svc.default.svc.cluster.local:8080"
)
)
sandbox = client.create_sandbox(template="python-sandbox-template", namespace="default")
try:
sandbox.commands.run("ls -la")
finally:
sandbox.terminate()If your sandbox runtime listens on a port other than 8888 (e.g., a Node.js app on 3000), specify server_port.
from k8s_agent_sandbox import SandboxClient
from k8s_agent_sandbox.models import SandboxLocalTunnelConnectionConfig
client = SandboxClient(
connection_config=SandboxLocalTunnelConnectionConfig(server_port=3000)
)
sandbox = client.create_sandbox(template="node-sandbox-template", namespace="default")For async applications (FastAPI, aiohttp, async agent orchestrators), use the AsyncSandboxClient.
Install the async extras first:
pip install k8s-agent-sandbox[async]The async client requires an explicit connection config — SandboxLocalTunnelConnectionConfig
is not supported because it relies on a synchronous kubectl port-forward subprocess. Use
SandboxGatewayConnectionConfig, SandboxDirectConnectionConfig, or
SandboxInClusterConnectionConfig instead.
Direct connection (explicit URL, e.g. router service):
import asyncio
from k8s_agent_sandbox import AsyncSandboxClient
from k8s_agent_sandbox.models import SandboxDirectConnectionConfig
async def main():
config = SandboxDirectConnectionConfig(
api_url="http://sandbox-router-svc.default.svc.cluster.local:8080"
)
async with AsyncSandboxClient(connection_config=config) as client:
sandbox = await client.create_sandbox(
template="python-sandbox-template",
namespace="default",
)
result = await sandbox.commands.run("echo 'Hello from async!'")
print(result.stdout)
asyncio.run(main())In-cluster (direct to sandbox pod; default: cluster DNS):
import asyncio
from k8s_agent_sandbox import AsyncSandboxClient
from k8s_agent_sandbox.models import SandboxInClusterConnectionConfig
async def main():
config = SandboxInClusterConnectionConfig() # default: cluster DNS
async with AsyncSandboxClient(connection_config=config) as client:
sandbox = await client.create_sandbox(
template="python-sandbox-template",
namespace="default",
)
result = await sandbox.commands.run("echo 'Hello from async!'")
print(result.stdout)
asyncio.run(main())A test script is included to verify the full lifecycle (Creation -> Execution -> File I/O -> Cleanup).
python test_client.py --namespace defaultpython test_client.py --gateway-name external-http-gateway