sandbox

package
v0.1.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 16, 2026 License: Apache-2.0 Imports: 4 Imported by: 0

Documentation

Overview

Package sandbox is the "hands" boundary: a disposable per-session container where the built-in toolset executes. Cattle, not pets — a sandbox dying is one tool-call error, never a lost session, because all durable state lives in the event log.

The surface is deliberately small. Higher-level tools (glob, grep, edit) are pure functions of Exec and the file primitives below, so they live once in the toolset layer instead of being re-implemented by every backend.

Divergence from the plan: there is no Attach. Provision is idempotent per session — it returns the session's existing sandbox when one is running — which is the only thing an executor ever needed Attach for, and it saves persisting a sandbox id nothing else would read.

Index

Constants

View Source
const DefaultWorkdir = "/workspace"

DefaultWorkdir is where a sandbox runs commands and where the toolset's relative paths resolve when Spec.Workdir is empty. It is one constant so those two can never disagree.

View Source
const MaxFileBytes = 4 << 20

MaxFileBytes caps ReadFile. The sandbox's filesystem is agent-controlled, so a read is an untrusted-length allocation: refuse rather than truncate, since a silently half-read file is worse than a failed tool call.

View Source
const MaxOutputBytes = 1 << 20

MaxOutputBytes caps what Exec keeps from each of stdout and stderr. It is a memory guard on the executor, not the tool-result limit: a command that writes a gigabyte must not be able to kill the process that ran it. The command still runs to completion — the excess is drained and discarded.

Variables

View Source
var (
	// ErrNotFound reports that the sandbox is gone (destroyed, or reaped by
	// the host). The caller's tool call fails; the session does not.
	ErrNotFound = errors.New("sandbox: no such sandbox")
	// ErrFileNotExist reports a read of a path that does not exist.
	ErrFileNotExist = errors.New("sandbox: no such file")
	// ErrIsDirectory reports a file read of a directory.
	ErrIsDirectory = errors.New("sandbox: path is a directory")
	// ErrNotRegularFile reports a file read of a device, FIFO, socket, or other
	// non-regular file. Like ErrIsDirectory it describes the path the caller
	// asked for, not the sandbox failing, so a tool surfaces it to the model
	// rather than to the executor.
	ErrNotRegularFile = errors.New("sandbox: not a regular file")
	// ErrFileTooLarge reports a read of a file above MaxFileBytes.
	ErrFileTooLarge = errors.New("sandbox: file too large")
)

Functions

This section is empty.

Types

type ExecRequest

type ExecRequest struct {
	Command string
	Timeout time.Duration
}

ExecRequest runs Command through /bin/bash -c inside the sandbox's workdir. A zero Timeout means "no limit", and then only the context bounds the call.

type ExecResult

type ExecResult struct {
	Stdout    string
	Stderr    string
	ExitCode  int
	TimedOut  bool
	Truncated bool
}

ExecResult is a finished command. TimedOut means the command itself outlived its deadline: the sandbox stopped it, or stopped waiting for it, or caught it still running past the deadline and exiting later on its own terms. TimedOut is the authoritative field — ExitCode may be the kill's code, or the code a command that dodged the kill chose for itself — and the output is whatever arrived. Truncated means output exceeded MaxOutputBytes and the tail was discarded.

A backend must decide TimedOut where the sandboxed command cannot reach the decision. Anything inside the sandbox is the agent's to tamper with, so a deadline enforced only in there is a deadline the command can lift.

The command's own life is what a deadline is measured against, not the life of what it leaves behind: a process the command backgrounds inherits its output stream and can hold it open long after the command has exited.

type Provider

type Provider interface {
	// Provision returns the session's sandbox, creating it only if none is
	// running. Concurrent executors provisioning the same session converge on
	// one sandbox rather than racing to create two.
	Provision(ctx context.Context, spec Spec) (Sandbox, error)
}

Provider makes sandboxes. Every backend passes the same contract suite (internal/sandbox/sandboxtest).

type Sandbox

type Sandbox interface {
	// ID identifies the sandbox to the backend (a container id, a pod name).
	ID() string
	Exec(ctx context.Context, req ExecRequest) (ExecResult, error)
	// ReadFile returns a file's bytes verbatim, binary included.
	ReadFile(ctx context.Context, path string) ([]byte, error)
	// WriteFile writes data, creating parent directories and overwriting any
	// existing file.
	WriteFile(ctx context.Context, path string, data []byte) error
	// Destroy removes the sandbox. It is idempotent: destroying an already
	// destroyed sandbox is not an error.
	Destroy(ctx context.Context) error
}

Sandbox is one session's execution environment.

type Spec

type Spec struct {
	SessionID  domain.ID
	Image      string
	Workdir    string
	Networking domain.Networking
}

Spec is what a session's sandbox is made of. Image is a platform deployment choice (the wire's environment config has no image field); Networking comes from the environment.

Directories

Path Synopsis
Package backend selects a sandbox provider by name, so the executor and the BYOC worker construct Docker or Kubernetes "hands" from the same config point instead of hard-coding one.
Package backend selects a sandbox provider by name, so the executor and the BYOC worker construct Docker or Kubernetes "hands" from the same config point instead of hard-coding one.
Package docker is the v1 sandbox backend: one disposable container per session, driven over the Docker Engine API.
Package docker is the v1 sandbox backend: one disposable container per session, driven over the Docker Engine API.
Package k8s is the Kubernetes sandbox backend: one disposable Pod per session, driven over the Kubernetes API.
Package k8s is the Kubernetes sandbox backend: one disposable Pod per session, driven over the Kubernetes API.
Package sandboxtest is the contract suite every sandbox.Provider must pass (CLAUDE.md: backend variability lives behind an interface with one shared suite).
Package sandboxtest is the contract suite every sandbox.Provider must pass (CLAUDE.md: backend variability lives behind an interface with one shared suite).
Package shell runs the built-in bash tool as a persistent per-session shell, on top of the sandbox's stateless Exec + file primitives — no new backend surface.
Package shell runs the built-in bash tool as a persistent per-session shell, on top of the sandbox's stateless Exec + file primitives — no new backend surface.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL