From 245a0d5f79b506e8934a346b1b37c3df12d83e51 Mon Sep 17 00:00:00 2001 From: Brian Reardon Date: Thu, 3 Sep 2026 13:57:23 -0700 Subject: [PATCH 1/3] =?UTF-8?q?docs:=20templates=20on=20v2=20are=20two=20m?= =?UTF-8?q?echanisms,=20not=20one=20missing=20one=20=E2=80=94=20workspace?= =?UTF-8?q?=20templates=20keep=20the=20pooled=20create=20and=20capture=20t?= =?UTF-8?q?he=20home=20directory=20(which=20is=20where=20pip=20and=20npm?= =?UTF-8?q?=20already=20install),=20custom=20images=20bake=20system=20pack?= =?UTF-8?q?ages=20into=20the=20machine=20image=20the=20sandbox=20boots=20f?= =?UTF-8?q?rom;=20documents=20what=20customers=20will=20actually=20hit:=20?= =?UTF-8?q?builds=20take=20minutes=20so=20they=20are=20ahead-of-time=20and?= =?UTF-8?q?=20inline=20image:=20on=20create=20is=20refused,=20custom-image?= =?UTF-8?q?=20creates=20cold-start,=20the=20base=20is=20AL2023=20with=20dn?= =?UTF-8?q?f=20rather=20than=20Ubuntu=20with=20apt,=20everything=20is=20AR?= =?UTF-8?q?M64,=20and=20an=20org=20holds=2010=20images=20with=20identical?= =?UTF-8?q?=20definitions=20deduped?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/migrating-from-v1.mdx | 6 +- docs/reference/typescript-sdk/image.mdx | 17 ++- docs/sandboxes/templates.mdx | 151 +++++++++++++++++------- 3 files changed, 127 insertions(+), 47 deletions(-) diff --git a/docs/migrating-from-v1.mdx b/docs/migrating-from-v1.mdx index 3b88c2eac..cd2885717 100644 --- a/docs/migrating-from-v1.mdx +++ b/docs/migrating-from-v1.mdx @@ -36,7 +36,9 @@ Seven questions. If every answer is "no", your migration is a configuration chan None of these exist in v2. - Image builds are unavailable. Fork is unavailable today and being worked on. + Image builds work, but only ahead of time — see [Templates](/sandboxes/templates). + Passing `image:` directly to a create is refused. Fork is unavailable today and being + worked on. @@ -134,7 +136,7 @@ that sandbox. See [Secrets](/sandboxes/secrets). |---|---| | `scale()`, `setAutoscale()` | memory is fixed at launch | | Mounts (FUSE, NFS, overlay) | the guest cannot perform `mount` | -| Image builds (`image:`) | no build pipeline in v2 | +| Inline `image:` on create | build ahead of time instead — see [Templates](/sandboxes/templates) | | Fork from a checkpoint | in progress | | Checkpoint patches | not wired up | | Live migration | not applicable | diff --git a/docs/reference/typescript-sdk/image.mdx b/docs/reference/typescript-sdk/image.mdx index 9f11549c2..683e65e02 100644 --- a/docs/reference/typescript-sdk/image.mdx +++ b/docs/reference/typescript-sdk/image.mdx @@ -7,7 +7,14 @@ Fluent, immutable builder for declarative sandbox images. Each method returns a ## `Image.base()` -Start from the default OpenSandbox environment (Ubuntu 22.04, Python, Node.js, build tools). +Start from the default OpenSandbox environment (Amazon Linux 2023, Python, Node.js, build +tools) on ARM64. + + +Images are built ahead of time and started by name — see +[Templates](/sandboxes/templates). Passing an `Image` directly to `Sandbox.create()` is +refused, because a build takes minutes. + ```typescript import { Image } from "@opencomputer/sdk"; @@ -28,9 +35,15 @@ const image = Image.base() ### `image.aptInstall(packages)` - System packages to install via apt-get + System packages to install + +The base is Amazon Linux 2023, so these are installed with `dnf`. Common Debian names are +translated (`build-essential` becomes `gcc gcc-c++ make`); a package that exists only on +Debian fails the build and the error names it. + + **Returns:** `Image` --- diff --git a/docs/sandboxes/templates.mdx b/docs/sandboxes/templates.mdx index 3ee466472..8b67feb72 100644 --- a/docs/sandboxes/templates.mdx +++ b/docs/sandboxes/templates.mdx @@ -1,72 +1,137 @@ --- title: "Templates" -description: "Which templates carry over, and which do not" +description: "Two ways to prepare an environment, and which one you need" --- -Templates work on v2, but **the templates you have today probably do not.** This is -the migration issue most likely to affect you, and it is worth checking before anything moves. +A template is an environment prepared once and reused by many sandboxes. v2 has **two +mechanisms**, and which one you need depends on a single question: does your setup write +outside the home directory? -## How a template is applied here +| Your setup | Mechanism | Create speed | +| --- | --- | --- | +| Python/Node packages, files, env vars | **Workspace template** | Full pooled speed | +| System packages (`apt`/`dnf`), anything in `/usr` | **Custom image** | Cold start, a few seconds | -A template create claims a standard pooled sandbox and unpacks the template's **workspace -archive** on top of it. That keeps the fast pooled create and makes a template cost a tarball -rather than a separately published machine image. +If a workspace template covers you, use it — it is faster at create time and has no limits +worth worrying about. + +## Workspace templates + +A workspace template claims a standard pooled sandbox and unpacks your saved workspace on top +of it. You keep the fast pooled create, and the template costs nothing but a tarball. ```typescript const sandbox = await Sandbox.create({ templateID: "my-template" }); ``` -## The catch: rootfs templates are refused +This captures **everything under your home directory**. That is more than it sounds: `pip` and +`npm` are configured to install there, so a Python or Node toolchain is captured for free. + +```typescript +// Both of these are captured by a workspace template. +await sandbox.exec.run("pip install pandas"); +await sandbox.exec.run("npm install -g typescript"); +``` + +What it does **not** capture is anything outside your home directory — `dnf install` writing to +`/usr`, system services, files in `/etc`. For those you need a custom image. + +## Custom images + +A custom image bakes your setup into the machine image the sandbox boots from, so system-level +changes persist. You define it with the same `Image` builder v1 uses: + +```typescript +import { Image, Snapshots, Sandbox } from "@opencomputer/sdk"; + +const snapshots = new Snapshots(); + +await snapshots.create({ + name: "video-tools", + image: Image.base() + .aptInstall(["ffmpeg"]) + .pipInstall(["numpy"]), +}); + +// Building takes minutes — wait for it before using it. +await snapshots.waitUntilReady("video-tools"); + +const sandbox = await Sandbox.create({ template: "video-tools" }); +``` + +### Four things to know -A template that carries a **rootfs image** cannot be used on v2. The create fails with -*"template … carries a rootfs image, which v2 cannot restore."* +**Builds take minutes, not seconds.** The image is built by the platform, not in your sandbox. +Build once, then start as many sandboxes from it as you like. -Templates built on v1 capture the **whole disk** — every system-level change, -not just your workspace. This runtime can only replay the workspace half, and doing that -silently would hand you your files while dropping every system change the template existed for: -a template that looks like it worked and hasn't. +**Sandboxes from a custom image cold-start.** The warm pool holds standard sandboxes, so a +custom-image create takes a few seconds instead of milliseconds. If create latency matters more +than system packages, prefer a workspace template. -So it refuses instead. That is the right failure, but it means: +**The base is Amazon Linux 2023, not Ubuntu.** `aptInstall` still works — package names are +translated where they differ (`build-essential` becomes `gcc gcc-c++ make`) — but a package that +exists only on Debian will fail the build, and the error names the package. -**Any template that installed system packages, changed system configuration, or was built -before your org moved will need rebuilding on the new runtime.** +**Everything runs on ARM64.** A build step that downloads an x86-64 binary will fail. Use your +package manager, or fetch the `aarch64`/`arm64` build. -## What to do +### Limits - - - A refused template fails loudly at create with the message above. That is the fastest audit - — you do not need to inspect anything. - - - Start a sandbox on the new runtime, install what the template provided, and capture it as a - [checkpoint](/sandboxes/checkpoints) or a new template. What can be captured is the - filesystem, so anything you can install with files and packages carries over. - - - If the template depended on changes outside the workspace, they need to live somewhere else - — either in a published image (talk to us) or as a step your sandbox runs on boot. - - +Custom images are a limited resource, so each org can hold **10** at a time. Delete one you are +no longer using to make room. + +Two identical definitions share a single image, so rebuilding an unchanged template costs +nothing and returns immediately. + +## Building inline is not supported + + +Passing `image:` directly to `Sandbox.create()` is refused on v2. Create the image first, then +create sandboxes from it by name. + + +A build takes minutes; a create that waited for one would time out. The refusal names the +supported path rather than quietly handing you a sandbox without your packages. + +```typescript +// Refused on v2 +await Sandbox.create({ image: Image.base().aptInstall(["ffmpeg"]) }); + +// Do this instead +await snapshots.create({ name: "tools", image: Image.base().aptInstall(["ffmpeg"]) }); +await snapshots.waitUntilReady("tools"); +await Sandbox.create({ template: "tools" }); +``` -## Image builds are not available +## Migrating a v1 template -Declarative image manifests (`image:` on create) and the image build pipeline are **not -supported** on v2. They depend on a build fleet it does not have. +A template that carries a **rootfs image** cannot be used on v2. The create fails with +*"template … carries a rootfs image, which v2 cannot restore."* -If you build images today, that workflow needs an alternative before you migrate: +v1 templates capture the whole disk. v2 cannot replay that, and replaying only the workspace half +would hand you your files while dropping every system change the template existed for — a +template that looks like it worked and hasn't. So it refuses instead. + + + + A template that cannot be used fails loudly at create with the message above. That is the + fastest audit — nothing to inspect. + + + Packages installed into your home directory become a workspace template. System packages + become a custom image, using the same `Image` definition you already have. + + - - Prepare a workspace once and start sandboxes from it — as long as it does not need a - rootfs. + + Save a running sandbox's workspace and restore it later. - - Install into a sandbox, checkpoint it, and restore that checkpoint when you need the - environment again. + + Every behaviour that differs between v1 and v2. From 0688ade47e3d363f72cc0eb7a9e8f3cd90143e58 Mon Sep 17 00:00:00 2001 From: Brian Reardon Date: Thu, 3 Sep 2026 14:02:14 -0700 Subject: [PATCH 2/3] =?UTF-8?q?docs:=20templates=20page=20leads=20with=20t?= =?UTF-8?q?he=20contract=20being=20unchanged=20rather=20than=20offering=20?= =?UTF-8?q?a=20choice=20=E2=80=94=20there=20is=20one=20templates=20path=20?= =?UTF-8?q?in=20the=20API=20(define=20by=20name=20with=20Image,=20create?= =?UTF-8?q?=20with=20template:),=20so=20presenting=20'workspace=20template?= =?UTF-8?q?s'=20vs=20'custom=20images'=20invented=20a=20decision=20custome?= =?UTF-8?q?rs=20cannot=20make=20and=20named=20an=20internal=20mechanism=20?= =?UTF-8?q?they=20never=20see;=20the=20page=20now=20states=20the=20API=20i?= =?UTF-8?q?s=20the=20same=20as=20v1=20and=20covers=20only=20what=20is=20ac?= =?UTF-8?q?tually=20visible=20to=20them:=20build=20ahead=20of=20time,=20te?= =?UTF-8?q?mplate=20creates=20cold-start,=20AL2023/ARM64=20package=20and?= =?UTF-8?q?=20architecture=20caveats,=20the=2010-per-org=20cap,=20and=20re?= =?UTF-8?q?building=20v1=20rootfs=20templates?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/migrating-from-v1.mdx | 3 +- docs/sandboxes/templates.mdx | 135 ++++++++++++++--------------------- 2 files changed, 54 insertions(+), 84 deletions(-) diff --git a/docs/migrating-from-v1.mdx b/docs/migrating-from-v1.mdx index cd2885717..9dd4deca0 100644 --- a/docs/migrating-from-v1.mdx +++ b/docs/migrating-from-v1.mdx @@ -88,7 +88,8 @@ A v1 template captures the whole disk. v2 can only replay the workspace half, an silently would hand you your files while dropping every system change the template existed for. So it refuses, loudly, at create. -Rebuild affected templates as workspace templates or checkpoints on v2. +Rebuild them on v2 — usually by re-running the same `Image` definition under the same name. +See [Templates](/sandboxes/templates). ### Sizes are fixed steps, and 16 GB is gone diff --git a/docs/sandboxes/templates.mdx b/docs/sandboxes/templates.mdx index 8b67feb72..8afe70c4b 100644 --- a/docs/sandboxes/templates.mdx +++ b/docs/sandboxes/templates.mdx @@ -1,45 +1,10 @@ --- title: "Templates" -description: "Two ways to prepare an environment, and which one you need" +description: "Same API as v1, with two differences worth knowing" --- -A template is an environment prepared once and reused by many sandboxes. v2 has **two -mechanisms**, and which one you need depends on a single question: does your setup write -outside the home directory? - -| Your setup | Mechanism | Create speed | -| --- | --- | --- | -| Python/Node packages, files, env vars | **Workspace template** | Full pooled speed | -| System packages (`apt`/`dnf`), anything in `/usr` | **Custom image** | Cold start, a few seconds | - -If a workspace template covers you, use it — it is faster at create time and has no limits -worth worrying about. - -## Workspace templates - -A workspace template claims a standard pooled sandbox and unpacks your saved workspace on top -of it. You keep the fast pooled create, and the template costs nothing but a tarball. - -```typescript -const sandbox = await Sandbox.create({ templateID: "my-template" }); -``` - -This captures **everything under your home directory**. That is more than it sounds: `pip` and -`npm` are configured to install there, so a Python or Node toolchain is captured for free. - -```typescript -// Both of these are captured by a workspace template. -await sandbox.exec.run("pip install pandas"); -await sandbox.exec.run("npm install -g typescript"); -``` - -What it does **not** capture is anything outside your home directory — `dnf install` writing to -`/usr`, system services, files in `/etc`. For those you need a custom image. - -## Custom images - -A custom image bakes your setup into the machine image the sandbox boots from, so system-level -changes persist. You define it with the same `Image` builder v1 uses: +Templates work on v2, and **the contract is unchanged**. You define an environment once, +give it a name, and start sandboxes from that name: ```typescript import { Image, Snapshots, Sandbox } from "@opencomputer/sdk"; @@ -53,83 +18,87 @@ await snapshots.create({ .pipInstall(["numpy"]), }); -// Building takes minutes — wait for it before using it. await snapshots.waitUntilReady("video-tools"); const sandbox = await Sandbox.create({ template: "video-tools" }); ``` -### Four things to know - - -**Builds take minutes, not seconds.** The image is built by the platform, not in your sandbox. -Build once, then start as many sandboxes from it as you like. - +Same `Image` builder, same names, same `list` / `get` / `delete`. Your existing definitions +carry over as written — what changes is how they are built underneath, and two consequences of +that are visible to you. -**Sandboxes from a custom image cold-start.** The warm pool holds standard sandboxes, so a -custom-image create takes a few seconds instead of milliseconds. If create latency matters more -than system packages, prefer a workspace template. +## 1. Build ahead of time -**The base is Amazon Linux 2023, not Ubuntu.** `aptInstall` still works — package names are -translated where they differ (`build-essential` becomes `gcc gcc-c++ make`) — but a package that -exists only on Debian will fail the build, and the error names the package. +A template is built into a machine image before any sandbox uses it, which takes minutes rather +than seconds. So the build is a separate step from the create, and you wait for it once: -**Everything runs on ARM64.** A build step that downloads an x86-64 binary will fail. Use your -package manager, or fetch the `aarch64`/`arm64` build. +```typescript +await snapshots.create({ name: "tools", image }); +await snapshots.waitUntilReady("tools"); // minutes, once +await Sandbox.create({ template: "tools" }); // fast, every time after +``` -### Limits + +Passing `image:` directly to `Sandbox.create()` is refused on v2. A create that waited for a +build would time out, so the error names the two-step path instead of returning a sandbox +without your packages. + -Custom images are a limited resource, so each org can hold **10** at a time. Delete one you are -no longer using to make room. +## 2. Sandboxes from a template cold-start -Two identical definitions share a single image, so rebuilding an unchanged template costs -nothing and returns immediately. +Standard sandboxes come from a warm pool. A sandbox built on your template does not, because the +pool holds standard sandboxes — so expect a few seconds rather than milliseconds on create. -## Building inline is not supported +Everything the template installed is already baked in, so this is paid at create, not on your +first command. - -Passing `image:` directly to `Sandbox.create()` is refused on v2. Create the image first, then -create sandboxes from it by name. - +## What your definitions run on -A build takes minutes; a create that waited for one would time out. The refusal names the -supported path rather than quietly handing you a sandbox without your packages. +The environment underneath is Amazon Linux 2023 on ARM64, so two things in an existing +definition can need attention: -```typescript -// Refused on v2 -await Sandbox.create({ image: Image.base().aptInstall(["ffmpeg"]) }); + + + `aptInstall` works and common Debian names are translated — `build-essential` becomes + `gcc gcc-c++ make`. A package that exists only on Debian fails the build, and the error + names it. + + + A step that downloads an x86-64 binary fails. Use your package manager, or fetch the + `aarch64` build. + + -// Do this instead -await snapshots.create({ name: "tools", image: Image.base().aptInstall(["ffmpeg"]) }); -await snapshots.waitUntilReady("tools"); -await Sandbox.create({ template: "tools" }); -``` +Each org holds up to **10** templates at a time; delete one to make room. Two identical +definitions share one build, so rebuilding an unchanged template returns immediately. -## Migrating a v1 template +## Templates built on v1 A template that carries a **rootfs image** cannot be used on v2. The create fails with *"template … carries a rootfs image, which v2 cannot restore."* -v1 templates capture the whole disk. v2 cannot replay that, and replaying only the workspace half -would hand you your files while dropping every system change the template existed for — a -template that looks like it worked and hasn't. So it refuses instead. +v1 templates capture the whole disk. Replaying only part of that would hand you your files while +dropping every system change the template existed for — a template that looks like it worked and +hasn't — so it refuses instead. + +Rebuilding is the fix, and usually means re-running the `Image` definition you already have. - A template that cannot be used fails loudly at create with the message above. That is the - fastest audit — nothing to inspect. + One that cannot be used fails loudly at create with the message above. That is the fastest + audit — nothing to inspect. - - Packages installed into your home directory become a workspace template. System packages - become a custom image, using the same `Image` definition you already have. + + Create it again by name with the same definition, wait for the build, and point your creates + at it. - Save a running sandbox's workspace and restore it later. + Save a running sandbox and restore it later. Every behaviour that differs between v1 and v2. From 00cc10f01923f947856c1f8d19a3cb49f3a9880e Mon Sep 17 00:00:00 2001 From: Brian Reardon Date: Thu, 3 Sep 2026 14:26:54 -0700 Subject: [PATCH 3/3] =?UTF-8?q?sdk:=20export=20Image=20and=20Snapshots=20a?= =?UTF-8?q?s=20values,=20not=20only=20as=20types=20=E2=80=94=20both=20were?= =?UTF-8?q?=20type-only=20exports,=20so=20the=20import=20the=20Image=20ref?= =?UTF-8?q?erence=20documents=20(import=20{=20Image=20}=20from=20"@opencom?= =?UTF-8?q?puter/sdk")=20failed=20at=20runtime=20with=20'does=20not=20prov?= =?UTF-8?q?ide=20an=20export=20named=20Image',=20and=20there=20was=20no=20?= =?UTF-8?q?supported=20way=20to=20define=20a=20template=20through=20the=20?= =?UTF-8?q?SDK=20at=20all;=20caught=20by=20the=20first=20end-to-end=20temp?= =?UTF-8?q?late=20run,=20which=20could=20not=20import=20them?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sdks/typescript/src/index.ts | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/sdks/typescript/src/index.ts b/sdks/typescript/src/index.ts index da0ee32af..4fd36271b 100644 --- a/sdks/typescript/src/index.ts +++ b/sdks/typescript/src/index.ts @@ -100,5 +100,12 @@ export { type TagKeyInfo, } from "./usage.js"; // Node.js-only modules (use crypto, fs, path) — import via "@opencomputer/sdk/node". +// The Image builder and the Snapshots client are exported as VALUES, not only +// as types. Both were type-only, so `import { Image } from "@opencomputer/sdk"` +// — which the Image reference documents — failed at runtime with "does not +// provide an export named 'Image'", and there was no supported way to define a +// template through the SDK at all. +export { Image } from "./image.js"; export type { ImageManifest, ImageStep } from "./image.js"; +export { Snapshots } from "./snapshot.js"; export type { SnapshotInfo, CreateSnapshotOpts, WaitForReadyOpts } from "./snapshot.js";