Isorun Docs
Sandboxes

Any OCI Image

Use any Docker Hub / GHCR / private-registry image as a sandbox base. First boot pulls and builds; every subsequent boot is fast.

Pass any OCI image reference to isorun.create({ image }) and the runner pulls it on first use, prepares an optimized cache, and reuses that cache for subsequent boots of the same image. The cache build is one-time per (image, runner) pair, after that, every isorun.create() for that image returns to the standard low-latency startup path.

Examples

TypeScript
import { Isorun } from 'isorun'

const isorun = new Isorun()

// Standard library images, no separate setup needed
await isorun.create({ image: 'python:3.12-slim' })
await isorun.create({ image: 'node:22-slim' })
await isorun.create({ image: 'ubuntu:24.04' })
await isorun.create({ image: 'alpine:3.20' })
await isorun.create({ image: 'ruby:3.3' })
await isorun.create({ image: 'golang:1.23' })
await isorun.create({ image: 'rust:1.83' })

// Specialized agent images
await isorun.create({ image: 'mcr.microsoft.com/playwright:v1.48.0' })
await isorun.create({ image: 'jupyter/scipy-notebook:python-3.12' })

// Your own image (build + push, then reference by ref)
await isorun.create({ image: 'ghcr.io/your-org/agent-runtime:1.0' })
await isorun.create({ image: 'docker.io/youraccount/data-pipeline:v3' })

// Private registries, same syntax, configure the runner with creds
await isorun.create({ image: 'registry.internal.example.com/team/agent:latest' })

How it works

  1. The first time a runner sees an image reference, it fetches and validates the image.
  2. It prepares an optimized runtime artifact for that image so startup paths stay predictable.
  3. The runtime injects the control agent needed for exec, hibernate, networking, and observability APIs.
  4. That optimized artifact is cached per (image, runner) so subsequent isorun.create() calls reuse it.
  5. After the first build, sandbox startup returns to the normal low-latency path for that image.

The first build takes 10 to 60 seconds depending on image size and network. Every boot after that is the standard cold-start.

Pin your image tags

latest, lts, and stable tags are rejected at create time. They change without notice and would silently invalidate the cached artifact when the upstream tag is republished. Use a pinned tag (python:3.12, node:22-slim) or a digest reference (python@sha256:...).

The latest, lts, and stable tags are rejected at create time. Pin an explicit tag or digest so the cached artifact stays valid.

Pre-build an image

To amortize the first-boot pull (for example, in CI before a launch), call the build endpoint. It runs the same prep work the first create() would do:

Terminal
curl -X POST https://run-us.isorun.ai/v1/images/build \
  -H "Authorization: Bearer $ISORUN_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"image": "your-image:1.0"}'

Use custom image content

Inside the sandbox, your image is mounted as an immutable base with a writable scratch layer on top. Anything user code writes to /, /tmp, /home, etc. lands on the scratch layer and is preserved for the sandbox's lifetime (including across hibernate/resume cycles).

The image's ENTRYPOINT and CMD are not run, the init script replaces them with the isorun guest agent. If your image starts a daemon on boot, wrap it in a script and call it after isorun.create().

If your image has a startup hook (e.g. a daemon that should launch on boot), wrap it in a script and call it after isorun.create():

TypeScript
const sandbox = await isorun.create({ image: 'docker.io/your-team/agent:1.0' })
await sandbox.exec('/usr/local/bin/start-services.sh & disown', 2)

The image's environment variables (PATH, NODE_VERSION, etc.) are applied, the runner reads the image config at build time and injects them via the agent during boot.

Next steps

On this page