Docs

Packages

Sandbox

Docker-backed sandbox sessions and agent tool helpers from @anvia/sandbox.

Import from @anvia/sandbox.

Image builder CLI

pnpm dlx @anvia/sandbox create-image [options]

The CLI requires Node.js 20.12 or newer. With a terminal it prompts for runtimes and features. In a non-interactive environment, provide --name and at least one repeatable --runtime or --feature flag.

The wizard always shows curated checkbox lists for common apt tools, npm libraries, and Python libraries. Use the package flags below for entries that are not in those lists. Python packages are written to pyproject.toml and installed with uv sync.

Option Behavior
--runtime node|bun|python Add a runtime; repeatable.
--feature artifacts|playwright Add a curated capability; repeatable.
--apt, --npm, --uv Add an apt, npm, or Python package; repeatable. Unpinned npm and Python packages produce a warning.
--tag <tag> Set the local image tag. Defaults to anvia-sandbox-<name>:latest.
--output <path> Set the generated context path. Defaults to .anvia/sandbox-images/<name>.
--no-build Write the context without running docker build.
--dry-run Print the generated files without writing or building.
--force Regenerate files in a context previously created by this CLI.

Runtime versions can be overridden with --node-version, --pnpm-version, --bun-version, --python-version, --uv-version, and --playwright-version. --docker-path selects a non-default Docker executable.

Generated contexts contain a Dockerfile, a restrictive .dockerignore, and anvia-sandbox.json. The manifest records selected capabilities, versions, packages, and generated files. Regeneration never recursively deletes the directory or overwrites a directory without a recognized manifest.

DockerSandbox

class DockerSandbox implements Sandbox {
  readonly provider: "docker";
  constructor(options?: DockerSandboxOptions);
  static node(options?: DockerSandboxOptions): DockerSandbox;
  static python(options?: DockerSandboxOptions): DockerSandbox;
  static deno(options?: DockerSandboxOptions): DockerSandbox;
  createSession(options?: DockerSandboxCreateSessionOptions): Promise<DockerSandboxSession>;
}

Purpose: create ephemeral Docker-backed workspace sessions for running untrusted or model-generated code outside the host process.

Return behavior: createSession(...) creates one container and one Docker volume mounted at the session workdir. Call destroy() on the returned SandboxSession to remove both resources.

Notable errors: throws SandboxDockerUnavailableError when the Docker CLI is missing, SandboxDockerCommandError when Docker setup fails, and SandboxPathError for unsafe manifest paths.

Sandbox Interfaces

interface Sandbox {
  readonly provider: string;
  createSession(options?: SandboxCreateSessionOptions): Promise<SandboxSession>;
}

interface SandboxSession {
  readonly id: string;
  readonly provider: string;
  readonly workdir: string;
  exec(options: SandboxExecOptions): Promise<SandboxExecResult>;
  execStream(options: SandboxExecOptions): AsyncIterable<SandboxExecStreamEvent>;
  readFile(path: string): Promise<Uint8Array>;
  readTextFile(path: string): Promise<string>;
  writeFile(path: string, data: string | Uint8Array): Promise<void>;
  writeTextFile(path: string, content: string): Promise<void>;
  listFiles(path?: string): Promise<SandboxFileEntry[]>;
  destroy(): Promise<void>;
}

Purpose: provider-neutral contracts for sandbox clients and live workspace sessions.

Return behavior: file paths are sandbox-relative; absolute paths and traversal outside the workspace are rejected.

DockerSandboxSession adds published-port and managed-process capabilities without making them required for other SandboxSession providers.

Session Options

type SandboxCreateSessionOptions = {
  id?: string;
  workspace?: SandboxWorkspaceOptions;
  manifest?: SandboxManifest;
  metadata?: Record<string, string>;
};

type DockerSandboxCreateSessionOptions = SandboxCreateSessionOptions & {
  ports?: readonly number[];
};

type SandboxWorkspaceOptions =
  | { mode?: "ephemeral" }
  | {
      mode: "persistent";
      id: string;
      destroyOnSessionDestroy?: boolean;
    };

type SandboxManifest = {
  files?: Record<string, string | Uint8Array>;
  directories?: string[];
  env?: Record<string, string>;
};

type SandboxLimits = {
  timeoutMs?: number;
  maxOutputBytes?: number;
  maxFileBytes?: number;
  memoryMb?: number;
  cpus?: number;
  pidsLimit?: number;
  maxProcesses?: number;
};

type SandboxLifecycleOptions = {
  ttlMs?: number;
  idleTimeoutMs?: number;
  autoDestroy?: boolean;
};

Purpose: seed files, directories, environment, metadata, workspace mode, lifecycle cleanup, and runtime limits for a sandbox session.

ports contains unique TCP ports from 1 through 65535. Published ports require network: true or a bridge-capable custom network. Docker binds them to random ports on host address 127.0.0.1; the application remains responsible for any authenticated public proxy.

Docker Options

type DockerSandboxOptions = {
  image?: string;
  pull?: "missing" | "always" | "never";
  workdir?: string;
  workspace?: SandboxWorkspaceOptions;
  lifecycle?: SandboxLifecycleOptions;
  network?: SandboxNetworkMode | DockerSandboxNetworkOptions;
  user?: string;
  dockerPath?: string;
  labels?: Record<string, string>;
  limits?: SandboxLimits;
  security?: DockerSandboxSecurityOptions;
  hooks?: SandboxHooks;
};

type DockerSandboxSecurityOptions = {
  readonlyRootfs?: boolean;
  noNewPrivileges?: boolean;
  dropCapabilities?: string[];
};

type DockerSandboxNetworkOptions = {
  mode: SandboxNetworkMode;
};

type SandboxNetworkMode = boolean | "none" | "host" | string;

Defaults: image is node:22-bookworm, pull is missing, workdir is /workspace, network access is disabled, noNewPrivileges is enabled, and Docker capabilities are dropped with ["ALL"].

Static presets: DockerSandbox.node(...), DockerSandbox.python(...), and DockerSandbox.deno(...) create sandboxes with language-specific default images.

Execution

type SandboxExecOptions = {
  command: string;
  args?: string[];
  cwd?: string;
  env?: Record<string, string>;
  timeoutMs?: number;
  input?: string | Uint8Array;
  signal?: AbortSignal;
  onStdout?: (chunk: Uint8Array) => void;
  onStderr?: (chunk: Uint8Array) => void;
};

type SandboxExecResult = {
  stdout: string;
  stderr: string;
  exitCode: number;
  durationMs: number;
  timedOut: boolean;
  aborted: boolean;
  stdoutTruncated: boolean;
  stderrTruncated: boolean;
};

type SandboxExecStreamEvent =
  | { type: "stdout"; chunk: Uint8Array; text: string }
  | { type: "stderr"; chunk: Uint8Array; text: string }
  | { type: "exit"; result: SandboxExecResult };

Return behavior: non-zero command exits are returned in SandboxExecResult; infrastructure failures throw. execStream(...) yields stdout and stderr chunks as they arrive, then yields one exit event with the final result.

Files

type SandboxFileType = "file" | "directory" | "symlink" | "other";

type SandboxFileEntry = {
  path: string;
  type: SandboxFileType;
  size?: number;
};

Purpose: typed file-listing results from SandboxSession.listFiles(...).

Published ports and managed processes

interface SandboxPortSession extends SandboxSession {
  readonly publishedPorts: readonly SandboxPublishedPort[];
  waitForPort(
    containerPort: number,
    options?: SandboxWaitForPortOptions,
  ): Promise<SandboxPublishedPort>;
}

interface SandboxProcessSession extends SandboxSession {
  startProcess(options: SandboxProcessStartOptions): Promise<SandboxProcessInfo>;
  listProcesses(): Promise<SandboxProcessInfo[]>;
  readProcessLogs(
    processId: string,
    options?: SandboxProcessLogsOptions,
  ): Promise<SandboxProcessLogs>;
  stopProcess(
    processId: string,
    options?: SandboxProcessStopOptions,
  ): Promise<SandboxProcessInfo>;
}

interface DockerSandboxSession extends SandboxPortSession, SandboxProcessSession {}

type SandboxPublishedPort = {
  containerPort: number;
  host: "127.0.0.1";
  hostPort: number;
  protocol: "tcp";
};

type SandboxProcessStartOptions = {
  command: string;
  args?: string[];
  cwd?: string;
  env?: Record<string, string>;
};

type SandboxProcessStatus = "running" | "exited" | "stopped";

type SandboxProcessInfo = {
  id: string;
  command: string;
  args: string[];
  cwd?: string;
  status: SandboxProcessStatus;
  exitCode?: number;
  startedAt: string;
  endedAt?: string;
};

type SandboxProcessLogs = {
  stdout: string;
  stderr: string;
  stdoutTruncated: boolean;
  stderrTruncated: boolean;
};

type SandboxProcessLogsOptions = { tailBytes?: number };
type SandboxProcessStopOptions = { gracePeriodMs?: number };
type SandboxWaitForPortOptions = {
  timeoutMs?: number;
  intervalMs?: number;
  signal?: AbortSignal;
};

function isSandboxPortSession(session: SandboxSession): session is SandboxPortSession;
function isSandboxProcessSession(session: SandboxSession): session is SandboxProcessSession;

startProcess(...) starts an arbitrary structured command and returns after launch. Output is retained in a bounded tail buffer. maxProcesses caps concurrent processes and retained process records; the oldest completed records are pruned when capacity is needed. waitForPort(...) confirms that the pre-authorized port is listening on all container interfaces; web servers must bind to 0.0.0.0, not container localhost. Idle timeout, TTL, and explicit session destruction still clean up managed processes. Managed commands should remain in the foreground rather than daemonizing, so the session can track their exit status and stop them reliably.

Agent Tools

function createSandboxTools(
  session: SandboxSession,
  options?: SandboxToolsOptions,
): AnyTool[];

type SandboxToolsOptions = {
  allow?: SandboxToolName[];
  include?: SandboxToolName[];
  execTimeoutMs?: number;
  exec?: SandboxExecToolPolicy;
  readFile?: SandboxFileToolPolicy;
  writeFile?: SandboxFileToolPolicy;
  process?: SandboxProcessToolPolicy;
};

type SandboxToolName =
  | "exec_command"
  | "read_file"
  | "write_file"
  | "list_files"
  | "list_ports"
  | "start_process"
  | "list_processes"
  | "read_process_logs"
  | "stop_process"
  | "wait_for_port";

type SandboxExecToolPolicy = {
  allowedCommands?: string[];
  blockedCommands?: string[];
  defaultTimeoutMs?: number;
  maxTimeoutMs?: number;
};

type SandboxFileToolPolicy = {
  maxBytes?: number;
};

type SandboxProcessToolPolicy = {
  maxLogBytes?: number;
  defaultWaitTimeoutMs?: number;
  maxWaitTimeoutMs?: number;
  stopGracePeriodMs?: number;
};

type SandboxToolsFactory = (
  session: SandboxSession,
  options?: SandboxToolsOptions,
) => AnyTool[];

Purpose: expose a live sandbox session as Anvia tools. The default bundle remains exec_command, read_file, write_file, and list_files. Published-port and managed-process tools are opt-in. They use the existing executable allow/block policy plus SandboxProcessToolPolicy limits.

Hooks

type SandboxHooks = {
  onSessionCreate?: (event: SandboxSessionEvent) => void | Promise<void>;
  onExecStart?: (event: SandboxExecEvent) => void | Promise<void>;
  onExecEnd?: (event: SandboxExecEndEvent) => void | Promise<void>;
  onFileWrite?: (event: SandboxFileWriteEvent) => void | Promise<void>;
  onDestroy?: (event: SandboxSessionEvent) => void | Promise<void>;
};

type SandboxSessionEvent = {
  sessionId: string;
  provider: string;
  workdir: string;
};

type SandboxExecEvent = SandboxSessionEvent & {
  command: string;
  args: string[];
  cwd?: string;
};

type SandboxExecEndEvent = SandboxExecEvent & {
  result: SandboxExecResult;
};

type SandboxFileWriteEvent = SandboxSessionEvent & {
  path: string;
  size: number;
};

Purpose: observe session creation, command execution, managed process start/exit, file writes, and cleanup without exposing those details to the model. Managed processes emit onExecStart when launched and onExecEnd when they exit or are stopped.

For workflow guidance, see Sandbox.

Errors

class SandboxError extends Error {}
class SandboxDockerUnavailableError extends SandboxError {}
class SandboxDockerCommandError extends SandboxError {}
class SandboxSessionDestroyedError extends SandboxError {}
class SandboxPathError extends SandboxError {}
class SandboxTimeoutError extends SandboxError {}
class SandboxFileSizeError extends SandboxError {}
class SandboxToolPolicyError extends SandboxError {}
class SandboxPortError extends SandboxError {}
class SandboxProcessError extends SandboxError {}

Purpose: typed failures for Docker setup, path and port validation, managed processes, destroyed sessions, file size limits, tool policy limits, and sandbox operations.