Skip to main content

Custom Sandbox Images

Bring your own container image to run agent tasks in a pre-built environment.

Why Use a Custom Image?

By default, the runbook step builds a fresh container from a Dockerfile on every run. This works well for simple tasks, but has drawbacks:

  • Slow cold starts -- installing packages on every run wastes time
  • Reproducibility -- builds may break if upstream packages change
  • Complex toolchains -- some environments need system libraries, compilers, or tools that are tedious to install via apt_packages

A custom image solves all three. You build it once, push it to a container registry, and reference it by tag. Every run gets the exact same environment in seconds.

How It Works

Set the image parameter to a full container image reference. Jetty pulls the image directly from the registry and launches the sandbox -- no Dockerfile is generated.

{
"activity": "runbook",
"instruction": "Run the test suite and write results to /app/results/report.md",
"agent": "claude-code",
"image": "ghcr.io/myorg/my-test-env:v1.2"
}

The agent (Claude Code, Codex, or Gemini CLI) is installed on top of your image at runtime. Your image provides the base environment; Jetty handles the agent.

Pre-Built Snapshots

Before building a custom image, check if a pre-built Jetty snapshot fits your needs:

SnapshotIncludesBest For
python312-uvPython 3.12, uv package manager, network accessMost tasks: data processing, API calls, code generation, file manipulation
prism-playwrightEverything in python312-uv + Playwright + ChromiumBrowser automation: screenshots, web scraping, OAuth flows, HTML rendering, UI testing

Use a snapshot by setting the snapshot parameter:

{
"activity": "runbook",
"instruction": "...",
"agent": "claude-code",
"snapshot": "prism-playwright"
}

Or in runbook frontmatter:

---
snapshot: prism-playwright
---

Snapshots load faster than custom images and are maintained by Jetty. Only build a custom image when you need packages or tools not available in either snapshot.

Supported Registries

Any public container registry works:

RegistryExample
Docker Hubdocker.io/myuser/my-image:latest or myuser/my-image:latest
GitHub Container Registryghcr.io/myorg/my-image:v1
Google Artifact Registryus-docker.pkg.dev/my-project/repo/image:tag
Amazon ECR Publicpublic.ecr.aws/myorg/image:tag

Images must be publicly accessible. Private registry authentication is not currently supported.

Building Your Image

Image Requirements

  • Linux/amd64 architecture
  • bash must be available (most base images include it)
  • Network access during build is fine -- the sandbox itself can optionally disable network at runtime via network_enabled: false
  • Write output files to /app/results/ for automatic artifact persistence

Example: Data Science Environment

FROM python:3.13-slim-bookworm

RUN apt-get update && apt-get install -y \
git curl build-essential libpq-dev \
&& rm -rf /var/lib/apt/lists/*

RUN pip install --no-cache-dir \
pandas numpy scipy scikit-learn \
matplotlib seaborn plotly \
jupyter nbformat \
sqlalchemy psycopg2-binary

WORKDIR /app

Build and push:

docker build -t ghcr.io/myorg/data-science:v1 .
docker push ghcr.io/myorg/data-science:v1

Then use it in a workflow:

{
"activity": "runbook",
"instruction": "Analyze the uploaded CSV. Produce charts and a summary report in /app/results/.",
"agent": "claude-code",
"image": "ghcr.io/myorg/data-science:v1",
"files": ["uploads/dataset.csv"]
}

Example: Browser Automation

FROM mcr.microsoft.com/playwright:v1.52.0-noble

RUN npm install -g playwright @playwright/test
RUN npx playwright install --with-deps chromium

WORKDIR /app
{
"activity": "runbook",
"instruction": "Navigate to https://example.com, take screenshots of each page, and write a visual QA report to /app/results/.",
"agent": "claude-code",
"image": "ghcr.io/myorg/playwright-env:v1",
"timeout_sec": 1200
}

Chat Completions API

Use the image field inside the jetty block:

curl -X POST "https://flows-api.jetty.io/v1/chat/completions" \
-H "Authorization: Bearer $JETTY_API_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"model": "claude-sonnet-4-6",
"messages": [
{
"role": "system",
"content": "You are a data scientist. Analyze the uploaded dataset and produce a report."
},
{
"role": "user",
"content": "Run the analysis"
}
],
"stream": true,
"jetty": {
"runbook": true,
"collection": "my-org",
"task": "analysis",
"agent": "claude-code",
"image": "ghcr.io/myorg/data-science:v1",
"file_paths": ["uploads/dataset.csv"]
}
}'

Choosing the Right Sandbox Source

OptionParameterBest forTrade-off
Dockerfile buildbase_image + pip_packages + apt_packagesSimple environments, quick iterationSlower startup (builds every run)
Custom imageimageComplex environments, reproducible buildsYou maintain the image
Daytona snapshotsnapshotJetty-managed pre-built environmentsMust be pre-created on the platform

Priority when multiple are set: snapshot > image > Dockerfile build.

Tips

  • Tag your images with specific versions (v1.2, not latest) for reproducibility
  • Keep images small -- use slim base images and multi-stage builds to reduce pull time
  • Pre-install large packages (ML frameworks, browser engines) in the image to avoid per-run installation
  • Test locally before pushing: docker run -it your-image bash to verify the environment works
  • The pip_packages and apt_packages parameters are ignored when image is set -- bake everything into your image instead