Warm
Imports resolved, caches hot, model weights mapped, the interpreter primed — the setup work is done, but nothing is left running. A fork wakes with the heavy imports already paid, so the rollout skips the import tax and gets straight to work.
00 / The cookbook
A ready state is the point a rollout starts from. You bake
an image once, warm it, and checkpoint it into an artifact; every
fork then wakes at that exact state instead of paying the
setup cost per branch. This page explains the two kinds of ready state and the
Ready helpers that declare them — the rest of the cookbook is worked recipes.
Warm
Imports resolved, caches hot, model weights mapped, the interpreter primed — the setup work is done, but nothing is left running. A fork wakes with the heavy imports already paid, so the rollout skips the import tax and gets straight to work.
Live service
A long-running process — a browser, a Jupyter kernel, a database, a model server — is started at bake time and left running, so the snapshot captures it alive. Every fork wakes with the service already up; the rollout attaches to it instead of launching it.
Warm is the common case and often all you need: pay import torch (or the npm
install, or the dataset load) once, at bake time, instead of on every branch.
Live service goes one step further — it keeps a process running across the
snapshot, so the fork inherits not just a warm cache but a live connection point.
ReadyYou name what to run and how "ready" is detected; Collimate does the rest — launching the process, waiting until it is actually serving, and snapshotting at the right moment. There is no launch-and-wait shell to hand-write.
from collimate_rl import Ready, Template, connect
client = connect() # a col_pro_* key via COLLIMATE_API_KEY
Template.bake( client, name="torch-warm", image="ghcr.io/you/trainer@sha256:…", # pin by digest ready=Ready.warm("python -c 'import torch, numpy'"), # ready when it exits 0 width=64,)Pick the readiness signal that matches the service:
# HTTP service (model/tool server, browser over CDP): poll a health URL.ready = Ready.http_service("vllm serve --port 8000", port=8000, path="/health")
# Anything with a probe command (Postgres, Redis): wait for it to exit 0.ready = Ready.service("pg_ctl -D $PGDATA start", await_cmd="pg_isready -q")
# Anything that just needs its port to accept a connection.ready = Ready.service("jupyter kernel --KernelApp.ip=127.0.0.1", await_port=8888)handle = Template.bake( client, name="my-live-service", image="ghcr.io/you/my-live-service@sha256:…", ready=ready, width=64,)handle.wait(timeout=600) # Pending → Converting → Distributing → LiveEach live-service helper compiles to a warm command that launches the process
detached (so it outlives the bake step and lands in the snapshot), then
blocks until the real serving signal passes — an HTTP 2xx, a TCP port
accepting a connection, or your probe exiting 0 — and only then exits 0,
which is what tells Collimate to snapshot. That launch → wait-until-serving →
snapshot sequence is the whole contract; the helper writes it so you don't.
A rollout against a live-service ready state attaches to the already-running process; it does not launch one. The pattern is the same across services — connect to the live endpoint, do isolated per-rollout work, disconnect without tearing the shared service down:
from collimate_rl import connect
client = connect()
ROLLOUT = """# runs inside the sandbox — attaches to the service the snapshot is already runningimport urllib.requestprint(urllib.request.urlopen("http://127.0.0.1:PORT/…").read())"""
sb = client.create_sandbox("my-live-service")result = client.exec(sb["id"], commands=[["python3", "-c", ROLLOUT]], timeout_seconds=60)print(result["stdout"])client.delete_sandbox(sb["id"])Fan a single warmed parent out across many rollouts with fork — every child
inherits the same live service:
# count is the per-call fan-out, capped by tier (Pro 32, Ent 64); call again# (or use Session.fork_group) for a wider group.children = client.fork(sb["id"], count=32)["children"]for child in children: client.exec(child["id"], commands=[["python3", "-c", ROLLOUT]], timeout_seconds=60)Give each rollout its own isolated scope against the shared service (a fresh browser context, a scratch database schema, a per-rollout kernel session) and tear down that scope on exit — never the service itself, which is the shared warm state.
Each cookbook page declares its service with one Ready helper — a different
service and readiness signal swapped in:
| Recipe | Service | Ready helper |
|---|---|---|
| Live browser | Headless Chromium over CDP | Ready.http_service(…, path="/json/version") |
| Live Jupyter | A running Jupyter kernel | Ready.service(…, await_port=…) |
| Live Postgres | An initialized Postgres server | Ready.service(…, await_cmd="pg_isready") |
| Live model server | A small inference/tool server | Ready.http_service(…, path="/health") |