diff --git a/docs/migrating-from-v1.mdx b/docs/migrating-from-v1.mdx
index 3b88c2eac..9dd4deca0 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.
@@ -86,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
@@ -134,7 +137,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..8afe70c4b 100644
--- a/docs/sandboxes/templates.mdx
+++ b/docs/sandboxes/templates.mdx
@@ -1,72 +1,106 @@
---
title: "Templates"
-description: "Which templates carry over, and which do not"
+description: "Same API as v1, with two differences worth knowing"
---
-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.
+Templates work on v2, and **the contract is unchanged**. You define an environment once,
+give it a name, and start sandboxes from that name:
-## How a template is applied here
+```typescript
+import { Image, Snapshots, Sandbox } from "@opencomputer/sdk";
-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.
+const snapshots = new Snapshots();
-```typescript
-const sandbox = await Sandbox.create({ templateID: "my-template" });
+await snapshots.create({
+ name: "video-tools",
+ image: Image.base()
+ .aptInstall(["ffmpeg"])
+ .pipInstall(["numpy"]),
+});
+
+await snapshots.waitUntilReady("video-tools");
+
+const sandbox = await Sandbox.create({ template: "video-tools" });
```
-## The catch: rootfs templates are refused
+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.
+
+## 1. Build ahead of time
+
+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:
+
+```typescript
+await snapshots.create({ name: "tools", image });
+await snapshots.waitUntilReady("tools"); // minutes, once
+await Sandbox.create({ template: "tools" }); // fast, every time after
+```
-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."*
+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.
-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.
+## 2. Sandboxes from a template cold-start
-So it refuses instead. That is the right failure, but it means:
+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.
-**Any template that installed system packages, changed system configuration, or was built
-before your org moved will need rebuilding on the new runtime.**
+Everything the template installed is already baked in, so this is paid at create, not on your
+first command.
-## What to do
+## What your definitions run on
-
-
- 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.
-
-
+The environment underneath is Amazon Linux 2023 on ARM64, so two things in an existing
+definition can need attention:
+
+
+
+ `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.
+
+
-## Image builds are not available
+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.
+
+## Templates built on v1
-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. 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.
+
+
+
+ One that cannot be used fails loudly at create with the message above. That is the fastest
+ audit — nothing to inspect.
+
+
+ Create it again by name with the same definition, wait for the build, and point your creates
+ at it.
+
+
-
- Prepare a workspace once and start sandboxes from it — as long as it does not need a
- rootfs.
+
+ Save a running sandbox 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.
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";