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
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
- The first time a runner sees an image reference, it fetches and validates the image.
- It prepares an optimized runtime artifact for that image so startup paths stay predictable.
- The runtime injects the control agent needed for
exec, hibernate, networking, and observability APIs. - That optimized artifact is cached per
(image, runner)so subsequentisorun.create()calls reuse it. - 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:
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():
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
- Lifecycle and hibernation, how the scratch layer survives hibernate/resume.
- Computer use (CDP + VNC), a custom browser image in action.
- TypeScript SDK, the
create({ image })reference.