Deep Agents
AgentContextOrchestratorRetrievalText2SQLToolbox

Docker Sandbox

Execute real binaries in isolated Docker containers with three creation strategies

The Docker sandbox provides isolated code execution by running commands inside Docker containers. It supports three strategies for creating sandboxes, each suited to different use cases.

Strategies

Starts a vanilla image and installs packages/binaries at container startup. Best for quick experiments and when dependencies change frequently.

import { createDockerSandbox } from '@deepagents/context';

const sandbox = await createDockerSandbox({
  image: 'alpine:latest',
  packages: ['curl', 'jq', 'python3'],
  mounts: [
    {
      hostPath: process.cwd(),
      containerPath: '/workspace',
      readOnly: true,
    },
  ],
  resources: { memory: '512m', cpus: 1 },
});

try {
  await sandbox.executeCommand('python3 --version');
} finally {
  await sandbox.dispose();
}

Default image: alpine:latest

Package manager detection: Alpine images use apk, Debian-based images (debian, ubuntu, node, python) use apt-get.

Builds a custom image from a Dockerfile. Best for reproducible environments with many dependencies. Uses content-based hashing for automatic image caching — same Dockerfile content means same image tag, so Docker skips the rebuild.

import { createDockerSandbox } from '@deepagents/context';

// Inline Dockerfile
const sandbox = await createDockerSandbox({
  dockerfile: `
    FROM python:3.11-slim
    RUN pip install pandas numpy matplotlib
  `,
  context: '.',
  mounts: [
    {
      hostPath: process.cwd(),
      containerPath: '/workspace',
    },
  ],
});

// Or reference a Dockerfile path
const sandbox2 = await createDockerSandbox({
  dockerfile: './Dockerfile.sandbox',
  context: '.',
});

Caching: The image tag is sandbox-<sha256-first-12-chars>. Same Dockerfile content produces the same tag, so subsequent calls skip the build entirely.

Detection: Inline vs path is determined by whether the string contains \n.

Manages multi-container environments using Docker Compose. Best for applications that need databases, APIs, or other services alongside the sandbox.

import { createDockerSandbox } from '@deepagents/context';

const sandbox = await createDockerSandbox({
  compose: './docker-compose.yml',
  service: 'app',
});

try {
  // Commands run in the 'app' service
  await sandbox.executeCommand('node --version');

  // Can reach other services by name
  await sandbox.executeCommand('curl http://db:5432');
} finally {
  // Stops ALL services
  await sandbox.dispose();
}

Volumes: Must be defined in the compose file itself, not via mounts.

Lifecycle: dispose() runs docker compose down, stopping all services.

Mounts

Mount host directories into the container. Read-only by default for security.

const sandbox = await createDockerSandbox({
  mounts: [
    {
      hostPath: '/absolute/path/on/host',
      containerPath: '/workspace',
      readOnly: true,   // default
    },
    {
      hostPath: process.cwd(),
      containerPath: '/project',
      readOnly: false,  // allow writes
    },
  ],
});

Mount paths are validated at creation time — a MountPathError is thrown if the hostPath doesn't exist on the host.

Resource Limits

const sandbox = await createDockerSandbox({
  resources: {
    memory: '512m',  // default: '1g'
    cpus: 1,         // default: 2
  },
});

Installing Binaries from URLs

For tools not available in package managers, install pre-built binaries directly from URLs. Architecture is auto-detected via uname -m.

const sandbox = await createDockerSandbox({
  packages: ['curl'],  // curl required for downloads
  binaries: [
    {
      name: 'presenterm',
      url: {
        x86_64: 'https://github.com/.../presenterm-x86_64-linux-musl.tar.gz',
        aarch64: 'https://github.com/.../presenterm-aarch64-linux-musl.tar.gz',
      },
      binaryPath: 'presenterm',  // filename inside the archive
    },
  ],
});

Supported formats:

  • .tar.gz / .tgz — extracted, binary found by name, moved to /usr/local/bin/
  • Raw binary URL — downloaded directly to /usr/local/bin/

File I/O

Read and write files inside the container using base64 encoding for binary safety:

// Write files
await sandbox.writeFiles([
  { path: '/tmp/data.json', content: '{"key": "value"}' },
  { path: '/tmp/script.py', content: 'print("hello")' },
]);

// Read files
const content = await sandbox.readFile('/tmp/data.json');

Parent directories are created automatically during writes.

Container Lifecycle

Manual Disposal

Always wrap sandbox usage in try/finally:

const sandbox = await createDockerSandbox({ packages: ['curl'] });
try {
  await sandbox.executeCommand('curl --version');
} finally {
  await sandbox.dispose();
}

Auto-Disposal with useSandbox

import { useSandbox } from '@deepagents/context';

const version = await useSandbox(
  { packages: ['curl'] },
  async (sandbox) => {
    const result = await sandbox.executeCommand('curl --version');
    return result.stdout.split('\n')[0];
  },
);

Containers are created with --rm, so they're removed automatically when stopped. dispose() calls docker stop (or docker compose down for Compose).

Error Handling

All errors extend DockerSandboxError:

ErrorWhen
DockerNotAvailableErrorDocker daemon is not running
ContainerCreationErrorContainer fails to start
PackageInstallErrorPackage installation fails (includes package names, manager type, stderr)
BinaryInstallErrorBinary download/install fails (includes binary name, URL, reason)
MountPathErrorHost path doesn't exist (includes both host and container paths)
DockerfileBuildErrorDockerfile build fails (includes stderr)
ComposeStartErrorDocker Compose startup fails (includes compose file path, stderr)
import {
  createDockerSandbox,
  DockerNotAvailableError,
  PackageInstallError,
} from '@deepagents/context';

try {
  const sandbox = await createDockerSandbox({
    packages: ['nonexistent-package'],
  });
} catch (error) {
  if (error instanceof DockerNotAvailableError) {
    console.error('Start Docker first');
  } else if (error instanceof PackageInstallError) {
    console.error(`Failed packages: ${error.packages.join(', ')}`);
    console.error(`Package manager: ${error.packageManager}`);
  }
}

Next Steps