@coder/ai-sdk-sandbox 0.4.1 → 0.4.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/README.md +177 -11
  2. package/package.json +1 -1
package/README.md CHANGED
@@ -246,17 +246,181 @@ Esc or Ctrl+C).
246
246
 
247
247
  Because the bridge runs inside the workspace, the workspace image must have:
248
248
 
249
- - **Node.js** (the docs use `node24`). The bridge is `node bridge.mjs`.
250
- - **pnpm** available on PATH (e.g. via `corepack enable`) — the adapter uses it to
251
- bootstrap the bridge.
252
- - **Outbound network access** to the npm registry (the adapter `pnpm install`s
253
- the bridge's dependencies + the Claude Code CLI on first use) and to the model
254
- API (`api.anthropic.com` for Claude Code, `api.openai.com` for Codex). Bake the
255
- dependencies into the image to avoid per-session installs.
249
+ - **Node.js ≥ 22** on the login-shell PATH. The bridge is `node bridge.mjs`, the
250
+ native transport's relay is `node -e`, and the pinned
251
+ `@anthropic-ai/claude-code` bridge dependency requires Node 22+.
252
+ - **pnpm** on the login-shell PATH (e.g. `npm install -g pnpm`) — the adapter's
253
+ bootstrap runs `pnpm install --frozen-lockfile` to install the bridge's
254
+ dependencies.
255
+ - **Outbound network access** to the npm registry (the bootstrap downloads the
256
+ bridge's dependencies — including the Claude Code CLI's ~250 MB platform
257
+ binary, which ships as an npm package — on first use) and to the model API
258
+ (`api.anthropic.com` for Claude Code, `api.openai.com` for Codex). Pre-bake
259
+ the bootstrap into the image to skip the registry entirely — see
260
+ [Template authoring](#template-authoring-zero-install-sessions).
256
261
  - **The model API key** available to the bridge — `ANTHROPIC_API_KEY` /
257
262
  `OPENAI_API_KEY`. Configure it through the adapter's `auth` option or ensure it
258
263
  is present in the workspace environment.
259
- - `bash` and `base64` (standard on any Linux dev image).
264
+ - `bash` and `base64` (remote commands run through `bash -lc`; file I/O is
265
+ base64-encoded), plus `stty` for the native transport's relay bootstrap. All
266
+ standard on any Linux dev image.
267
+
268
+ ## Template authoring: zero-install sessions
269
+
270
+ How to build a Coder template whose workspaces start harness sessions with
271
+ **zero runtime install latency**. Generic template authoring is covered by the
272
+ [Coder template docs](https://coder.com/docs/admin/templates) and
273
+ [Coder's example Docker template](https://github.com/coder/coder/tree/main/examples/templates/docker);
274
+ this section covers only the ai-sdk-specific delta. A validated
275
+ Dockerfile + `main.tf` pair lives in [`examples/template/`](./examples/template/).
276
+
277
+ ### What the first session installs
278
+
279
+ On the first session in a fresh workspace, the Claude Code adapter applies its
280
+ bootstrap recipe relative to the session's default working directory (`$HOME`
281
+ for this provider):
282
+
283
+ 1. It writes `package.json`, `pnpm-lock.yaml`, and `bridge.mjs` (assets shipped
284
+ inside `@ai-sdk/harness-claude-code`) to `~/.harness-bootstrap/claude-code/`.
285
+ 2. It runs `pnpm install --frozen-lockfile --store-dir .pnpm-store` there. This
286
+ is the expensive step: ~300 MB from the npm registry — the bridge
287
+ dependencies include the `@anthropic-ai/claude-code` platform binary — taking
288
+ tens of seconds to minutes depending on the network.
289
+ 3. It runs the CLI's `install.cjs` (links the platform binary npm delivered; no
290
+ extra download) and `./node_modules/.bin/claude --version`.
291
+ 4. It writes a `.bootstrap-<recipe-hash>.ok` marker next to them. Later sessions
292
+ see the marker and skip all of the above — a single file read.
293
+
294
+ Zero-install means baking the results of steps 1–3 into the image **at that
295
+ exact path**. The first session in each workspace then replays the recipe as a
296
+ fast offline no-op (~4 s measured; pnpm prints `Already up to date` and
297
+ downloads nothing) and writes the marker; every session after that is a single
298
+ file read.
299
+
300
+ ### Step 1 — Dockerfile: pre-bake the bootstrap
301
+
302
+ [`examples/template/Dockerfile`](./examples/template/Dockerfile) installs the
303
+ [workspace requirements](#workspace-requirements) (Node 24 + pnpm on PATH,
304
+ bash/coreutils) and replays the recipe at build time — same files, same
305
+ commands, same absolute path:
306
+
307
+ ```dockerfile
308
+ ARG HARNESS_CLAUDE_CODE_VERSION=1.0.76
309
+ RUN mkdir -p /home/${USER}/.harness-bootstrap/claude-code \
310
+ && cd /tmp \
311
+ && npm pack @ai-sdk/harness-claude-code@${HARNESS_CLAUDE_CODE_VERSION} \
312
+ && tar -xzf ai-sdk-harness-claude-code-${HARNESS_CLAUDE_CODE_VERSION}.tgz \
313
+ && cp package/dist/bridge/package.json package/dist/bridge/pnpm-lock.yaml \
314
+ /home/${USER}/.harness-bootstrap/claude-code/ \
315
+ && cp package/dist/bridge/index.mjs \
316
+ /home/${USER}/.harness-bootstrap/claude-code/bridge.mjs \
317
+ && rm -rf package ai-sdk-harness-claude-code-${HARNESS_CLAUDE_CODE_VERSION}.tgz \
318
+ && cd /home/${USER}/.harness-bootstrap/claude-code \
319
+ && pnpm install --frozen-lockfile --store-dir .pnpm-store \
320
+ && node node_modules/@anthropic-ai/claude-code/install.cjs \
321
+ && ./node_modules/.bin/claude --version
322
+ ```
323
+
324
+ Rules that make or break the pre-bake:
325
+
326
+ - **Bake at the final absolute path.** pnpm records the store location as an
327
+ absolute path (in `node_modules/.modules.yaml`), so a cache baked at, say,
328
+ `/opt/...` and copied into `$HOME` later makes the session's `pnpm install`
329
+ abort (`ERR_PNPM_ABORTED_REMOVE_MODULES_DIR_NO_TTY` — pnpm wants to purge and
330
+ reinstall, and a session has no TTY to confirm).
331
+ - **Pin the adapter version your application resolves** (find it with
332
+ `pnpm why @ai-sdk/harness-claude-code`, or in your lockfile) and pass it as
333
+ `--build-arg HARNESS_CLAUDE_CODE_VERSION=...`. The recipe and its marker hash
334
+ derive from the adapter's shipped assets. A mismatch is not fatal — the
335
+ recipe re-runs in the same directory and downloads only the delta — but it
336
+ reintroduces registry traffic on first sessions.
337
+ - **Build for the workspace CPU architecture** — the pre-bake fetches the
338
+ builder platform's `claude` binary.
339
+
340
+ ### Step 2 — main.tf: get the cache into the home volume
341
+
342
+ [`examples/template/main.tf`](./examples/template/main.tf) is Coder's example
343
+ Docker template minus the IDE modules, with three ai-sdk-specific choices:
344
+
345
+ - **The workspace image is the pre-baked one** (`variable "image"`); push it to
346
+ a registry your Coder provisioners can pull from.
347
+ - **`startup_script_behavior = "blocking"`** on `coder_agent`: this provider's
348
+ create mode waits for `lifecycle_state: ready` before the harness runs, and
349
+ blocking makes ready mean "startup script finished" (the attribute defaults to
350
+ `non-blocking`, in which case ready does not wait for the script).
351
+ - **The home volume seeds itself from the image.** Docker populates a fresh
352
+ (empty) named volume with the image's content at the mount path, so
353
+ `/home/coder/.harness-bootstrap` lands in every new workspace's volume with no
354
+ startup-script copying. No port configuration is needed either: the provider
355
+ forwards the bridge port itself (OpenSSH `-L` or the native relay), not
356
+ through template port shares.
357
+
358
+ For volume types that do _not_ copy image content (a Kubernetes PVC mounted at
359
+ `/home/coder` shadows it with an empty filesystem), stash the bake outside the
360
+ mount and restore it — at the same absolute path — on first start:
361
+
362
+ ```dockerfile
363
+ # Dockerfile, after the pre-bake step:
364
+ RUN sudo cp -a /home/${USER}/.harness-bootstrap /opt/harness-bootstrap-stash
365
+ ```
366
+
367
+ ```hcl
368
+ startup_script = <<-EOT
369
+ set -e
370
+ if [ ! -d ~/.harness-bootstrap ]; then
371
+ cp -a /opt/harness-bootstrap-stash ~/.harness-bootstrap
372
+ fi
373
+ EOT
374
+ ```
375
+
376
+ (`cp -a` preserves the hardlinks between the pnpm store and `node_modules`, so
377
+ the stash and the restore each stay ~300 MB rather than doubling.)
378
+
379
+ Build, push, and point the provider at the template
380
+ ([creating templates](https://coder.com/docs/admin/templates/creating-templates)):
381
+
382
+ ```bash
383
+ cd examples/template
384
+ docker build -t <registry>/ai-sdk-sandbox-workspace:v1 .
385
+ docker push <registry>/ai-sdk-sandbox-workspace:v1
386
+ coder templates push ai-sdk-sandbox --variable image=<registry>/ai-sdk-sandbox-workspace:v1
387
+ ```
388
+
389
+ ```ts
390
+ createCoderWorkspace({ create: { template: "ai-sdk-sandbox" } });
391
+ ```
392
+
393
+ ### Sizing
394
+
395
+ Measured on the example image (linux/amd64): ~730 MB total — ~430 MB for
396
+ Ubuntu 24.04 + Node 24 + pnpm, ~300 MB for the bootstrap cache (dominated by
397
+ the pnpm store; `node_modules` hardlinks into it). Each workspace's home volume
398
+ receives the ~300 MB seeded cache; leave headroom for per-session work
399
+ directories (`claude-code-<sessionId>/`) and whatever your agents check out.
400
+
401
+ ### Verifying zero installs
402
+
403
+ **Image-level (no Coder deployment needed).** Replay the bootstrap on a fresh
404
+ volume with networking disabled — it must succeed offline:
405
+
406
+ ```bash
407
+ docker volume rm -f probe-home && docker volume create probe-home
408
+ docker run --rm --network none -v probe-home:/home/coder \
409
+ <image> bash -lc 'cd ~/.harness-bootstrap/claude-code \
410
+ && pnpm install --frozen-lockfile --store-dir .pnpm-store \
411
+ && node node_modules/@anthropic-ai/claude-code/install.cjs \
412
+ && ./node_modules/.bin/claude --version'
413
+ ```
414
+
415
+ Expect `Already up to date` from pnpm and the CLI version banner in a few
416
+ seconds — proof that a session's bootstrap needs no registry access.
417
+
418
+ **Session-level.** After the first session against a workspace from the
419
+ template, `~/.harness-bootstrap/claude-code/` must contain a `.bootstrap-*.ok`
420
+ marker (later sessions skip the recipe entirely). If session creation instead
421
+ stalls for minutes with pnpm download progress in the bootstrap, the image's
422
+ pinned adapter version doesn't match the application's (see the pinning rule
423
+ above).
260
424
 
261
425
  ## Settings
262
426
 
@@ -383,9 +547,11 @@ and a full Claude Code turn with tool use (`scripts/e2e-claude.ts`).
383
547
  native transport refuses to guess.
384
548
  - `@ai-sdk/sandbox-just-bash` cannot expose ports and is rejected by bridge-backed
385
549
  adapters — this provider exists precisely to provide that port.
386
- - To run Claude Code / Codex, the **workspace** image needs Node.js (the adapter
387
- installs the bridge + CLI on first use) and egress to the npm registry and the
388
- model API. Provide the API key via the adapter's `auth` option.
550
+ - To run Claude Code / Codex, the **workspace** image needs Node.js ≥ 22 (the
551
+ adapter installs the bridge + CLI on first use) and egress to the npm registry
552
+ and the model API unless the image pre-bakes the bootstrap (see
553
+ [Template authoring](#template-authoring-zero-install-sessions)). Provide the
554
+ API key via the adapter's `auth` option.
389
555
 
390
556
  ## Development
391
557
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@coder/ai-sdk-sandbox",
3
- "version": "0.4.1",
3
+ "version": "0.4.2",
4
4
  "description": "Coder workspace sandbox provider for the Vercel AI SDK v7 HarnessAgent",
5
5
  "keywords": [
6
6
  "ai-sdk",