Autonomous AI systems are only as useful as the actions they can verify. With the release of Gemini 4 Argon, multi-step reasoning and native tool calling allow agents to write data transformation scripts, generate infrastructure migrations, and debug failing tests across long execution horizons. However, a fundamental architectural bottleneck emerges the moment the model outputs a block of Python or Bash: something has to execute that code and return the output so the model can iterate.
Running LLM-generated code inside the same Kubernetes Pod as your orchestrator application is an immediate security liability. A hallucinated command, a prompt-injection payload, or a dependency conflict can corrupt the container filesystem, exfiltrate mounted service account credentials, or starve adjacent workloads of memory. Conversely, spinning up a fresh Kubernetes Job or virtual machine for every turn of a multi-step reasoning loop introduces 5 to 30 seconds of cold-start latency per iteration, stalling the agent workflow.
By pairing a Gemini 4 Argon reasoning loop with GKE Agent Sandbox (Generally Available on GKE 1.32 and later across both GKE Autopilot and GKE Standard), platform teams can isolate every code execution step inside a kernel-hardened gVisor runtime with sub-second allocation from pre-warmed Pod pools.
In this article, I will walk through the architecture of a self-correcting Gemini 4 Argon code execution loop on Google Kubernetes Engine (GKE), show how to configure warm sandbox pools across GKE Autopilot and Standard, and implement a Python orchestrator that claims, executes, and recycles isolated sandboxes.
Architectural tension in multi-turn code execution
When a Gemini 4 Argon agent solves an analytical or engineering task, it rarely stops at a single code snippet. Instead, it operates in an iterative loop:
- Task submission: The client sends an analytical query or code generation request to the GKE orchestrator Pod.
-
Model reasoning and tool dispatch: The orchestrator invokes Gemini 4 Argon with an
execute_pythontool declaration. The model emits a tool call containing the proposed script. - Warm pool allocation: The orchestrator requests a pre-warmed sandbox from the GKE Sandbox Router, which allocates an initialized gVisor Pod in under 200ms.
-
Isolated execution: The untrusted script runs inside the sandbox, capturing
stdout,stderr, and exit codes without host kernel access. - Recycling and feedback: The used sandbox is returned to the router for teardown, and execution outputs are fed back to Gemini 4 Argon for iterative refinement until the final answer is ready.
Evaluating where to execute that generated code requires balancing isolation boundaries against allocation latency:
| Execution pattern | Isolation boundary | Allocation latency | Operational trade-off |
|---|---|---|---|
In-process subprocess in orchestrator Pod |
Shared container kernel and filesystem | < 10ms | Exposes Workload Identity tokens, application memory, and internal cluster networking to arbitrary code |
Per-invocation Kubernetes Job |
Standard container (runc) or RuntimeClass
|
3s to 20s | Scheduling, image pulling, and container initialization add seconds of delay to every turn of the agent loop |
GKE Agent Sandbox with SandboxWarmPool |
User-space kernel via gVisor + default-deny network | < 200ms (p90) | Requires maintaining a small footprint of pre-warmed idle Pods in exchange for sub-second isolation |
GKE Agent Sandbox resolves this tension by combining four open-source custom resources from the kubernetes-sigs/agent-sandbox project with GKE kernel isolation:
-
Kernel-level isolation via
Sandboxand gVisor: EachSandbox(agents.x-k8s.io/v1alpha1) manages an isolated Pod running inside GKE Sandbox, intercepting application system calls in user space so untrusted code never interacts directly with the host Linux kernel. -
Reusable blueprints via
SandboxTemplate: ASandboxTemplate(extensions.agents.x-k8s.io/v1alpha1) defines the Pod specification, resource boundaries, and security context once for a class of agent tools. -
Pre-warmed capacity via
SandboxWarmPool: Rather than waiting for the Kubernetes scheduler and container runtime on each tool call, aSandboxWarmPool(extensions.agents.x-k8s.io/v1alpha1) maintains a standing buffer of initializedSandboxPods ready to be claimed in under 200 milliseconds. -
Declarative allocation via
SandboxClaimand zero-trust posture: When an agent needs to run code, the Sandbox Router creates aSandboxClaim(extensions.agents.x-k8s.io/v1alpha1) to bind a warmSandboxPod and deletes the claim on release. Sandbox Pods disable Kubernetes service account token automounting (automountServiceAccountToken: false) and enforce strict network egress policies, keeping your orchestrator's Workload Identity Federation for GKE credentials unreachable from the code execution environment.
Configuring the cluster and sandbox node pools
Before deploying the sandbox templates and the Gemini orchestrator, you need a GKE cluster with gVisor (GKE Sandbox) support and the Agent Sandbox controller installed.
Enabling Agent Sandbox on GKE Autopilot
On GKE Autopilot, GKE Sandbox is supported out of the box and automatically provisions gVisor-enabled compute capacity whenever Pods request runtimeClassName: gvisor. If you are using the managed GKE Agent Sandbox addon preview, pass --enable-agent-sandbox via gcloud beta; otherwise, create a standard Autopilot cluster and install the upstream controller manifests in the next step:
export PROJECT_ID="production-ai-platform"
export LOCATION="us-central1"
export CLUSTER_NAME="agent-execution-cluster"
gcloud beta container clusters create-auto "${CLUSTER_NAME}" \
--project="${PROJECT_ID}" \
--location="${LOCATION}" \
--enable-agent-sandbox
Enabling Agent Sandbox on GKE Standard
On GKE Standard, your cluster must keep at least one regular node pool for system Pods while isolating untrusted execution onto a dedicated node pool configured with --image-type=cos_containerd and --sandbox=type=gvisor. Separating the untrusted execution node pool from the node pool hosting your orchestrator Pods also prevents noisy-neighbor resource contention:
# Enable the Agent Sandbox addon on an existing Standard cluster (beta)
gcloud beta container clusters update "${CLUSTER_NAME}" \
--project="${PROJECT_ID}" \
--location="${LOCATION}" \
--enable-agent-sandbox
# Create a dedicated gVisor node pool for untrusted code execution
gcloud container node-pools create sandbox-execution-pool \
--cluster="${CLUSTER_NAME}" \
--project="${PROJECT_ID}" \
--location="${LOCATION}" \
--machine-type=e2-standard-8 \
--image-type=cos_containerd \
--sandbox=type=gvisor \
--num-nodes=3 \
--enable-autoscaling \
--min-nodes=2 \
--max-nodes=10
If you are installing the open-source kubernetes-sigs/agent-sandbox controller and extension CRDs (Sandbox, SandboxTemplate, SandboxClaim, and SandboxWarmPool) directly onto any GKE Autopilot or Standard cluster, apply the release manifests:
export AGENT_SANDBOX_VERSION="v0.1.0"
kubectl apply -f "https://github.com/kubernetes-sigs/agent-sandbox/releases/download/${AGENT_SANDBOX_VERSION}/manifest.yaml"
kubectl apply -f "https://github.com/kubernetes-sigs/agent-sandbox/releases/download/${AGENT_SANDBOX_VERSION}/extensions.yaml"
Defining the SandboxTemplate, SandboxWarmPool, and SandboxClaim
Once the cluster and CRDs are ready, you define the execution environment using SandboxTemplate and SandboxWarmPool. When you specify runtimeClassName: gvisor on GKE, the GKE admission controller automatically injects the required sandbox.gke.io/runtime: gvisor node selector and taint tolerations on both Autopilot and Standard clusters.
Create a manifest named analytics-sandbox-pool.yaml in a dedicated agent-sandboxes namespace. This configuration enforces non-root execution, drops all Linux capabilities, disables service account token mounting, and keeps 5 pre-warmed Python runtime Pods ready for tool calls:
apiVersion: v1
kind: Namespace
metadata:
name: agent-sandboxes
---
apiVersion: extensions.agents.x-k8s.io/v1alpha1
kind: SandboxTemplate
metadata:
name: python-analytics-template
namespace: agent-sandboxes
spec:
podTemplate:
metadata:
labels:
app.kubernetes.io/component: execution-sandbox
sandbox-tier: untrusted-python
spec:
# GKE automatically adds the gVisor nodeSelector and toleration for this RuntimeClass
runtimeClassName: gvisor
automountServiceAccountToken: false
securityContext:
runAsNonRoot: true
runAsUser: 10001
seccompProfile:
type: RuntimeDefault
containers:
- name: python-runtime
image: registry.k8s.io/agent-sandbox/python-runtime-sandbox:v0.1.0
ports:
- containerPort: 8888
securityContext:
allowPrivilegeEscalation: false
capabilities:
drop:
- ALL
resources:
requests:
cpu: "500m"
memory: "1Gi"
ephemeral-storage: "2Gi"
limits:
cpu: "1000m"
memory: "1Gi"
ephemeral-storage: "2Gi"
---
apiVersion: extensions.agents.x-k8s.io/v1alpha1
kind: SandboxWarmPool
metadata:
name: python-analytics-warmpool
namespace: agent-sandboxes
spec:
replicas: 5
sandboxTemplateRef:
name: python-analytics-template
Under the hood, whenever the Sandbox Router (or a Kubernetes client) allocates a sandbox from this warm pool, it creates a SandboxClaim resource targeting python-analytics-template:
apiVersion: extensions.agents.x-k8s.io/v1alpha1
kind: SandboxClaim
metadata:
name: analytics-task-claim-example
namespace: agent-sandboxes
spec:
sandboxTemplateRef:
name: python-analytics-template
To prevent untrusted code from scanning internal cluster services or calling the GKE metadata server, apply a default-deny NetworkPolicy (isolate-untrusted-sandboxes.yaml) in the agent-sandboxes namespace that blocks all egress and only permits ingress on port 8888 from the Sandbox Router:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: isolate-untrusted-sandboxes
namespace: agent-sandboxes
spec:
podSelector:
matchLabels:
app.kubernetes.io/component: execution-sandbox
policyTypes:
- Ingress
- Egress
ingress:
- from:
- namespaceSelector:
matchLabels:
kubernetes.io/metadata.name: agent-sandbox-system
- podSelector:
matchLabels:
app.kubernetes.io/component: sandbox-router
ports:
- protocol: TCP
port: 8888
egress: []
Apply the manifests to your cluster:
kubectl apply -f analytics-sandbox-pool.yaml
kubectl apply -f isolate-untrusted-sandboxes.yaml
Building the Gemini orchestrator loop
With the sandbox pool running in agent-sandboxes, you can deploy the orchestrator service in a separate agent-orchestrator namespace. The orchestrator uses Workload Identity Federation for GKE to authenticate with the Gemini platform and calls the Sandbox Router whenever Gemini invokes the code execution tool.
Here is the core implementation (orchestrator.py) using the google-genai SDK and the agentic_sandbox client. In the snippet below, GEMINI_MODEL defaults to gemini-4-argon:
import os
from google import genai
from google.genai import types
from agentic_sandbox import SandboxClient
# Defaults to gemini-4-argon on the Gemini platform:
MODEL_ID = os.environ.get("GEMINI_MODEL", "gemini-4-argon")
# Initialize the Gemini platform client using Workload Identity credentials
genai_client = genai.Client(
vertexai=True,
project=os.environ["GOOGLE_CLOUD_PROJECT"],
location=os.environ.get("GOOGLE_CLOUD_LOCATION", "us-central1"),
)
# Initialize the GKE Agent Sandbox client (communicates via the Sandbox Router)
sandbox_client = SandboxClient(namespace="agent-sandboxes")
def execute_python_in_sandbox(code: str) -> dict[str, str | int]:
"""Executes Python code inside an isolated GKE gVisor sandbox and returns stdout, stderr, and exit code."""
sandbox = sandbox_client.claim_sandbox(
template_name="python-analytics-template",
timeout_seconds=5,
)
try:
result = sandbox.execute(code, timeout_seconds=30)
return {
"stdout": result.output or "",
"stderr": result.error or "",
"exit_code": result.exit_code,
}
finally:
# Always release the sandbox so the SandboxClaim is deleted and replaced
sandbox.release()
def run_autonomous_task(user_prompt: str) -> str:
"""Runs a multi-turn Gemini 4 Argon reasoning loop backed by GKE Agent Sandbox."""
config = types.GenerateContentConfig(
system_instruction=(
"You are a quantitative engineering agent. When solving data or systems problems, "
"write Python scripts and run them using execute_python_in_sandbox. "
"If execution returns a non-zero exit_code or stderr traceback, inspect the error, "
"adjust your code, and re-run until the output is verified."
),
tools=[execute_python_in_sandbox],
automatic_function_calling=types.AutomaticFunctionCallingConfig(
maximum_remote_calls=10,
),
temperature=0.1,
)
chat = genai_client.chats.create(
model=MODEL_ID,
config=config,
)
response = chat.send_message(user_prompt)
return response.text or ""
When genai_client.chats.create receives a tool declaration with a typed Python function, the google-genai SDK automatically manages the multi-turn tool-calling loop (bounded by maximum_remote_calls=10), invoking execute_python_in_sandbox each time the model emits a function call and feeding the structured stdout, stderr, and exit_code dictionary back into the conversation context. Because sandbox.release() runs inside a finally block, every execution turn gets a clean, ephemeral container filesystem, preventing state pollution across unrelated tasks.
Verifying sandbox allocation and observability
After deploying the warm pool and orchestrator, verify that the pre-warmed Pods are scheduled under the gVisor runtime and that the warm pool controller is maintaining target capacity:
# Inspect the warm pool status, active sandboxes, and claims
kubectl get sandboxwarmpool,sandbox,sandboxclaim -n agent-sandboxes
# Confirm that sandbox Pods are running with RuntimeClass gvisor
kubectl get pods -n agent-sandboxes \
-l app.kubernetes.io/component=execution-sandbox \
-o custom-columns="NAME:.metadata.name,STATUS:.status.phase,RUNTIME:.spec.runtimeClassName,NODE:.spec.nodeName"
Expected output:
NAME STATUS RUNTIME NODE
python-analytics-warmpool-6d8f9b7c4-2x9kl Running gvisor gke-agent-execution-sandbox-pool-8a12f-9b2c
python-analytics-warmpool-6d8f9b7c4-7m4pq Running gvisor gke-agent-execution-sandbox-pool-8a12f-9b2c
python-analytics-warmpool-6d8f9b7c4-9v1zr Running gvisor gke-agent-execution-sandbox-pool-8a12f-c41d
To inspect sandbox claim latency and catch container OOM kills triggered by runaway agent scripts in Cloud Logging, run the following query:
resource.type="k8s_pod"
resource.labels.namespace_name="agent-sandboxes"
(reason="OOMKilling" OR reason="SandboxClaimed" OR reason="SandboxReleased")
In Cloud Monitoring, track kubernetes.io/pod/ephemeral_storage/used_bytes and kubernetes.io/container/memory/used_bytes filtered by namespace_name="agent-sandboxes" to rightsize your SandboxTemplate resource limits based on the actual memory footprint of the scripts Gemini 4 Argon generates.
Operational trade-offs and sharp edges
When running GKE Agent Sandbox with Gemini 4 Argon in production, keep these operational boundaries in mind:
-
Warm pool sizing vs. burst concurrency: If 20 concurrent Gemini 4 Argon requests trigger tool execution simultaneously and your
SandboxWarmPoolonly holdsreplicas: 5, the remaining 15 requests will wait for cold Pod creation. Sizereplicasto cover your p95 burst concurrency during peak traffic hours. -
Stateful multi-step sessions: In the example above, releasing the sandbox inside
execute_python_in_sandboxdestroys the Pod after every turn. If your Gemini 4 Argon agent writes files to disk in turn 1 and analyzes them in turn 2, bind thesandboxinstance to thechatsession lifecycle and invokesandbox.release()only after the entire conversation completes. - gVisor syscall overhead for heavy I/O: Because gVisor intercepts system calls in user space, compute-bound Python scripts (such as NumPy or Pandas array operations) run near native speed, whereas workloads performing thousands of small file opens or network socket creations incur additional CPU overhead.
-
Hard execution timeouts: LLM-generated code can inadvertently introduce infinite
whileloops. Always enforce a stricttimeout_secondsparameter onsandbox.execute()so the orchestrator returns a timeout error to Gemini 4 Argon rather than blocking the request worker indefinitely.
Next steps
Pairing Gemini 4 Argon with GKE Agent Sandbox gives your agents the ability to test and self-correct their own code without exposing your cluster or credentials to untrusted execution. By isolating every tool invocation inside a pre-warmed gVisor Pod with zero network egress, you get both kernel-level safety and sub-second iteration latency.
To build this pattern in your own environment, explore the GKE Agent Sandbox conceptual guide, follow the GKE Agent Sandbox installation instructions, and check out the upstream kubernetes-sigs/agent-sandbox repository.
Top comments (0)