Back to Blogs
#kubernetes#ai#gke#googlecloud

Autonomous agent loops with Gemini 4 Argon and GKE Agent Sandbox: Running untrusted code safely at scale

Run untrusted LLM-generated Python and Bash code safely at scale using Gemini 4 Argon and GKE Agent Sandbox with gVisor isolation.

9 min read
Cover for Autonomous agent loops with Gemini 4 Argon and GKE Agent Sandbox: Running untrusted code safely at scale

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:

  1. Task submission: The client sends an analytical query or code generation request to the GKE orchestrator Pod.
  2. Model reasoning and tool dispatch: The orchestrator invokes Gemini 4 Argon with an execute_python tool declaration. The model emits a tool call containing the proposed script.
  3. Warm pool allocation: The orchestrator requests a pre-warmed sandbox from the GKE Sandbox Router, which allocates an initialized gVisor Pod in under 200ms.
  4. Isolated execution: The untrusted script runs inside the sandbox, capturing stdout, stderr, and exit codes without host kernel access.
  5. 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 Sandbox and gVisor: Each Sandbox (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: A SandboxTemplate (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, a SandboxWarmPool (extensions.agents.x-k8s.io/v1alpha1) maintains a standing buffer of initialized Sandbox Pods ready to be claimed in under 200 milliseconds.
  • Declarative allocation via SandboxClaim and zero-trust posture: When an agent needs to run code, the Sandbox Router creates a SandboxClaim (extensions.agents.x-k8s.io/v1alpha1) to bind a warm Sandbox Pod 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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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"
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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: []
Enter fullscreen mode Exit fullscreen mode

Apply the manifests to your cluster:

kubectl apply -f analytics-sandbox-pool.yaml
kubectl apply -f isolate-untrusted-sandboxes.yaml
Enter fullscreen mode Exit fullscreen mode

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 ""
Enter fullscreen mode Exit fullscreen mode

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"
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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")
Enter fullscreen mode Exit fullscreen mode

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 SandboxWarmPool only holds replicas: 5, the remaining 15 requests will wait for cold Pod creation. Size replicas to cover your p95 burst concurrency during peak traffic hours.
  • Stateful multi-step sessions: In the example above, releasing the sandbox inside execute_python_in_sandbox destroys 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 the sandbox instance to the chat session lifecycle and invoke sandbox.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 while loops. Always enforce a strict timeout_seconds parameter on sandbox.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.