SesameSesame

Docker

Run agent tasks in isolated Docker containers

The Docker sandbox provider runs each agent task in an isolated Docker container, providing better security and consistent environments.

Overview

FeatureValue
IsolationContainer-level
SetupDocker required
PerformanceFast with sandbox image
Use caseMulti-user, untrusted code

Requirements

  • Docker installed and running
  • Docker daemon accessible to the Sesame process
  • Sufficient disk space for container images (~3GB for the sandbox image)

Configuration

# Enable Docker provider
SANDBOX_PROVIDER=docker

# Optional: customize settings
TASK_DIR_BASE=/tmp/sesame
DOCKER_SANDBOX_IMAGE=ghcr.io/jakejarvis/sesame-sandbox:latest

Official Sandbox Image

Sesame provides an official sandbox image pre-loaded with everything needed for fast task execution:

# Pull from GitHub Container Registry (recommended)
docker pull ghcr.io/jakejarvis/sesame-sandbox:latest

# Or from Docker Hub
docker pull jakejarvis/sesame-sandbox:latest

What's Included

The sandbox image comes with:

Runtimes (via mise):

RuntimeVersionsDefault
Node.js20, 22, 2424 (LTS)
Python3.12, 3.13, 3.143.14
Golatestlatest
Rustlatestlatest
Rubylatestlatest
Bunlatestlatest

AI Agent CLIs:

AgentCLIPre-installed
Claude CodeclaudeYes
CodexcodexYes
CopilotcopilotYes
GeminigeminiYes
OpenCodeopencodeYes

Dev Tools:

  • git, git-lfs
  • gh (GitHub CLI)
  • curl, wget, jq
  • Build essentials (gcc, make, etc.)

Benefits

Without Sandbox ImageWith Sandbox Image
Downloads mise each taskmise pre-installed
Downloads runtimes on demandCommon runtimes pre-cached
Installs agent CLI per taskAgent CLIs ready to use
Slower task startupFast task startup

Image Tags

TagDescription
latestMost recent stable build
YYYYMMDDWeekly builds (e.g., 20260203)
X.Y.ZSemantic version releases

The image is automatically rebuilt weekly to pick up runtime updates.

How It Works

  1. Container Creation: Each task gets its own container

    docker run -d \
      --name sesame-sandbox-{taskId} \
      -v /tmp/sesame/{taskId}/project:/workspace \
      -w /workspace \
      -p {hostPort}:3000 \
      ghcr.io/jakejarvis/sesame-sandbox:latest \
      tail -f /dev/null
  2. Mise Bootstrap: Links to pre-installed mise and shims

    # With sandbox image: instant (symlinks to /opt/mise)
    # With custom image: downloads mise binary
  3. Runtime Setup: Installs any additional versions needed

    # Reads .nvmrc, .python-version, .tool-versions, etc.
    mise install  # Fast if version is pre-cached
    mise prepare  # Installs project dependencies
  4. Agent Ready: With the sandbox image, agents are pre-installed

    # No installation needed - claude, codex, copilot, gemini, opencode ready
  5. Volume Mounting: The project directory is mounted into the container at /workspace

  6. Command Execution: Commands run via docker exec

    docker exec sesame-sandbox-{taskId} npm install
  7. Port Mapping: Container port 3000 is mapped to a random available host port

  8. Cleanup: Container is stopped and removed when the task completes

Agent Availability

With the official sandbox image, all agent CLIs are pre-installed and ready to use immediately:

AgentCLIStatus
Claude CodeclaudePre-installed
CodexcodexPre-installed
CopilotcopilotPre-installed
GeminigeminiPre-installed
OpenCodeopencodePre-installed

If you use a custom base image, Sesame will automatically install the selected agent's CLI at runtime:

AgentInstallation Command
Claude Codenpm install -g @anthropic-ai/claude-code
Codexnpm install -g @openai/codex
Copilotnpm install -g @github/copilot
Gemininpm install -g @google/gemini-cli
OpenCodenpm install -g opencode-ai

Using the official sandbox image is recommended for production deployments to minimize task startup time.

Advantages

  • Isolation: Each task runs in its own container with no access to host filesystem (except mounted volume)
  • Consistent environment: Same base image regardless of host configuration
  • Security: Better protection against malicious code
  • Reproducibility: Tasks run in identical environments

Limitations

  • Startup overhead: Container creation adds 2-5 seconds to task startup
  • Resource usage: Each container consumes memory and disk space
  • Docker dependency: Requires Docker to be installed and running
  • Networking complexity: Port mapping required for preview URLs

Environment Variables

VariableDefaultDescription
SANDBOX_PROVIDERlocalSet to docker to enable
TASK_DIR_BASE/tmp/sesameBase directory for mounted volumes
DOCKER_SANDBOX_IMAGEghcr.io/jakejarvis/sesame-sandbox:latestBase Docker image
DOCKER_HOST(system default)Docker daemon socket (e.g., tcp://proxy:2375)
DOCKER_TLS_VERIFY(unset)Enable TLS verification for remote Docker
DOCKER_CERT_PATH(unset)Path to TLS certificates for remote Docker

Custom Images

Extending the Official Image

For most customizations, extend the official sandbox image:

# Dockerfile.custom
FROM ghcr.io/jakejarvis/sesame-sandbox:latest

# Add more Node.js versions
RUN mise install node@16

# Add Java
RUN mise install java@21 && mise reshim

# Add custom npm packages
RUN npm install -g your-custom-tool

# Add system packages
RUN apt-get update && apt-get install -y \
    your-package \
    && rm -rf /var/lib/apt/lists/*

Build and use:

docker build -t my-sandbox -f Dockerfile.custom .
DOCKER_SANDBOX_IMAGE=my-sandbox

Building from Scratch

If you need a minimal image without pre-installed runtimes:

# Dockerfile.minimal
FROM debian:trixie-slim

# Install essentials
RUN apt-get update && apt-get install -y \
    git curl ca-certificates build-essential \
    && rm -rf /var/lib/apt/lists/*

# Install mise
ENV MISE_VERSION=2026.2.2
RUN curl -fsSL "https://github.com/jdx/mise/releases/download/v${MISE_VERSION}/mise-v${MISE_VERSION}-linux-x64.tar.gz" \
    | tar -xz -C /usr/local --strip-components=1

# Install just what you need
RUN mise install node@24 && mise use --global node@24 && mise reshim

WORKDIR /workspace

Custom images without pre-installed agents will have slower task startup as agents must be installed at runtime.

Networking

The Docker provider uses bridge networking with explicit port mapping:

  • Container port 3000 is mapped to a random available host port (10000-65000)
  • Preview URLs use the mapped host port: http://localhost:{hostPort}
  • Additional ports can be exposed by customizing the provider

Resource Limits

The default configuration doesn't set resource limits. Consider extending the provider to add:

# Example limits (not yet configurable via env vars)
--memory="2g"
--cpus="2"

Troubleshooting

"Docker is required but not available"

This error means Docker isn't running or accessible:

  1. Check Docker is installed: docker --version
  2. Check Docker daemon is running: docker ps
  3. On Linux, ensure the user is in the docker group: sudo usermod -aG docker $USER

Container Already Exists

If a container with the same name exists, it will be automatically removed before creating a new one. If you see issues:

# List Sesame containers
docker ps -a | grep sesame-sandbox

# Remove stuck containers
docker rm -f $(docker ps -a -q --filter "name=sesame-sandbox")

Port Conflicts

The provider automatically finds available ports. If you consistently see port issues:

  1. Check for orphaned containers using ports
  2. Ensure the port range (10000-65000) isn't blocked by firewall
  3. Check other services aren't consuming all available ports

Volume Permission Issues

If you see permission errors accessing mounted files:

  1. Check host directory permissions: ls -la /tmp/sesame/
  2. The container runs as root by default, which should have access
  3. On SELinux systems, you may need :z or :Z volume options

Cleanup Issues

Containers should be removed automatically. If orphaned containers accumulate:

# Remove all Sesame sandbox containers
docker rm -f $(docker ps -a -q --filter "name=sesame-sandbox")

# Remove unused images
docker image prune

Host Docker Socket

When running Sesame in Docker, you can use the host's Docker daemon instead of Docker-in-Docker (DinD). This is the recommended approach.

Why Use the Host Docker Socket?

Docker-in-Docker (DinD)Host Docker Socket
Requires privileged modeNo privileged mode needed
Nested containers add latencyDirect access, better performance
Storage driver complexityUses host's storage driver
Caching doesn't persist across restartsImage cache shared with host
Complete isolation from hostSandbox containers visible on host

Configuration Options

Option 1: Direct Socket Mount

The simplest approach - mount the Docker socket directly:

docker-compose.yml
services:
  sesame:
    environment:
      - SANDBOX_PROVIDER=docker
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
      # IMPORTANT: Use bind mount for sandboxes so host Docker can access them
      - ./sandboxes:/app/sandboxes

Direct socket access grants full Docker API control. Any process in the container can create privileged containers, mount host filesystems, or access other containers. Only use this if you trust all code running in Sesame.

Use docker-socket-proxy for fine-grained access control:

docker-compose.yml
services:
  sesame:
    environment:
      - SANDBOX_PROVIDER=docker
      - DOCKER_HOST=tcp://docker-socket-proxy:2375
    volumes:
      - ./sandboxes:/app/sandboxes
    depends_on:
      - docker-socket-proxy

  docker-socket-proxy:
    image: tecnativa/docker-socket-proxy:latest
    environment:
      # Only enable required endpoints
      - CONTAINERS=1
      - IMAGES=1
      - EXEC=1
      - VERSION=1
      - POST=1
      # Keep everything else disabled
      - AUTH=0
      - BUILD=0
      - NETWORKS=0
      - VOLUMES=0
      - SWARM=0
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock:ro

A complete example is available in docker-compose.socket-proxy.yml.

Option 3: Remote Docker Host

Connect to a remote Docker daemon over TCP:

DOCKER_HOST=tcp://docker-host.example.com:2375
# Or with TLS:
DOCKER_HOST=tcp://docker-host.example.com:2376
DOCKER_TLS_VERIFY=1
DOCKER_CERT_PATH=/path/to/certs

Volume Mount Considerations

When using the host Docker socket, sandbox containers are created on the host, not inside the Sesame container. This means:

  1. Sandbox directories must be accessible from both Sesame and the host
  2. Use bind mounts instead of named volumes for the sandboxes directory
  3. Paths must match between what Sesame sees and what the host sees
docker-compose.yml
services:
  sesame:
    environment:
      # Tell Sesame where sandboxes are (from its perspective)
      - TASK_DIR_BASE=/app/sandboxes
    volumes:
      # Bind mount so the path is consistent
      - ./sandboxes:/app/sandboxes

If Sesame runs with TASK_DIR_BASE=/app/sandboxes and you use a named volume, the host Docker daemon won't be able to find the project files to mount into sandbox containers.

Security Considerations

While Docker provides better isolation than the local provider:

  • Volume mounts expose the project directory to the container
  • Network access is not restricted by default
  • Root in container - processes run as root inside the container

Socket-specific risks:

  • Container escape: With socket access, a compromised process could create a privileged container and access the host
  • Data exfiltration: Access to other containers' filesystems and networks
  • Resource exhaustion: Ability to spawn unlimited containers

Mitigations:

  1. Use docker-socket-proxy to limit API access
  2. Run Sesame with --read-only where possible
  3. Use Docker user namespaces
  4. Consider network isolation with custom Docker networks
  5. Set resource limits to prevent DoS
  6. Regularly audit running containers

For maximum security:

  1. Use read-only volume mounts where possible
  2. Consider network isolation with custom Docker networks
  3. Run containers as non-root users
  4. Set resource limits to prevent DoS

On this page