Agent Sandbox

Go SDK Reference

Agent Sandbox Go SDK Reference.
import "sigs.k8s.io/agent-sandbox/clients/go/sandbox"

Index

Constants

const (

    // PodNameAnnotation is the deprecated annotation key on a Sandbox resource that identifies the name of the underlying pod.
    // Deprecated: New Sandboxes use their own name for the backing pod while non-empty legacy annotations may still be honored.
    PodNameAnnotation = "agents.x-k8s.io/pod-name"
)

Variables

Span attribute keys in the sandbox.* namespace.

var (
    AttrClaimName         = attribute.Key("sandbox.claim.name")
    AttrCommandExecutable = attribute.Key("sandbox.command.executable")
    AttrExitCode          = attribute.Key("sandbox.exit_code")
    AttrFilePath          = attribute.Key("sandbox.file.path")
    AttrFileSize          = attribute.Key("sandbox.file.size")
    AttrFileCount         = attribute.Key("sandbox.file.count")
    AttrFileExists        = attribute.Key("sandbox.file.exists")
    AttrGatewayName       = attribute.Key("sandbox.gateway.name")
    AttrGatewayNamespace  = attribute.Key("sandbox.gateway.namespace")
    AttrRequestID         = attribute.Key("sandbox.request_id")
)

Sentinel errors returned by the SDK.

var (
    ErrNotReady         = errors.New("sandbox is not ready")
    ErrTimeout          = errors.New("operation timed out")
    ErrClaimFailed      = errors.New("claim creation failed")
    ErrWarmPoolNotFound = errors.New("sandbox warm pool not found")
    ErrTemplateNotFound = errors.New("sandbox template not found")
    ErrPortForwardDied  = errors.New("port-forward connection lost")
    ErrNoSandboxService = errors.New("sandbox has no headless Service")
    ErrAlreadyOpen      = errors.New("sandbox is already open; call Close first")
    ErrOrphanedClaim    = errors.New("orphaned claim; call Close() to retry deletion")
    ErrRetriesExhausted = errors.New("retries exhausted")
    ErrSandboxDeleted   = errors.New("sandbox was deleted before becoming ready")
    ErrGatewayDeleted   = errors.New("gateway was deleted during address discovery")
    ErrResponseTooLarge = errors.New("response exceeded 16 MB limit")
    // ErrUnsupportedByRuntime is returned by operations the selected
    // runtime or connection cannot perform (e.g. Delete on the legacy
    // python-runtime, or Run with RuntimeSandboxd and APIURL).
    ErrUnsupportedByRuntime = errors.New("operation not supported by the sandbox runtime")
    // ErrProcessProtocol indicates an invalid or incomplete process event stream.
    ErrProcessProtocol = errors.New("invalid process event stream")
    // ErrConcurrentRecv indicates that another Recv is already in progress.
    ErrConcurrentRecv = errors.New("concurrent Recv on process handle")
)

func NewTracerProvider

func NewTracerProvider(ctx context.Context, serviceName string) (*sdktrace.TracerProvider, error)

NewTracerProvider creates a TracerProvider with an OTLP/gRPC exporter. The endpoint is read from OTEL_EXPORTER_OTLP_ENDPOINT (default: localhost:4317). serviceName becomes the service.name resource attribute. The caller owns the returned provider and must call Shutdown when done.

type CallOption

CallOption configures per-call behavior for SDK operations.

type CallOption func(*callOptions)

func WithEnv

func WithEnv(env map[string]string) CallOption

WithEnv sets environment variables for a single Run or Commands.Start, merged over the sandbox’s own environment (a key given here wins). Repeated calls accumulate. Both return ErrUnsupportedByRuntime on the legacy python-runtime, which cannot carry them. Other operations ignore it.

result, err := client.Run(ctx, "echo $GREETING", sandbox.WithEnv(map[string]string{"GREETING": "hi"}))

func WithMaxAttempts

func WithMaxAttempts(n int) CallOption

WithMaxAttempts sets the maximum number of attempts for an operation. Values ≤0 are ignored and the default is used (1 for Run, 6 for file operations). Commands.Start rejects values greater than 1 because a non-idempotent process creation cannot be safely replayed.

result, err := client.Run(ctx, "cat /etc/hostname", sandbox.WithMaxAttempts(6))

func WithTimeout

func WithTimeout(d time.Duration) CallOption

WithTimeout sets the total timeout for a single operation. HTTP operations override their default RequestTimeout. For Commands.Start it covers the entire stream, including startup; Start has no default timeout.

func WithWorkingDir

func WithWorkingDir(dir string) CallOption

WithWorkingDir sets the working directory for Run or Commands.Start, relative to the sandbox root (the default). sandboxd rejects a directory that resolves outside the root. Both return ErrUnsupportedByRuntime on the legacy python-runtime. Other operations ignore it.

type Client

Client manages sandbox lifecycles and tracks active handles.

type Client struct {
    // contains filtered or unexported fields
}

func NewClient

func NewClient(_ context.Context, opts Options) (*Client, error)

NewClient creates a Client with shared configuration.

func (*Client) CreateSandbox

func (c *Client) CreateSandbox(ctx context.Context, warmPoolName, namespace string, opts ...CreateOption) (*Sandbox, error)

CreateSandbox provisions a new sandbox and returns a managed handle. Optional CreateOption values override or merge onto the Client’s base Options for this call. On failure, a claim with a generated name is cleaned up; a claim named with WithClaimName is left in place.

func (*Client) DeleteAll

func (c *Client) DeleteAll(ctx context.Context)

DeleteAll closes and deletes all tracked sandboxes. Best-effort.

func (*Client) DeleteSandbox

func (c *Client) DeleteSandbox(ctx context.Context, claimName, namespace string) error

DeleteSandbox closes the handle (if tracked) and deletes the claim.

func (*Client) EnableAutoCleanup

func (c *Client) EnableAutoCleanup() (stop func())

EnableAutoCleanup deletes tracked sandboxes on SIGINT/SIGTERM. Claims created with WithClaimName are caller-owned: their handles are disconnected but the claims are kept. Call the returned function to stop the signal handler.

func (*Client) GetSandbox

func (c *Client) GetSandbox(ctx context.Context, claimName, namespace string) (*Sandbox, error)

GetSandbox retrieves an existing sandbox by claim name. Returns the cached handle if connected, otherwise re-attaches.

func (*Client) ListActiveSandboxes

func (c *Client) ListActiveSandboxes() []Key

ListActiveSandboxes returns tracked sandboxes, pruning inactive handles.

func (*Client) ListAllSandboxes

func (c *Client) ListAllSandboxes(ctx context.Context, namespace string, opts ...ListOption) ([]string, error)

ListAllSandboxes lists SandboxClaim names in the given namespace, optionally narrowed with WithLabelSelector.

type Commands

Commands provides command execution on a sandbox.

type Commands struct {
    // contains filtered or unexported fields
}

func (*Commands) Run

func (c *Commands) Run(ctx context.Context, command string, opts ...CallOption) (*ExecutionResult, error)

Run executes a command in the sandbox and returns the result. The combined JSON response (stdout + stderr + metadata) is limited to 16 MB; commands producing more output will fail with ErrResponseTooLarge.

Because command execution is not idempotent, Run defaults to a single attempt (no retries). For idempotent commands that should retry on transient server errors (502, 503, etc.), use WithMaxAttempts:

result, err := client.Run(ctx, "cat /etc/hostname", sandbox.WithMaxAttempts(6))

WithMaxAttempts applies only to the legacy runtime. With RuntimeSandboxd, Run issues a single gRPC Execute regardless of the configured attempts.

WithEnv and WithWorkingDir apply only to RuntimeSandboxd; the legacy runtime returns ErrUnsupportedByRuntime rather than silently ignoring them.

func (*Commands) Start

func (c *Commands) Start(ctx context.Context, command string, opts ...CallOption) (handle *ProcessHandle, err error)

Start starts a sandboxd command and returns after receiving its process ID. It preserves Run’s shell-string, WithEnv and WithWorkingDir semantics. The caller must Recv through the exit event to io.EOF, or Close the handle. The context and an explicit WithTimeout cover the entire stream; there is no default RequestTimeout. Start never retries and rejects WithMaxAttempts > 1. The legacy runtime and REST-only connections return ErrUnsupportedByRuntime.

type ConnectionStrategy

ConnectionStrategy defines how the SDK discovers or reaches a runtime’s HTTP endpoint, either directly or through the sandbox-router.

type ConnectionStrategy interface {
    Connect(ctx context.Context) (baseURL string, err error)
    Close() error
}

type Connectivity

Connectivity selects the transport used to reach the in-sandbox runtime.

type Connectivity string

const (
    // ConnectivityPortForward reaches the sandbox over a SPDY port-forward
    // brokered by the apiserver. Works from anywhere a kubeconfig does,
    // including a laptop or CI runner. Default.
    //
    // With RuntimeSandboxd the forward targets the sandbox pod itself, which
    // does not work for Kata or gVisor pods: their workload does not listen in
    // the pod's host-side network namespace. Use an in-cluster mode for those.
    // RuntimeLegacyPython forwards to the sandbox-router instead and is
    // unaffected.
    ConnectivityPortForward Connectivity = "port-forward"
    // ConnectivityInClusterService dials the Sandbox's headless Service by
    // its in-cluster DNS name (Status.ServiceFQDN), taking the apiserver —
    // and, for RuntimeLegacyPython, the sandbox-router, off the data path.
    //
    // Prefer this over ConnectivityInClusterPodIP when sandboxes cross a trust
    // boundary. The Service's selector only ever matches its own Sandbox's
    // pod, so a pod IP that Kubernetes has since reassigned to another
    // tenant would be caught when the TTL expires. A deleted Sandbox takes
    // its Service with it: connections then fail rather than landing on a stranger.
    // (DNS caching still leaves a TTL-bounded window)
    //
    // Requires the Sandbox to have a Service — set spec.service: true on
    // the template. Open fails when Status.ServiceFQDN is empty rather than
    // falling back to the pod IP, so the safety property cannot be lost
    // silently.
    ConnectivityInClusterService Connectivity = "in-cluster-service"

    // ConnectivityInClusterPodIP dials Status.PodIP. It needs no Service, so
    // it works against any Sandbox without template changes.
    //
    // It carries the pod IP's reuse hazard: nothing detects that the sandbox
    // pod was rescheduled, so requests can continue to a stale address that
    // Kubernetes may have since reassigned to an unrelated pod. Use
    // ConnectivityInClusterService where that matters.
    ConnectivityInClusterPodIP Connectivity = "in-cluster-pod-ip"
)

type CreateOption

CreateOption configures per-sandbox options for Client.CreateSandbox, overriding or merging onto the Client’s base Options for that call.

type CreateOption func(*createOptions)

func WithAdoptExisting

func WithAdoptExisting() CreateOption

WithAdoptExisting makes a single CreateSandbox call attach to an existing SandboxClaim named by WithClaimName instead of failing when it already exists. See Options.AdoptExisting for the checks applied to the existing claim.

func WithClaimEnv

func WithClaimEnv(env []extv1beta1.EnvVar) CreateOption

WithClaimEnv sets the environment variables injected into the SandboxClaim for a single CreateSandbox call, replacing Client-level Options.Env.

func WithClaimLabels

func WithClaimLabels(labels map[string]string) CreateOption

WithClaimLabels merges labels onto the SandboxClaim metadata for a single CreateSandbox call. Per-call keys override colliding Client-level Options.Labels keys; the SDK’s created-by label always wins. Repeated calls accumulate.

func WithClaimName

func WithClaimName(name string) CreateOption

WithClaimName sets a deterministic SandboxClaim name for a single CreateSandbox call. See Options.ClaimName.

func WithPodAnnotations

func WithPodAnnotations(annotations map[string]string) CreateOption

WithPodAnnotations merges annotations onto spec.additionalPodMetadata.annotations for a single CreateSandbox call. Per-call keys override colliding Client-level Options.PodAnnotations keys. Repeated calls accumulate.

func WithPodLabels

func WithPodLabels(labels map[string]string) CreateOption

WithPodLabels merges labels onto spec.additionalPodMetadata.labels for a single CreateSandbox call. Per-call keys override colliding Client-level Options.PodLabels keys. Repeated calls accumulate.

func WithSandboxReadyTimeout

func WithSandboxReadyTimeout(d time.Duration) CreateOption

WithSandboxReadyTimeout sets how long a single CreateSandbox call waits for the sandbox to become ready, replacing Client-level Options.SandboxReadyTimeout. Zero keeps the Client-level value.

func WithShutdownAfter

func WithShutdownAfter(d time.Duration) CreateOption

WithShutdownAfter sets the claim lifetime for a single CreateSandbox call, replacing Client-level Options.ShutdownAfter. Zero means no expiry.

func WithVolumeClaimTemplates

func WithVolumeClaimTemplates(templates []sandboxv1beta1.PersistentVolumeClaimTemplate) CreateOption

WithVolumeClaimTemplates sets spec.volumeClaimTemplates on the SandboxClaim for a single CreateSandbox call, replacing Client-level Options.VolumeClaimTemplates.

type DirectStrategy

DirectStrategy connects using a pre-configured URL, bypassing all discovery.

type DirectStrategy struct {
    URL string
}

func (*DirectStrategy) Close

func (s *DirectStrategy) Close() error

func (*DirectStrategy) Connect

func (s *DirectStrategy) Connect(_ context.Context) (string, error)

type ExecutionResult

ExecutionResult holds the result of a command execution in the sandbox.

type ExecutionResult struct {
    Stdout   string `json:"stdout"`
    Stderr   string `json:"stderr"`
    ExitCode int    `json:"exit_code"`
}

type FileEntry

FileEntry represents a file or directory entry in the sandbox. It is runtime-neutral: the SDK decodes the legacy wire format (mod_time as a float POSIX timestamp) and the sandboxd wire format (modified_at as an RFC 3339 string, plus mode) into this one shape.

type FileEntry struct {
    Name    string
    Size    int64
    Type    FileType
    ModTime time.Time
    // Mode holds octal permission bits (e.g. "0644"). Only populated by
    // the sandboxd runtime; empty on legacy.
    Mode string
}

type FileType

FileType represents the type of a file entry.

type FileType string

const (
    FileTypeFile      FileType = "file"
    FileTypeDirectory FileType = "directory"
)

type Files

Files provides file operations on a sandbox.

type Files struct {
    // contains filtered or unexported fields
}

func (*Files) Delete

func (f *Files) Delete(ctx context.Context, path string, recursive bool, opts ...CallOption) error

Delete removes a file or directory in the sandbox. When recursive is true, directories are removed with their contents (rm -rf semantics); otherwise deleting a non-empty directory fails with a 409 HTTPError.

Only supported by the sandboxd runtime: the legacy python-runtime has no delete endpoint, and calls return ErrUnsupportedByRuntime.

func (*Files) Exists

func (f *Files) Exists(ctx context.Context, path string, opts ...CallOption) (bool, error)

Exists checks if a file or directory exists at the given path in the sandbox.

func (*Files) List

func (f *Files) List(ctx context.Context, path string, opts ...CallOption) ([]FileEntry, error)

List returns the contents of a directory in the sandbox.

func (*Files) Read

func (f *Files) Read(ctx context.Context, path string, opts ...CallOption) ([]byte, error)

Read downloads a file from the sandbox and returns its complete contents.

func (*Files) ReadTo

func (f *Files) ReadTo(ctx context.Context, path string, destination io.Writer, opts ...CallOption) (int64, error)

ReadTo downloads a file into a caller-owned destination without buffering the complete response. It returns the number of bytes written. The destination is never closed. If the response exceeds MaxDownloadSize, ReadTo writes at most MaxDownloadSize bytes and returns an error. Data written before an error or context cancellation remains in the destination.

func (*Files) Write

func (f *Files) Write(ctx context.Context, path string, content []byte, opts ...CallOption) error

Write uploads content to the sandbox.

With the legacy runtime the path must be a plain filename without directory separators (e.g., “script.py”, not “dir/script.py”). The sandboxd runtime supports relative paths and creates parent directories automatically.

The entire content is buffered in memory to support retries on transient failures. Content exceeding MaxUploadSize (default 256 MB) is rejected before any network I/O.

func (*Files) WriteReader

func (f *Files) WriteReader(ctx context.Context, path string, content io.Reader, opts ...CallOption) error

WriteReader uploads content read from content without buffering the entire payload in memory. Streaming uploads use a single request attempt because a generic io.Reader cannot be replayed safely after a partial request. Passing WithMaxAttempts with a value greater than 1 returns an error; it is not silently reduced to a single attempt.

With the legacy runtime, path must be a plain filename. The sandboxd runtime accepts relative paths and creates parent directories automatically. For an unknown-length reader, MaxUploadSize is enforced while the request is being streamed; the server may therefore receive a prefix before an oversized upload is rejected. Legacy streaming uploads use HTTP chunked transfer encoding, so compatible runtimes and proxies must accept streaming request bodies without a Content-Length header.

type HTTPError

HTTPError represents a non-OK HTTP response from the sandbox.

type HTTPError struct {
    StatusCode int
    Body       string
    Operation  string
}

func (*HTTPError) Error

func (e *HTTPError) Error() string

type Handle

Handle provides high-level interaction with a sandbox instance. Sandbox implements this interface; consumers should accept Handle in their APIs to enable testing with mocks. For sub-object access (Commands(), Files()), use the concrete *Sandbox type directly.

type Handle interface {
    Open(ctx context.Context) error
    Close(ctx context.Context) error
    Disconnect(ctx context.Context) error
    IsReady() bool

    Run(ctx context.Context, command string, opts ...CallOption) (*ExecutionResult, error)
    Write(ctx context.Context, path string, content []byte, opts ...CallOption) error
    Read(ctx context.Context, path string, opts ...CallOption) ([]byte, error)
    List(ctx context.Context, path string, opts ...CallOption) ([]FileEntry, error)
    Exists(ctx context.Context, path string, opts ...CallOption) (bool, error)
}

type Health

Health is the sandboxd runtime’s report from GET /v1/health.

type Health struct {
    Status string `json:"status"`
    // UptimeSeconds is how long sandboxd has been running.
    UptimeSeconds int64 `json:"uptime_seconds"`
}

type Info

Info provides read-only access to sandbox identity metadata.

type Info interface {
    ClaimName() string
    SandboxName() string
    PodName() string
    PodIP() string
    Annotations() map[string]string
}

type K8sHelper

K8sHelper encapsulates all Kubernetes API interactions for sandbox lifecycle management. It can be shared across multiple Sandbox instances.

type K8sHelper struct {
    AgentsClient     agentsv1beta1.AgentsV1beta1Interface
    ExtensionsClient extensionsv1beta1.ExtensionsV1beta1Interface
    DynamicClient    dynamic.Interface
    CoreClient       corev1client.CoreV1Interface
    DiscoveryClient  discoveryv1client.DiscoveryV1Interface
    RestConfig       *rest.Config

    Log logr.Logger
}

func NewK8sHelper

func NewK8sHelper(restConfig *rest.Config, log logr.Logger) (*K8sHelper, error)

NewK8sHelper creates a K8sHelper by loading kubeconfig and constructing all required clientsets. If restConfig is non-nil it is used directly; otherwise in-cluster config is tried first, then ~/.kube/config.

func (*K8sHelper) WaitForSandboxReady

func (h *K8sHelper) WaitForSandboxReady(ctx context.Context, sandboxName, namespace string) error

WaitForSandboxReady waits until the named Sandbox has a true Ready condition. sandboxName is the backing Sandbox name, not the SandboxClaim name. It does not connect to the runtime. Use a context deadline to bound the wait; cancellation and deadline errors are detectable with errors.Is. A missing Sandbox is waited for, while deletion observed during the watch returns ErrSandboxDeleted. A terminal Ready=False reason such as PodFailed returns ErrClaimFailed. API list/watch failures are retried until ctx ends.

type Key

Key identifies a tracked sandbox in the registry.

type Key struct {
    Namespace string
    ClaimName string
}

type ListOption

ListOption configures Client.ListAllSandboxes.

type ListOption func(*listOptions)

func WithLabelSelector

func WithLabelSelector(selector string) ListOption

WithLabelSelector restricts the listing to claims matching a Kubernetes label selector, for example “app=agent,tier!=dev”. Pair it with Options.Labels, which stamps labels on the claims the client creates.

type Metadata

Metadata is the non-sensitive, workload-scoped configuration sandboxd serves from GET /v1/metadata.

type Metadata struct {
    // Env holds the environment variables sandboxd exposes: only names
    // matching its --metadata-env-prefix, minus anything that looks like a
    // credential. It is never nil.
    Env map[string]string `json:"env"`
}

type Options

Options configures a Sandbox instance.

type Options struct {
    // WarmPoolName is the name of the SandboxWarmPool to use.
    // Required in Options before calling Open() to provision a new sandbox.
    // Optional on Client-level Options; pass the pool name per-sandbox to
    // CreateSandbox instead.
    // Must be a valid Kubernetes DNS subdomain (lowercase, [a-z0-9.-]).
    WarmPoolName string

    // ClaimName is an optional deterministic name for the SandboxClaim.
    // When empty, Kubernetes generates a unique name with prefix "sandbox-claim-".
    // When set and a SandboxClaim with this name already exists in Namespace,
    // Open fails with ErrClaimFailed unless AdoptExisting is also set.
    // A named claim is caller-owned: a failed Open and
    // Client.EnableAutoCleanup leave it in place; Close still deletes it.
    // Must be a valid Kubernetes DNS subdomain (lowercase, [a-z0-9.-]).
    // NewClient rejects it; use WithClaimName with Client.CreateSandbox.
    ClaimName string

    // AdoptExisting makes Open attach to an existing SandboxClaim named
    // ClaimName when creating it returns HTTP 409 Conflict, instead of
    // failing. The existing claim must reference the same WarmPoolName and
    // must not be terminating, and Open fails if it is replaced or starts
    // terminating before its sandbox name resolves. Creation options are not
    // reapplied to an adopted claim.
    // Requires ClaimName. NewClient rejects it; use WithAdoptExisting with
    // Client.CreateSandbox.
    AdoptExisting bool

    // Runtime selects the in-sandbox runtime API. Default: RuntimeLegacyPython.
    // RuntimeSandboxd talks to the sandbox pod rather than the sandbox-router,
    // so GatewayName is not supported with it. APIURL remains available as an
    // advanced/testing escape hatch for the REST endpoint only: Run needs the
    // gRPC endpoint and returns ErrUnsupportedByRuntime with it.
    Runtime Runtime

    // Connectivity selects the transport. Default: ConnectivityPortForward.
    //
    // The in-cluster values conflict with both GatewayName and APIURL, and
    // require that this process runs inside the same cluster as the sandbox
    // pods.
    Connectivity Connectivity

    // SandboxdRESTPort is the pod port of sandboxd's Filesystem & Runtime
    // REST API. Only used with RuntimeSandboxd. Default: 8080.
    SandboxdRESTPort int

    // SandboxdGRPCPort is the pod port of sandboxd's gRPC ProcessService.
    // Only used with RuntimeSandboxd. Default: 9090.
    SandboxdGRPCPort int

    // Namespace where the SandboxClaim will be created. Default: "default".
    // Must be a valid Kubernetes DNS label (lowercase, [a-z0-9-]).
    Namespace string

    // GatewayName enables Gateway mode. The client watches this Gateway resource
    // for an external IP, then routes through the sandbox-router.
    // Must be a valid Kubernetes DNS subdomain (lowercase, [a-z0-9.-]).
    GatewayName string

    // GatewayNamespace is where the Gateway lives. Default: "default".
    // Must be a valid Kubernetes DNS label (lowercase, [a-z0-9-]).
    GatewayNamespace string

    // GatewayScheme is the URL scheme used when constructing the base URL
    // from the Gateway's address. Default: "http".
    GatewayScheme string

    // APIURL enables Direct URL mode. The client connects directly to this URL,
    // bypassing gateway discovery. Takes precedence over GatewayName.
    APIURL string

    // ServerPort is the port the sandbox runtime listens on. Default: 8888.
    ServerPort int

    // Env is the list of environment variables to inject into the SandboxClaim.
    // Setting Env forces a cold start from the warm pool template.
    Env []extv1beta1.EnvVar

    // Labels are added to every SandboxClaim this client creates, so they can
    // be selected later (see WithLabelSelector). The SDK's own created-by label
    // always wins over a colliding key.
    Labels map[string]string

    // ShutdownAfter expires every SandboxClaim this client creates that long
    // after creation, so a crashed client cannot leak sandboxes. The claim
    // gets spec.lifecycle.shutdownTime and the Delete shutdown policy; the
    // deadline is rounded up to a whole second. Zero (the default) means no expiry.
    ShutdownAfter time.Duration

    // PodLabels are propagated to the backing Sandbox Pod via
    // spec.additionalPodMetadata.labels (unlike Labels, which are placed on the
    // SandboxClaim object itself). Label keys must carry a domain prefix from
    // the controller's label-domain allowlist (default: sandbox.users.io).
    PodLabels map[string]string

    // PodAnnotations are propagated to the backing Sandbox Pod via
    // spec.additionalPodMetadata.annotations.
    PodAnnotations map[string]string

    // VolumeClaimTemplates is a list of persistent volume claim templates to
    // create for the sandbox via spec.volumeClaimTemplates. Setting
    // VolumeClaimTemplates forces a cold start because warm pool pods do not
    // have these volumes.
    VolumeClaimTemplates []sandboxv1beta1.PersistentVolumeClaimTemplate

    // SandboxReadyTimeout is how long to wait for the sandbox to become ready. Default: 180s.
    SandboxReadyTimeout time.Duration

    // GatewayReadyTimeout is how long to wait for the gateway IP. Default: 180s.
    GatewayReadyTimeout time.Duration

    // PortForwardReadyTimeout is how long to wait for port-forward to be established. Default: 30s.
    PortForwardReadyTimeout time.Duration

    // CleanupTimeout is how long to wait for claim deletion during both Open
    // rollback and Close. Uses a detached context so cleanup succeeds even if
    // the caller's context is already cancelled. Default: 30s.
    CleanupTimeout time.Duration

    // RequestTimeout is the total timeout for a single SDK method call
    // (e.g., Run, Read, Write), encompassing all retry attempts and backoff
    // sleeps. Applied only when the caller's context has no deadline.
    // Default: 180s.
    RequestTimeout time.Duration

    // PerAttemptTimeout bounds the time to receive response headers per
    // HTTP attempt. Stopped on success so body reads use RequestTimeout.
    // Default: 60s.
    PerAttemptTimeout time.Duration

    // MaxDownloadSize is the maximum response body size for Read() and ReadTo().
    // Run() uses a fixed 16 MB decode limit; List() and Exists() use a
    // fixed 8 MB internal limit. Default: 256 MB.
    MaxDownloadSize int64

    // MaxUploadSize is the maximum content size for Write() and WriteReader().
    // Write rejects oversized content before network I/O; WriteReader enforces
    // the limit while streaming. Default: 256 MB.
    MaxUploadSize int64

    // Logger for structured logging. Defaults to stderr at INFO level.
    // Provide a custom logr.Logger for full control, or set Quiet to
    // suppress output.
    Logger logr.Logger

    // Quiet suppresses the default stderr logger. Has no effect when a
    // custom Logger is provided (non-zero-value).
    Quiet bool

    // K8sHelper provides pre-constructed Kubernetes clients. If nil, a new
    // K8sHelper is created from RestConfig. Use this to share clients
    // across multiple Sandbox instances.
    K8sHelper *K8sHelper

    // RestConfig overrides the Kubernetes REST config. If nil, the client first
    // tries in-cluster config (for pods), then falls back to the default
    // kubeconfig (~/.kube/config or KUBECONFIG env). Ignored when K8sHelper is set.
    RestConfig *rest.Config

    // HTTPTransport overrides the HTTP transport for sandbox operations.
    // If nil, a default transport with sensible timeouts is created.
    // Use this for custom TLS, proxies, or other transport-level settings.
    HTTPTransport http.RoundTripper

    // TraceServiceName is the OpenTelemetry service name used for the tracer's
    // instrumentation scope and the resource's service.name attribute.
    // Default: "sandbox-client".
    TraceServiceName string

    // TracerProvider sets the OpenTelemetry TracerProvider for span creation.
    // If nil, falls back to otel.GetTracerProvider (noop by default).
    TracerProvider trace.TracerProvider

    // DisablePodIPRouting suppresses the X-Sandbox-Pod-IP header even when a
    // pod IP is available. Use in environments with strict network policies,
    // service meshes, or secure overlays where direct pod-to-pod IP routing is
    // restricted but service-based DNS routing works correctly.
    // Note: this only affects router-based transports that send X-Sandbox-* headers.
    // Default: false (header is sent when router headers are enabled and a pod IP is present).
    DisablePodIPRouting bool
}

type ProcessEvent

ProcessEvent contains one raw output chunk or the command’s exit code. Output chunks need not be complete lines or valid UTF-8. Events from stdout and stderr do not have a guaranteed global ordering.

type ProcessEvent struct {
    Type ProcessEventType
    // Data is populated only for stdout/stderr and remains valid after Recv.
    Data []byte
    // ExitCode is populated only for exit events. A nonzero code is not an error.
    ExitCode int
}

type ProcessEventType

ProcessEventType identifies an output or exit event from a streaming command.

type ProcessEventType string

const (
    ProcessEventStdout ProcessEventType = "stdout"
    ProcessEventStderr ProcessEventType = "stderr"
    ProcessEventExit   ProcessEventType = "exit"
)

type ProcessHandle

ProcessHandle owns one Start stream, not the Sandbox or shared connection. Consume its events through io.EOF or call Close when abandoning the stream.

type ProcessHandle struct {
    // contains filtered or unexported fields
}

func (*ProcessHandle) Close

func (h *ProcessHandle) Close() error

Close cancels only this session and is idempotent. A nil error acknowledges local cleanup, not synchronous remote process termination. For graceful shutdown, send a signal before cancelling the stream instead.

func (*ProcessHandle) ProcessID

func (h *ProcessHandle) ProcessID() int32

ProcessID returns the daemon-local virtual ID, not an OS PID. It cannot identify a process across daemon restarts.

func (*ProcessHandle) Recv

func (h *ProcessHandle) Recv() (*ProcessEvent, error)

Recv returns the next stdout, stderr or exit event. An exit event must be followed by io.EOF to confirm that the RPC also completed successfully. Nonzero exit codes are results; RPC and protocol failures remain errors. Only one Recv may be active; a second returns ErrConcurrentRecv without ending the stream. SendSignal and Close may run concurrently with Recv.

func (*ProcessHandle) SendSignal

func (h *ProcessHandle) SendSignal(ctx context.Context, signal ProcessSignal) error

SendSignal sends SIGINT, SIGTERM or SIGKILL to this process group using its original connection. Success means the signal was sent, not that the process exited. Its context controls only this RPC; failure does not cancel Start. Keep receiving events to observe the exit and the final RPC status.

type ProcessSignal

ProcessSignal is a supported POSIX signal for a sandboxd process group.

type ProcessSignal string

const (
    SignalSIGINT  ProcessSignal = "SIGINT"
    SignalSIGTERM ProcessSignal = "SIGTERM"
    SignalSIGKILL ProcessSignal = "SIGKILL"
)

type Runtime

Runtime identifies the in-sandbox runtime API the SDK speaks.

type Runtime string

const (
    // RuntimeLegacyPython is the python-runtime HTTP API (POST /upload,
    // GET /download|list|exists/{path}, POST /execute on port 8888),
    // reached through the sandbox-router unless Connectivity selects a
    // direct pod dial. Default.
    RuntimeLegacyPython Runtime = "legacy-python"
    // RuntimeSandboxd is the sandboxd hybrid API defined by KEP-539.2:
    // REST filesystem (/v1/files/...) on port 8080 plus gRPC
    // ProcessService on port 9090. The SDK reaches the sandbox pod directly
    // or over a port-forward (default), see Connectivity.
    RuntimeSandboxd Runtime = "sandboxd"
)

type Sandbox

Sandbox manages the lifecycle of a single agent-sandbox instance. Operations are split across Commands and Files.

type Sandbox struct {
    // contains filtered or unexported fields
}

func New

func New(_ context.Context, opts Options) (*Sandbox, error)

New creates a new Sandbox with the given options. Call Open() to create a sandbox and establish connectivity.

func (*Sandbox) Annotations

func (s *Sandbox) Annotations() map[string]string

func (*Sandbox) ClaimName

func (s *Sandbox) ClaimName() string

func (*Sandbox) Close

func (s *Sandbox) Close(ctx context.Context) error

Close deletes the SandboxClaim and cleans up resources.

func (*Sandbox) Commands

func (s *Sandbox) Commands() *Commands

Commands returns the command execution sub-object.

func (*Sandbox) Delete

func (s *Sandbox) Delete(ctx context.Context, path string, recursive bool, opts ...CallOption) error

Delete removes a file or directory (sandboxd runtime only; the legacy python-runtime returns ErrUnsupportedByRuntime). Not part of the Handle interface to avoid breaking existing implementers.

func (*Sandbox) Disconnect

func (s *Sandbox) Disconnect(ctx context.Context) error

Disconnect closes the transport connection without deleting the SandboxClaim. The sandbox stays alive on the server. Call Open() to reconnect. Disconnect is safe to call concurrently with Open; an in-progress Open is cancelled before the transport is torn down.

func (*Sandbox) Exists

func (s *Sandbox) Exists(ctx context.Context, path string, opts ...CallOption) (bool, error)

func (*Sandbox) Files

func (s *Sandbox) Files() *Files

Files returns the file operations sub-object.

func (*Sandbox) Health

func (s *Sandbox) Health(ctx context.Context, opts ...CallOption) (*Health, error)

Health returns sandboxd’s report from GET /v1/health. It returns an HTTPError while sandboxd is shutting down, and ErrUnsupportedByRuntime on the legacy python-runtime. It does not retry unless WithMaxAttempts is set. Not part of the Handle interface to avoid breaking existing implementers.

func (*Sandbox) IsReady

func (s *Sandbox) IsReady() bool

IsReady returns true if the sandbox is ready for communication.

func (*Sandbox) List

func (s *Sandbox) List(ctx context.Context, path string, opts ...CallOption) ([]FileEntry, error)

func (*Sandbox) Metadata

func (s *Sandbox) Metadata(ctx context.Context, opts ...CallOption) (*Metadata, error)

Metadata returns the workload-scoped configuration sandboxd serves from GET /v1/metadata (sandboxd runtime only; the legacy python-runtime returns ErrUnsupportedByRuntime). It does not retry unless WithMaxAttempts is set. Not part of the Handle interface to avoid breaking existing implementers.

func (*Sandbox) Open

func (s *Sandbox) Open(ctx context.Context) (retErr error)

Open creates a SandboxClaim and waits for the sandbox to become ready, then discovers the API URL based on the configured connection mode. On failure after claim creation, a claim with a generated name is automatically deleted; if deletion also fails, call Close() to retry. A claim named by ClaimName is caller-owned and is left in place.

func (*Sandbox) PodIP

func (s *Sandbox) PodIP() string

func (*Sandbox) PodName

func (s *Sandbox) PodName() string

func (*Sandbox) Read

func (s *Sandbox) Read(ctx context.Context, path string, opts ...CallOption) ([]byte, error)

func (*Sandbox) ReadTo

func (s *Sandbox) ReadTo(ctx context.Context, path string, destination io.Writer, opts ...CallOption) (int64, error)

ReadTo streams a file into a caller-owned io.Writer without buffering the complete response. The destination is never closed.

func (*Sandbox) Run

func (s *Sandbox) Run(ctx context.Context, command string, opts ...CallOption) (*ExecutionResult, error)

func (*Sandbox) SandboxName

func (s *Sandbox) SandboxName() string

func (*Sandbox) ServiceFQDN

func (s *Sandbox) ServiceFQDN() string

ServiceFQDN returns the in-cluster DNS name of the Sandbox’s headless Service, or "" when it has none (spec.service unset or false). Not part of the Info interface, which is frozen for backward compatibility.

func (*Sandbox) Write

func (s *Sandbox) Write(ctx context.Context, path string, content []byte, opts ...CallOption) error

func (*Sandbox) WriteReader

func (s *Sandbox) WriteReader(ctx context.Context, path string, content io.Reader, opts ...CallOption) error

WriteReader streams content from an io.Reader without buffering the entire payload. Streaming uploads use a single request attempt because a generic reader cannot be replayed safely. Passing WithMaxAttempts with a value greater than 1 returns an error; it is not silently reduced to one attempt.

Generated by gomarkdoc

Last modified July 17, 2026: add go and python docs (#780) (e255c39)