Sandboxes follow a straightforward lifecycle:

  1. Image resolution. If the image is an Image spec (e.g. Image.debian_slim().pip_install([...])), it is built and cached. Pre-built OCI images are used directly.
  2. Scheduling. The sandbox is placed on a node with sufficient resources. gVisor initializes the isolation boundary.
  3. Running. The sandbox accepts exec calls. Volumes are mounted and accessible.
  4. Termination. The sandbox is terminated explicitly or after its lifetime expires. Ephemeral filesystem state is discarded; volume data persists if synced.
from chalkcompute import Image, Sandbox

sandbox = Sandbox(
    image=Image.debian_slim().pip_install(["numpy"]),
    cpu="2",
    memory="4Gi",
    lifetime="3600s",
).run()

result = sandbox.exec("python", "-c", "import numpy; print(numpy.__version__)")
print(result.stdout_text)

sandbox.terminate()

lifetime is a protobuf duration string — a number of seconds followed by s (fractional seconds are allowed, e.g. "1.5s"), not a Go-style duration like "1h". Omitting it lets the sandbox run until it is terminated explicitly; see Long-running sandboxes for runs measured in hours or days.


​
Inspecting status

sandbox.info is None until the sandbox has been started or attached to. sandbox.refresh() both refreshes and returns the current SandboxInfo, so prefer its return value over sandbox.info when you’ve just refreshed:

info = sandbox.refresh()
print(info.status)  # "pending", "running", "succeeded", "failed", etc.
print(sandbox.id)

​
Terminating

sandbox.terminate()                          # immediate termination + cleanup
sandbox.terminate(grace_period_seconds=30)   # allow processes to shut down first

Termination cleans up the sandbox and its ephemeral filesystem. Persistent volume data remains available according to the volume’s sync and versioning semantics.