🚀 Announcing Agent Sandbox v1.0.7!
We're excited to announce Agent Sandbox v1.0.7! This release adds optional bearer-token authentication to sandboxd, streaming command execution in the Go SDK, and closer parity across the Python and TypeScript SDKs (env and cwd, named claims, custom kubeconfig, fail-fast on terminated Pods). Warm pools no longer churn members that are waiting on scheduling gates, and they now report missing templates. sandbox-router adds traffic metrics. The multi-cluster fleet example is now complete, and there are new examples for KubeRay RLlib, agent memory that outlives the sandbox, and namespace-wide network policies for RL fleets.
⚠️ Behavior Changes / Action Required
- Python SDK No Longer Configures the Root Logger (#1900): Importing the SDK used to call
logging.basicConfig, which made the application's ownbasicConfigcall do nothing. The SDK now uses module loggers and leaves logging setup to the application.- Action Required: To keep seeing the SDK's INFO logs, call
logging.basicConfig(level=logging.INFO)in your application.
- Action Required: To keep seeing the SDK's INFO logs, call
- sandboxd Signal Exit Codes (#1897): A process killed by signal
nnow reports exit code128+n(for example,137for SIGKILL) instead of-1, in bothStartandExecute. This matches what a shell reports, and it separates killed or OOM-killed commands from daemon-side failures.- Action Required: Callers that treated
-1as "killed by a signal" should check for128+ninstead.
- Action Required: Callers that treated
WarmPoolNotProgressingEvent Action (#1817): The event's action is now the hold cause (HoldingUnschedulable,HoldingSchedulingGated, orHoldingUnschedulableAndSchedulingGated), notReconciling.- Action Required: Update any alerts or event filters that match on
Reconciling.
- Action Required: Update any alerts or event filters that match on
Key Highlights
Core Controller & Warm Pools
- Warm Pools Hold Members Waiting on Scheduling Gates (#1817): A warm pool member whose Pod waits on scheduling gates (
SchedulingGated, for example Kueue admission) is now held the same way as anUnschedulablemember, instead of being deleted as stuck when the readiness grace period expires. The grace period now starts when the Pod is scheduled, not when the Sandbox is created, so a member that has just been scheduled isn't deleted while it pulls images. In a Kueue test with too little quota, a 4-replica pool went from 11 sandboxes deleted as stuck to none. - Missing Template Warning (#1572): When a
SandboxWarmPoolneeds replicas but itsSandboxTemplateis missing, it now emits oneSandboxTemplateErrorwarning event and retries every minute until the template exists. - SandboxClaim
FinishedCondition Generation (#1898): A claim'sFinishedcondition now reports the claim's ownobservedGenerationinstead of copying the Sandbox's.kubectl wait --for=condition=Finishedno longer times out after a claim-only spec change such asspec.lifecycle.shutdownTime. --enable-rest-client-metricsFlag (#1571): A new controller flag, also exposed as a Helm value, turns off the client-go REST client histograms (request latency and size, DNS, rate limiting, retries). It defaults totrue.rest_client_requests_totalis always reported.
sandboxd
- Optional Bearer-Token Authentication (#1895): Set
--auth-token-sha256=<hex>or--auth-token-file=<path>(for example, a mounted Secret) to requireAuthorization: Bearer <token>on every REST request and gRPC call. With the digest flag, only the token's SHA-256 digest goes in the Pod spec.GET /v1/healthstays open for kubelet probes. If neither flag is set, behavior is unchanged. NetworkPolicy is still the primary boundary. --root-dir=/Now Works (#1896): With--root-dir=/, every path except/(for example,/tmp) was rejected as escaping the root. These paths now resolve. ADELETEof/itself is refused with403.
SDKs
- Go SDK:
- Streaming Command Execution (#1901):
Commands.Startreturns aProcessHandlethat streams stdout and stderr as output arrives, reports the exit code, and sends SIGINT, SIGTERM, or SIGKILL. Cancelling one session doesn't close the shared connection or delete the claim. Requires thesandboxdruntime.
- Streaming Command Execution (#1901):
- Python SDK:
envandcwdforcommands.run(#1893): Available in both the sync and async clients with thesandboxdruntime. The legacy runtime raisesNotImplementedError.SandboxClientas a Context Manager (#1894): On exit,with SandboxClient() as client:runs the same cleanup as theatexithook, matchingAsyncSandboxClient.- Short Readiness Waits (#1915): Fixed one-second readiness waits that failed immediately with
TimeoutError. Watches also no longer drop the last fraction of a second of the timeout after a reconnect.
- TypeScript SDK:
- New
createSandboxOptions (#1904, #1914):envsets environment variables on the claim (spec.env).claimNameandadoptExistingcreate or adopt a named claim that the caller owns. Both match the Python SDK. - Custom
KubeConfig(#1909):SandboxClientaccepts akubeConfigto target a specific cluster or user, matching Python'sapi_clientand Go'sOptions.RestConfig. - Faster
getSandboxReattach (#1877):resolveTimeoutlimits how long to wait for the claim's Sandbox name.waitForReady: falsereturns a handle without waiting for the Sandbox to become Ready. Previously, reattaching could wait the fullsandboxReadyTimeout(180s by default). - Packaging Fixes (#1922, #1888): The package now builds in
prepackinstead ofprepare, so installing it no longer runs an install script that needstsc.PodTunnelno longer deep-imports@kubernetes/client-nodeinternals, which would have broken if a later2.xrelease adds anexportsmap. - Empty Pod-Name Annotation (#1903): An empty
agents.x-k8s.io/pod-nameannotation now falls back to the Sandbox name, matching the controller and the Go and Python SDKs.
- New
- Python & TypeScript SDKs:
- Fail Fast on Terminated Pods (#1917):
create_sandboxandcreateSandboxraiseSandboxClaimFailedErroras soon as the claim reportsReady=Falsewith reasonPodFailedorPodSucceeded, instead of waiting for the timeout. This matches the Go SDK.
- Fail Fast on Terminated Pods (#1917):
sandbox-router
- Traffic Metrics (#1502): New byte counters for client traffic (
sandbox_router_client_rx_bytes_total,sandbox_router_client_tx_bytes_total, labeled bysandbox_namespace) and upstream traffic (sandbox_router_upstream_rx_bytes_total,sandbox_router_upstream_tx_bytes_total, labeled bysandbox_namespaceandsandbox_id). Two new histograms,sandbox_router_request_size_bytesandsandbox_router_response_size_bytes, use buckets from 100 B to 1 GB. Streamed (SSE) responses are counted as they're read.
Multi-Cluster Fleet & Reinforcement Learning
- Multi-Cluster Fleet Example Completed (#1541, #1542, #1544, #1545, #1908): Completes
examples/multi-cluster-fleet/, which started in v1.0.6. It adds deployment manifests, a hub bootstrap script (setup-hub.sh), and thefleet-memberimage. It also adds an operator README with aClusterProfileinventory walkthrough, e2e test tooling with a testing guide, and tools for diagnosing aClusterProfilehub integration. - One NetworkPolicy per Namespace for RL Fleets (#1861): The
agent-sandbox-rlSDK's newTemplateSpec.network_policy_managementsetsspec.networkPolicyManagementon the templates a fleet creates. WithUnmanagedtemplates, a fleet can run under one namespace-wideNetworkPolicyinstead of one per template, which avoids hundreds of policies that churn as pools come and go.preflight()warns if no policy covers the fleet's Pods. The newexamples/agent-sandbox-rl-network-policyprovides the policy, verification scripts, and guidance for GKE Dataplane V2 (Cilium identities). - KubeRay RayJob for RLlib (#1868): A CPU-only KubeRay
RayJobexample for RLlibSandboxEnv. It connects directly tosandboxdthrough in-cluster Service DNS, without the router or port-forwarding, and keeps checkpoints on a PVC.
Examples & Documentation
- Agent Memory That Outlives the Sandbox (#1913):
examples/recall-memorygives each claim persistent memory without putting a long-lived secret in the sandbox. The sandbox presents a projected service account token. The memory server validates it with TokenReview, follows the owner references from Pod to Sandbox to SandboxClaim, and issues a short-lived key scoped to that claim. Warm-pool sandboxes get no key until they are claimed. - One Service Across Claimed Sandboxes (#1887): Manifests and a walkthrough for putting several claimed Sandboxes behind one Kubernetes Service. Labels come from the claims'
additionalPodMetadata, so unclaimed warm-pool Pods stay out of the Service. - Reaching In-Cluster Services by DNS (#1911): A new Example 4 in
examples/policy/network-policy-management/shows aSandboxTemplatewhose sandboxes call an in-cluster Service by its DNS name (egress to kube-dns,dnsPolicy: ClusterFirst). - Port-Forward with Kata and gVisor (#1864): The SDK docs now say that
kubectl port-forward, the defaultsandboxdconnectivity mode, doesn't work with Kata or gVisor Pods. Use the in-cluster modes instead.
Integrations
- SDK 1.x Support (#1871): The
mcp-server,nemo-gym, andopenaiintegrations now acceptk8s-agent-sandbox>=1.0.0,<2.0. Fixedmcp-server'slist_fileson SDK 1.x. - OpenAI Agents Claim Leak (#1932):
K8sSandboxClient.delete()no longer reports success while leaving the claim, Pod, and PVC running when the claim lookup fails.
Installation
Standard Install (Core + Extensions)
Recommended for most users and GitOps engines (Argo CD, Config Sync, kustomize):
kubectl apply -f https://github.com/kubernetes-sigs/agent-sandbox/releases/download/v1.0.7/sandbox-with-extensions.yamlSelective Install
Install components separately:
# Core only:
kubectl apply -f https://github.com/kubernetes-sigs/agent-sandbox/releases/download/v1.0.7/sandbox.yaml
# Extensions (opt-in):
kubectl apply -f https://github.com/kubernetes-sigs/agent-sandbox/releases/download/v1.0.7/extensions.yamlPython SDK
pip install k8s-agent-sandbox==1.0.7Contributors
We extend our sincere thanks to all contributors to this release:
@HasonoCell, @Sean-790761, @YoungJinJung, @aditya-shantanu, @anuptalwalkar, @dependabot, @briankhoi, @chandwaniac, @dongjiang1989, @ericcurtin, @esposem, @git-jxj, @ilaigold, @khirotaka, @lunarwhite, @pranavthakur0-0, @tomergee, @toruiwasa, @vicentefb
New Contributors
- @chandwaniac made their first contribution in #1895
- @toruiwasa made their first contribution in #1898
- @pranavthakur0-0 made their first contribution in #1572
- @git-jxj made their first contribution in #1915
- @anuptalwalkar made their first contribution in #1911
Full Changelog: v1.0.6...v1.0.7