From 9a4f6c8310e011a9e5af54edcfc465e3805b7299 Mon Sep 17 00:00:00 2001 From: Naresh Date: Fri, 7 Aug 2026 16:57:44 +0100 Subject: [PATCH 1/5] Add Sandbox 1.0 migration skills Refresh sandbox-sdk for @next and add sandbox-v1-migration plus sandbox-2026-deprecation so agents install migrate paths from cloudflare/skills instead of docs-only markdown. --- README.md | 4 +- skills/sandbox-2026-deprecation/SKILL.md | 43 +++ skills/sandbox-sdk/SKILL.md | 235 +++++++------- .../sandbox-sdk/references/api-quick-ref.md | 158 ++++----- skills/sandbox-sdk/references/examples.md | 58 +--- skills/sandbox-v1-migration/SKILL.md | 301 ++++++++++++++++++ 6 files changed, 538 insertions(+), 261 deletions(-) create mode 100644 skills/sandbox-2026-deprecation/SKILL.md create mode 100644 skills/sandbox-v1-migration/SKILL.md diff --git a/README.md b/README.md index 351880c..59e9af9 100644 --- a/README.md +++ b/README.md @@ -57,7 +57,9 @@ Skills are contextual and auto-loaded based on your conversation. When a request | cloudflare | Comprehensive platform skill covering Workers, Pages, storage (KV, D1, R2), AI (Workers AI, Vectorize, Agents SDK), networking (Tunnel, Spectrum), security (WAF, DDoS), and IaC (Terraform, Pulumi) | | agents-sdk | Building stateful AI agents with state, scheduling, RPC, MCP servers, email, and streaming chat | | durable-objects | Stateful coordination (chat rooms, games, booking), RPC, SQLite, alarms, WebSockets | -| sandbox-sdk | Secure code execution for AI code execution, code interpreters, CI/CD systems, and interactive dev environments | +| sandbox-sdk | Secure code execution on Sandbox SDK; prefer `@cloudflare/sandbox@next` for new work | +| sandbox-v1-migration | Migrate a stable Sandbox app to `@cloudflare/sandbox@next` (1.0 preview) | +| sandbox-2026-deprecation | Clean up deprecated APIs while staying on the current stable Sandbox package | | wrangler | Deploying and managing Workers, KV, R2, D1, Vectorize, Queues, Workflows | | web-perf | Auditing Core Web Vitals (FCP, LCP, TBT, CLS), render-blocking resources, network chains | | building-mcp-server-on-cloudflare | Building remote MCP servers with tools, OAuth, and deployment | diff --git a/skills/sandbox-2026-deprecation/SKILL.md b/skills/sandbox-2026-deprecation/SKILL.md new file mode 100644 index 0000000..04372ba --- /dev/null +++ b/skills/sandbox-2026-deprecation/SKILL.md @@ -0,0 +1,43 @@ +--- +name: sandbox-2026-deprecation +description: Use when cleaning up a Cloudflare Sandbox SDK app that stays on the current stable package—HTTP/WebSocket transports, exposePort, default sessions, stream-specific helpers, or other APIs deprecated on stable. Not for full migration to @next (use sandbox-v1-migration). +--- + +# Sandbox SDK stable deprecation cleanup + +For apps that **remain on the current stable** `@cloudflare/sandbox` package and must leave deprecated features. Installed via [cloudflare/skills](https://github.com/cloudflare/skills) / [Agent setup](https://developers.cloudflare.com/agent-setup/). + +**Not** the path to Sandbox SDK 1.0. For `@cloudflare/sandbox@next`, use **`sandbox-v1-migration`**. + +**Docs:** [Deprecation guide](https://developers.cloudflare.com/sandbox/guides/2026-deprecation/) · [Changelog](https://developers.cloudflare.com/changelog/sandbox/2026-06-09-deprecating-sandbox-sdk-features/) + +## Checklist + +1. Update `@cloudflare/sandbox` and the matching container image before changing runtime config. +2. Search: + + ```sh + rg 'SANDBOX_TRANSPORT|transport:|exposePort\(|enableDefaultSession|execStream\(|readFileStream|writeFileStream' + ``` + +3. Switch every sandbox to **RPC** (`SANDBOX_TRANSPORT=rpc` or `getSandbox(..., { transport: "rpc" })`). +4. Replace `exposePort()` with `sandbox.tunnels.get()` when tunnels fit. Keep `exposePort` + `proxyToSandbox` if the Worker must authenticate or rewrite responses. +5. Set `enableDefaultSession: false` (requires SDK **0.10.3+**). Use explicit `createSession()` when shell state must persist across commands on stable. +6. Move stream-specific file/command helpers to base `readFile` / `writeFile` / `exec` where streaming is supported (often needs RPC). +7. Desktop demo APIs are removed on recent stable lines—do not restore them; rebuild in-sandbox computer-use only if the product still needs it. +8. Deploy and smoke-test commands, files, public URLs, and any remaining explicit sessions. + +## Replacements + +| Deprecated | Replacement | +| ---------- | ----------- | +| HTTP / WebSocket transport | RPC | +| `exposePort()` (typical public URL) | `sandbox.tunnels.get()` | +| Default sessions | `enableDefaultSession: false` + explicit sessions or per-command `cwd`/`env` | +| Stream-only helpers | Base APIs with streaming support | + +## Notes + +- Tunnels and large/binary streaming expect RPC—configure transport first. +- If `cd` must carry across `exec` on **stable**, use an explicit session with `cwd` (stable-only; gone on `@next`). +- After this cleanup, plan **`sandbox-v1-migration`** when moving to 1.0. diff --git a/skills/sandbox-sdk/SKILL.md b/skills/sandbox-sdk/SKILL.md index 2e7e0c3..c7b8118 100644 --- a/skills/sandbox-sdk/SKILL.md +++ b/skills/sandbox-sdk/SKILL.md @@ -1,177 +1,166 @@ --- name: sandbox-sdk -description: Build sandboxed applications for secure code execution. Load when building AI code execution, code interpreters, CI/CD systems, interactive dev environments, or executing untrusted code. Covers Sandbox SDK lifecycle, commands, files, code interpreter, and preview URLs. Biases towards retrieval from Cloudflare docs over pre-trained knowledge. +description: Build apps with Cloudflare Sandbox SDK for secure code execution. Use for new sandboxes, AI code execution, interpreters, CI-like jobs, and interactive environments. Prefer @cloudflare/sandbox@next (Sandbox SDK 1.0 preview) for new work. Load sandbox-v1-migration when moving a stable app to @next; load sandbox-2026-deprecation for stable-only cleanup of transports, exposePort, and default sessions. --- # Cloudflare Sandbox SDK -Build secure, isolated code execution environments on Cloudflare Workers. +Isolated Linux environments on [Cloudflare Containers](https://developers.cloudflare.com/containers/), driven from Workers. -## FIRST: Verify Installation +## Choose the right track -```bash -npm install @cloudflare/sandbox -docker info # Must succeed - Docker required for local dev -``` +| Situation | Package | Skill / docs | +| --------- | ------- | ------------ | +| **New project** | `@cloudflare/sandbox@next` | This skill + [1.0 preview](https://developers.cloudflare.com/sandbox/1-0-preview/) | +| **Migrate stable → 1.0** | `@next` | **`sandbox-v1-migration`** + [Migrate](https://developers.cloudflare.com/sandbox/1-0-preview/migrate/) | +| **Stay on stable; remove deprecated APIs** | current stable | **`sandbox-2026-deprecation`** + [2026 deprecation guide](https://developers.cloudflare.com/sandbox/guides/2026-deprecation/) | +| **Stable-only maintenance** | current stable | [Main Sandbox docs](https://developers.cloudflare.com/sandbox/) | -## Retrieval Sources +Do not mix a preview Worker package with a stable container image (or the reverse). -Your knowledge of the Sandbox SDK may be outdated. **Prefer retrieval over pre-training** for any Sandbox SDK task. +**Agent setup (install these skills):** [Agent setup](https://developers.cloudflare.com/agent-setup/) · [cloudflare/skills](https://github.com/cloudflare/skills) -| Resource | URL | -|----------|-----| -| Docs | https://developers.cloudflare.com/sandbox/ | -| API Reference | https://developers.cloudflare.com/sandbox/api/ | -| Examples | https://github.com/cloudflare/sandbox-sdk/tree/main/examples | -| Get Started | https://developers.cloudflare.com/sandbox/get-started/ | +## Retrieval (prefer docs over memory) -When implementing features, fetch the relevant doc page or example first. +| Topic | URL | +| ----- | --- | +| 1.0 overview | https://developers.cloudflare.com/sandbox/1-0-preview/ | +| Get started (`@next`) | https://developers.cloudflare.com/sandbox/1-0-preview/get-started/ | +| Processes | https://developers.cloudflare.com/sandbox/1-0-preview/processes/ | +| Process API | https://developers.cloudflare.com/sandbox/1-0-preview/api/processes/ | +| Terminals | https://developers.cloudflare.com/sandbox/1-0-preview/terminals/ | +| Errors | https://developers.cloudflare.com/sandbox/1-0-preview/errors/ | +| Environment | https://developers.cloudflare.com/sandbox/1-0-preview/environment/ | +| Interpreter | https://developers.cloudflare.com/sandbox/1-0-preview/interpreter/ | +| Examples | https://github.com/cloudflare/sandbox-sdk/tree/next/examples | +| Stable docs | https://developers.cloudflare.com/sandbox/ | -## Required Configuration +Fetch the relevant page when implementing. Installed `@next` types win over guesses. -**wrangler.jsonc** (exact - do not modify structure): +## Install (`@next`) -```jsonc -{ - "containers": [{ - "class_name": "Sandbox", - "image": "./Dockerfile", - "instance_type": "lite", - "max_instances": 1 - }], - "durable_objects": { - "bindings": [{ "class_name": "Sandbox", "name": "Sandbox" }] - }, - "migrations": [{ "new_sqlite_classes": ["Sandbox"], "tag": "v1" }] -} +```bash +npm install @cloudflare/sandbox@next +docker info # required for local container dev ``` -**Worker entry** - must re-export Sandbox class: +Container image must match the Worker line, for example `cloudflare/sandbox:next` (Python interpreter: `next-python` variant). -```typescript -import { getSandbox } from '@cloudflare/sandbox'; -export { Sandbox } from '@cloudflare/sandbox'; // Required export -``` +## Required Worker shape -## Quick Reference +Re-export `Sandbox` and bind the Durable Object / container in wrangler (see preview get-started). Minimal Worker: -| Task | Method | -|------|--------| -| Get sandbox | `getSandbox(env.Sandbox, 'user-123')` | -| Run command | `await sandbox.exec('python script.py')` | -| Run code (interpreter) | `await sandbox.runCode(code, { language: 'python' })` | -| Write file | `await sandbox.writeFile('/workspace/app.py', content)` | -| Read file | `await sandbox.readFile('/workspace/app.py')` | -| Create directory | `await sandbox.mkdir('/workspace/src', { recursive: true })` | -| List files | `await sandbox.listFiles('/workspace')` | -| Expose port | `await sandbox.exposePort(8080)` | -| Destroy | `await sandbox.destroy()` | +```ts +import { getSandbox, proxyToSandbox, Sandbox } from "@cloudflare/sandbox"; -## Core Patterns +export { Sandbox }; -### Execute Commands +export default { + async fetch(request: Request, env: Env): Promise { + const proxy = await proxyToSandbox(request, env); + if (proxy) return proxy; -```typescript -const sandbox = getSandbox(env.Sandbox, 'user-123'); -const result = await sandbox.exec('python --version'); -// result: { stdout, stderr, exitCode, success } + const sandbox = getSandbox(env.Sandbox, "user-123"); + const process = await sandbox.exec(["python3", "-c", "print(2 + 2)"]); + const output = await process.output({ encoding: "utf8" }); + return Response.json({ + stdout: output.stdout, + exitCode: output.exitCode, + }); + }, +}; ``` -### Code Interpreter (Recommended for AI) +## Core model (`@next`) -Use `runCode()` for executing LLM-generated code with rich outputs: +- `exec(argv)` takes an **argv array**, resolves when the process **starts**, returns a **handle**. +- Collect results with `output()`, `logs()`, `waitForExit()`, `waitForPort()`, `waitForLog()`, `kill(signal?)`. +- No implicit shell and no shell-escaping of argv. Shell syntax needs e.g. `["/bin/bash", "-lc", script]`. +- No hidden sessions: `cd` / `export` in one process do not affect the next. Pass `cwd` / `env` per launch or one shell script. +- Process handles have **no stdin**. Interactive PTY → `createTerminal` + `connect`. +- Local wait `timeout` / `AbortSignal` cancel the wait only — they do not kill the process. +- `getProcess` / `listProcesses` do not start a container; they return `null` / `[]` when none is up. +- Process IDs are per **current container**, not forever for a sandbox ID. Store the job to relaunch after stop/replace. -```typescript -const ctx = await sandbox.createCodeContext({ language: 'python' }); +### Short command -await sandbox.runCode('import pandas as pd; data = [1,2,3]', { context: ctx }); -const result = await sandbox.runCode('sum(data)', { context: ctx }); -// result.results[0].text = "6" +```ts +const process = await sandbox.exec(["node", "--version"]); +const result = await process.output({ encoding: "utf8" }); +// result.stdout, result.exitCode, result.truncated, ... ``` -**Languages**: `python`, `javascript`, `typescript` - -State persists within context. Create explicit contexts for production. - -### File Operations +### Long-running + readiness -```typescript -await sandbox.mkdir('/workspace/project', { recursive: true }); -await sandbox.writeFile('/workspace/project/main.py', code); -const file = await sandbox.readFile('/workspace/project/main.py'); -const files = await sandbox.listFiles('/workspace/project'); +```ts +const server = await sandbox.exec(["/bin/bash", "-lc", "npm run dev"], { + cwd: "/workspace/app", +}); +await server.waitForPort(3000, { timeout: 60_000 }); // default mode: tcp +const stream = await server.logs({ follow: true, replay: true }); +await server.kill(); // numeric signal, default 15 ``` -## When to Use What +### Interpreter (extension) -| Need | Use | Why | -|------|-----|-----| -| Shell commands, scripts | `exec()` | Direct control, streaming | -| LLM-generated code | `runCode()` | Rich outputs, state persistence | -| Build/test pipelines | `exec()` | Exit codes, stderr capture | -| Data analysis | `runCode()` | Charts, tables, pandas | +```ts +import { Sandbox as BaseSandbox } from "@cloudflare/sandbox"; +import { withInterpreter } from "@cloudflare/sandbox/interpreter"; -## Extending the Dockerfile - -Base image (`docker.io/cloudflare/sandbox:0.7.0`) includes Python 3.11, Node.js 20, and common tools. - -Add dependencies by extending the Dockerfile: - -```dockerfile -FROM docker.io/cloudflare/sandbox:0.7.0 +export class Sandbox extends BaseSandbox { + interpreter = withInterpreter(this); +} -# Python packages -RUN pip install requests beautifulsoup4 +const ctx = await sandbox.interpreter.createCodeContext({ language: "python" }); +const result = await sandbox.interpreter.runCode("print(1+1)", { context: ctx }); +``` -# Node packages (global) -RUN npm install -g typescript +Python needs the **`-python`** image variant. -# System packages -RUN apt-get update && apt-get install -y ffmpeg && rm -rf /var/lib/apt/lists/* +### Terminals -EXPOSE 8080 # Required for local dev port exposure +```ts +const terminal = await sandbox.createTerminal({ command: ["bash"] }); +// WebSocket upgrade: +const t = await sandbox.getTerminal(terminal.id); +if (t) return t.connect(request, { cursor }); ``` -Keep images lean - affects cold start time. +### Files, mounts, ports, tunnels -## Preview URLs (Port Exposure) +Still on the sandbox. Prefer main docs for signatures; ignore stable-only session/transport/`sandbox.terminal` bits. Preview env: [Environment variables](https://developers.cloudflare.com/sandbox/1-0-preview/environment/). -Expose HTTP services running in sandboxes: +Non-secret config only in `setEnvVars` / launch `env`. Live credentials: Worker secrets + [outbound traffic](https://developers.cloudflare.com/sandbox/guides/outbound-traffic/). -```typescript -const { url } = await sandbox.exposePort(8080); -// Returns preview URL for the service -``` - -**Production requirement**: Preview URLs need a custom domain with wildcard DNS (`*.yourdomain.com`). The `.workers.dev` domain does not support preview URL subdomains. +### Errors (do not one-loop retry) -See: https://developers.cloudflare.com/sandbox/guides/expose-services/ +| Error | Action | +| ----- | ------ | +| `ContainerUnavailableError` | Back off; retry as a **new** operation | +| `OperationInterruptedError` / `RPCTransportError` | Inspect; work may have started — no blind replay | +| `StaleProcessHandleError` / `StaleTerminalHandleError` | Relaunch from stored job | +| Local wait timeout / abort | Observation only; process may still run | -## OpenAI Agents SDK Integration +See [Errors and recovery](https://developers.cloudflare.com/sandbox/1-0-preview/errors/). -The SDK provides helpers for OpenAI Agents at `@cloudflare/sandbox/openai`: - -```typescript -import { Shell, Editor } from '@cloudflare/sandbox/openai'; -``` +### Public URLs -See `examples/openai-agents` for complete integration pattern. +Prefer `sandbox.tunnels` where appropriate; `exposePort` + `proxyToSandbox` when the Worker must front the request. Production preview hostnames need wildcard DNS on a custom domain. -## Sandbox Lifecycle +### Bridge -- `getSandbox()` returns immediately - container starts lazily on first operation -- Containers sleep after 10 minutes of inactivity (configurable via `sleepAfter`) -- Use `destroy()` to immediately free resources -- Same `sandboxId` always returns same sandbox instance +Self-deployed HTTP bridge is **not** on the 1.0 preview line yet. Keep bridge Worker + image + clients on **stable**. See [Bridge](https://developers.cloudflare.com/sandbox/bridge/). -## Anti-Patterns +## Anti-patterns -- **Don't use internal clients** (`CommandClient`, `FileClient`) - use `sandbox.*` methods -- **Don't skip the Sandbox export** - Worker won't deploy without `export { Sandbox }` -- **Don't hardcode sandbox IDs for multi-user** - use user/session identifiers -- **Don't forget cleanup** - call `destroy()` for temporary sandboxes +- String `exec` that expects buffered completion (stable) on `@next` +- Mixing `@next` Worker with stable image +- Assuming session/`cd` state across `exec` calls +- Putting API keys in sandbox env +- Inventing `gitCheckout` on core — use argv `git` via `exec` +- Using general knowledge instead of `@next` types + preview docs -## Detailed References +## Related skills -- **[references/api-quick-ref.md](references/api-quick-ref.md)** - Full API with options and return types -- **[references/examples.md](references/examples.md)** - Example index with use cases +- **`sandbox-v1-migration`** — stable → `@next` +- **`sandbox-2026-deprecation`** — deprecated APIs while staying on stable diff --git a/skills/sandbox-sdk/references/api-quick-ref.md b/skills/sandbox-sdk/references/api-quick-ref.md index 34cf760..ee641be 100644 --- a/skills/sandbox-sdk/references/api-quick-ref.md +++ b/skills/sandbox-sdk/references/api-quick-ref.md @@ -1,113 +1,89 @@ -# Sandbox SDK API Reference +# Sandbox SDK API quick reference (`@next`) -Detailed API for `@cloudflare/sandbox`. For full docs: https://developers.cloudflare.com/sandbox/api/ +Canonical docs: https://developers.cloudflare.com/sandbox/1-0-preview/api/ + +Prefer installed `@cloudflare/sandbox@next` types. Stable package APIs differ (string `exec`, sessions, etc.). ## Lifecycle -```typescript -getSandbox(binding: DurableObjectNamespace, sandboxId: string, options?: SandboxOptions): Sandbox +```ts +getSandbox(binding, sandboxId, options?: { + sleepAfter?: string | number; + keepAlive?: boolean; + normalizeId?: boolean; + // no transport / enableDefaultSession on @next +}): Sandbox -interface SandboxOptions { - sleepAfter?: string; // Duration before auto-sleep (default: "10m") - keepAlive?: boolean; // Prevent auto-sleep (default: false) - normalizeId?: boolean; // Lowercase IDs for preview URLs (default: false) -} +await sandbox.destroy(): Promise +``` -await sandbox.destroy(): Promise // Immediately terminate and delete all state +## Processes + +```ts +await sandbox.exec(argv: readonly [string, ...string[]], options?: { + cwd?: string; + env?: Record; + timeout?: number; // remote process lifetime +}): Promise + +await sandbox.getProcess(id: string): Promise // non-waking +await sandbox.listProcesses(): Promise + +// handle +process.id +process.pid +await process.output({ encoding?: "utf8"; maxBytes?; timeout?; signal? }) +await process.logs({ since?; replay?; follow?; signal? }) +await process.waitForExit({ timeout?; signal? }) +await process.waitForPort(port, { mode?: "tcp" | "http"; path?; timeout?; ... }) +await process.waitForLog(pattern, { stream?; timeout?; signal? }) +await process.kill(signal?: number) // default 15 +await process.status() ``` -## Commands +`await exec` = launch succeeded, not exit. No process stdin. -```typescript -await sandbox.exec(command: string, options?: ExecOptions): Promise +## Terminals -interface ExecOptions { - cwd?: string; // Working directory - env?: Record; // Environment variables - timeout?: number; // Timeout in ms (no default; runs without timeout if unset) - stdin?: string; // Input to command -} +```ts +await sandbox.createTerminal({ + command: readonly [string, ...string[]]; + cwd?; env?; cols?; rows?; bufferSize?; +}): Promise -interface ExecResult { - stdout: string; - stderr: string; - exitCode: number; - success: boolean; // exitCode === 0 -} -``` +await sandbox.getTerminal(id): Promise +await sandbox.listTerminals(): Promise -## Code Interpreter - -```typescript -await sandbox.createCodeContext(options?: CreateContextOptions): Promise - -interface CreateContextOptions { - language?: 'python' | 'javascript' | 'typescript'; // default: 'python' - cwd?: string; // Working directory (default: '/workspace') - envVars?: Record; - timeout?: number; // Request timeout in ms (default: 30000) -} - -await sandbox.runCode(code: string, options?: RunCodeOptions): Promise - -interface RunCodeOptions { - context?: CodeContext; // Reuse context for state persistence - language?: 'python' | 'javascript' | 'typescript'; - timeout?: number; // Execution timeout in ms (default: 60000) -} - -interface ExecutionResult { - code: string; - logs: { stdout: string[]; stderr: string[] }; - results: RichOutput[]; // text, html, png, json, etc. - error?: { name: string; value: string; traceback: string[] }; - executionCount: number; -} +await terminal.connect(request, { cursor?; cols?; rows? }) +await terminal.write(data: Uint8Array) +await terminal.resize(cols, rows) +await terminal.output({ since?; replay?; follow?; signal? }) +await terminal.interrupt() +await terminal.terminate() ``` -## Files - -```typescript -await sandbox.writeFile(path: string, content: string | Uint8Array): Promise -await sandbox.readFile(path: string): Promise<{ content: string }> -await sandbox.mkdir(path: string, options?: { recursive?: boolean }): Promise -await sandbox.listFiles(path: string): Promise -await sandbox.deleteFile(path: string): Promise - -interface FileMetadata { - name: string; - path: string; - isDirectory: boolean; - size: number; - modifiedAt: string; -} -``` +## Interpreter (extension) -## Ports +```ts +import { withInterpreter } from "@cloudflare/sandbox/interpreter"; +// subclass: interpreter = withInterpreter(this) -```typescript -await sandbox.exposePort(port: number): Promise<{ url: string; token: string }> -await sandbox.unexposePort(port: number): Promise -await sandbox.listPorts(): Promise +await sandbox.interpreter.createCodeContext({ language?, cwd? }) +await sandbox.interpreter.runCode(code, { context?, language?, onStdout?, ... }) +await sandbox.interpreter.runCodeStream(code, { context?, language? }) // SSE; callbacks not used +await sandbox.interpreter.listCodeContexts() +await sandbox.interpreter.deleteCodeContext(id) ``` -## Error Handling +## Environment -Errors include context about the operation: - -```typescript -try { - await sandbox.exec('invalid-command'); -} catch (error) { - // error.message includes command and sandbox context -} +```ts +await sandbox.setEnvVars(Record) // undefined removes +// plus env on exec / createTerminal ``` -For `runCode()`, check `result.error` instead of catching: +Non-secret config only. Secrets: Worker + outbound handlers. -```typescript -const result = await sandbox.runCode('1/0', { language: 'python' }); -if (result.error) { - console.error(result.error.name); // "ZeroDivisionError" -} -``` +## Errors (common) + +`ContainerUnavailableError`, `OperationInterruptedError`, `RPCTransportError`, `StaleProcessHandleError`, `StaleTerminalHandleError`, process wait/spawn errors — see https://developers.cloudflare.com/sandbox/1-0-preview/api/errors/ diff --git a/skills/sandbox-sdk/references/examples.md b/skills/sandbox-sdk/references/examples.md index e02b54b..39cb0ca 100644 --- a/skills/sandbox-sdk/references/examples.md +++ b/skills/sandbox-sdk/references/examples.md @@ -1,49 +1,15 @@ -# Sandbox SDK Examples +# Sandbox SDK examples -All examples: https://github.com/cloudflare/sandbox-sdk/tree/main/examples +Branch aligned with preview: https://github.com/cloudflare/sandbox-sdk/tree/next/examples -## Example Index +| Example | Use case | +| ------- | -------- | +| `minimal` | Basic `@next` setup | +| `code-interpreter` | `withInterpreter` | +| `openai-agents` | OpenAI adapters | +| `opencode` | OpenCode extension | +| `claude-code` / `codex` | Agent harnesses + argv `exec` / git via exec | +| `collaborative-terminal` / `s3-mount` | Terminals | +| `authentication` | Multi-user sandbox IDs | -| Example | Use Case | Key File | -|---------|----------|----------| -| `minimal` | Basic setup, exec, file ops | `src/index.ts` | -| `code-interpreter` | AI code execution with Workers AI | `src/index.ts` | -| `openai-agents` | OpenAI Agents SDK integration | `src/index.ts` | -| `opencode` | OpenCode agent integration | `src/index.ts` | -| `claude-code` | Claude Code agent integration | `src/index.ts` | -| `typescript-validator` | TypeScript compilation/validation | `src/index.ts` | -| `authentication` | Auth patterns for sandboxes | `src/index.ts` | - -## When to Use Which Example - -| Building | Start With | -|----------|------------| -| AI code execution | `code-interpreter` | -| Agent with shell + file editing | `openai-agents` | -| Basic command execution | `minimal` | -| Code validation service | `typescript-validator` | -| Multi-user sandboxes | `authentication` | - -## Common Patterns from Examples - -**Sandbox per user/session** (from `openai-agents`): -```typescript -const sandbox = getSandbox(env.Sandbox, `session-${sessionId}`); -``` - -**Code context reuse** (from `code-interpreter`): -```typescript -const pythonCtx = await sandbox.createCodeContext({ language: 'python' }); -const result = await sandbox.runCode(code, { context: pythonCtx }); -``` - -**Resource cleanup** (from `code-interpreter`): -```typescript -try { - // ... use sandbox -} finally { - await sandbox.destroy(); -} -``` - -Fetch the full example source when implementing similar patterns. +Prefer examples on the **`next`** branch when building for `@cloudflare/sandbox@next`. diff --git a/skills/sandbox-v1-migration/SKILL.md b/skills/sandbox-v1-migration/SKILL.md new file mode 100644 index 0000000..b24b93c --- /dev/null +++ b/skills/sandbox-v1-migration/SKILL.md @@ -0,0 +1,301 @@ +--- +name: sandbox-v1-migration +description: Use when migrating a Cloudflare Sandbox SDK app from the stable package to @cloudflare/sandbox@next (Sandbox SDK 1.0 preview), or when stable APIs such as string exec, sessions, execStream, startProcess, sandbox.terminal, gitCheckout, or SANDBOX_TRANSPORT appear in code that should move to 1.0. +--- + +# Migrate to Sandbox SDK 1.0 preview (`@next`) + +Portable migration runbook for agents installed via [cloudflare/skills](https://github.com/cloudflare/skills) / [Agent setup](https://developers.cloudflare.com/agent-setup/). Enough to audit, edit, deploy, and validate without fetching docs. Human docs deepen edge cases. + +Prefer `@next` for **new** work (`sandbox-sdk` skill). For migrations: do not force production cutover without the user agreeing. For **stable-only** deprecated-API cleanup (not full 1.0), use **`sandbox-2026-deprecation`** first if needed. + +**Human docs:** https://developers.cloudflare.com/sandbox/1-0-preview/migrate/ · https://developers.cloudflare.com/sandbox/1-0-preview/ +**Stable docs:** https://developers.cloudflare.com/sandbox/ + +## Workflow + +1. **Review** the rules and replacement map below. +2. **Audit** the codebase with the search; list every hit and its target shape. +3. **Clarify** with the user: cutover timing, bridge Worker, Python image, unclear call sites. +4. **Upgrade** package + image, apply code edits from this file, then deploy cutover. +5. **Validate** typecheck, smokes, and a second grep. + +Stop after any step that needs a user decision. + +## Hard rules + +- Worker npm package and container image must be the **same** `@next` line. Never mix `@next` Worker code with a stable image (or the reverse). +- Production cutover uses immediate container rollout (command below). Stable and `@next` control protocols are incompatible both ways; a gradual container rollout leaves a broken mixed window. +- `await sandbox.exec(...)` means **process launched**, not **command finished**. +- Argv is passed to the process **as-is** (no implicit shell, no shell-escaping of argv). Shell syntax needs an explicit shell binary. +- Process handles have **no stdin**. Interactive input → terminals. +- Observation `timeout` / `AbortSignal` on `output` / waits / `logs` cancel **only that wait**. They do **not** kill the process. Use `kill(signal?)` (numeric; default `15`) or `exec` remote `timeout`. +- Do **not** use one retry loop for every error (table below). +- Do **not** invent APIs: no `gitCheckout` on core, no process stdin, no string-exec completion helper, no custom extension authoring guide. +- No internal release calendars in user-facing text. +- Prefer installed `@next` TypeScript types when resolving API details. +- The self-deployed bridge is not part of the preview. Keep bridge deployments, clients, the Worker package, and the container image on the stable release line. + +## 1. Review — what changes + +| Stable | Preview | +| ------ | ------- | +| `SANDBOX_TRANSPORT` / `transport` / `setTransport` | Remove — RPC only | +| `await sandbox.exec("cmd")` → buffered result | `await sandbox.exec(argv)` → handle, then `output` / waits | +| `execStream` / `startProcess` | Same handle: `logs`, `waitFor*`, `kill` | +| Default / named sessions | Gone — `cwd`/`env` per launch, or one shell script argv | +| `sandbox.terminal(request)` / session terminal | `createTerminal` + `terminal.connect(request)` | +| xterm `sessionId` | `terminalId` | +| Interpreter methods on `Sandbox` | `withInterpreter` → `sandbox.interpreter.*` | +| `gitCheckout` | argv `git` via `exec` | +| String kill signals | Numeric only | +| Files, mounts, backups, ports, tunnels, `proxyToSandbox` | Mostly unchanged (ignore session/transport bits on stable pages) | + +## 2. Audit + +```sh +rg 'SANDBOX_TRANSPORT|transport:|setTransport|enableDefaultSession|createSession|getSession|deleteSession|execStream\(|startProcess\(|killProcess\(|sandbox\.terminal\(|sessionId|gitCheckout\(|SandboxTransport|ExecutionSession' +``` + +Also search: string `exec(`, patterns of `cd` then a later `exec`, bare `createCodeContext` / `runCode` on `Sandbox`. + +For each hit, note the replacement from this file. Ask the user before guessing. + +## 3. Clarify (ask when needed) + +- OK to cut production with immediate container rollout (live container processes/terminals/streams stop)? +- Self-deployed bridge Worker present? Leave it on the stable release line; this runbook is for Worker SDK apps only. +- Python interpreter → must use **`-python`** image variant? +- Any call site not covered below? + +## 4. Upgrade + +### 4.1 Package and image + +```sh +npm install @cloudflare/sandbox@next +# or pnpm / yarn equivalent +``` + +Dockerfile / container must match, for example: + +```dockerfile +FROM cloudflare/sandbox:next +# Python interpreter: +# FROM cloudflare/sandbox:next-python +``` + +Use the same exact prerelease tag on Worker and image when not on the floating `next` tag. + +### 4.2 Remove transport + +Delete `SANDBOX_TRANSPORT`, `transport` on `getSandbox()`, `setTransport()`, and `SandboxTransport` types. No replacement setting. + +### 4.3 Command execution + +**Buffered command** + +```ts +// Stable +const result = await sandbox.exec("npm test"); +console.log(result.stdout, result.exitCode); + +// Preview +const process = await sandbox.exec(["/bin/bash", "-lc", "npm test"]); +// single binary without shell: +// const process = await sandbox.exec(["npm", "test"], { cwd: "/workspace/app" }); +const result = await process.output({ encoding: "utf8" }); +console.log(result.stdout, result.exitCode); +``` + +- Default `output()` streams are **bytes** (`Uint8Array`). Pass `{ encoding: "utf8" }` for strings. +- Depth: https://developers.cloudflare.com/sandbox/1-0-preview/api/processes/ + +**Background / streaming** + +```ts +// Stable-ish: startProcess / execStream +// Preview: +const server = await sandbox.exec(["/bin/bash", "-lc", "npm run dev"], { + cwd: "/workspace/app", +}); +await server.waitForPort(3000, { timeout: 60_000 }); +// HTTP readiness: { mode: "http", path: "/health", timeout: 60_000 } +// Default waitForPort mode is tcp. + +const stream = await server.logs({ follow: true, replay: true }); +// consume stream... +await server.kill(); // default signal 15 +``` + +**Shell state / cwd / env** + +```ts +// Stable (broken assumption on preview) +await sandbox.exec("cd /app"); +await sandbox.exec("npm test"); + +// Preview — one shot +await sandbox.exec(["/bin/bash", "-lc", "cd /app && npm test"]); +// or +await sandbox.exec(["npm", "test"], { cwd: "/app", env: { NODE_ENV: "test" } }); +``` + +- `setEnvVars` still exists for sandbox-wide **non-secret** config. +- Do **not** put live API keys in `setEnvVars` or launch `env`. Keep secrets in the Worker; use outbound handlers when processes call external APIs: https://developers.cloudflare.com/sandbox/guides/outbound-traffic/ +- Depth: https://developers.cloudflare.com/sandbox/1-0-preview/environment/ + +**Timeouts** + +| Goal | API | +| ---- | --- | +| Limit process lifetime | `exec(argv, { timeout })` → completion may have `timedOut: true` | +| Limit how long you wait | `timeout` / `signal` on `output` / `waitFor*` / `logs` — does not kill | + +### 4.4 Drop sessions + +Remove `createSession`, `getSession`, `deleteSession`, `enableDefaultSession`, and `sessionId` options. Isolate users with **separate sandbox IDs**, not sessions inside one sandbox. + +### 4.5 Terminals + +```ts +// Stable +return sandbox.terminal(request); + +// Preview — create once, store id with sandbox id +const terminal = await sandbox.createTerminal({ + command: ["bash"], + cwd: "/workspace", +}); +// later request / WebSocket upgrade: +const t = await sandbox.getTerminal(terminal.id); +if (!t) { + // container gone or unknown id — createTerminal again from app state + return new Response("terminal gone", { status: 410 }); +} +return t.connect(request, { cursor, cols, rows }); +``` + +Browser `@cloudflare/sandbox/xterm`: pass `terminalId` (not `sessionId`) when building the WebSocket URL. + +Depth: https://developers.cloudflare.com/sandbox/1-0-preview/terminals/ + +### 4.6 Interpreter + +```ts +// Stable: sandbox.createCodeContext / sandbox.runCode +// Preview: +import { Sandbox as BaseSandbox } from "@cloudflare/sandbox"; +import { withInterpreter } from "@cloudflare/sandbox/interpreter"; + +export class Sandbox extends BaseSandbox { + interpreter = withInterpreter(this); +} + +const ctx = await sandbox.interpreter.createCodeContext({ language: "python" }); +const result = await sandbox.interpreter.runCode('print("hi")', { context: ctx }); +// result is plain serializable ExecutionResult +``` + +Python requires the **`-python`** image. Same `@next` Worker + image line. + +Depth: https://developers.cloudflare.com/sandbox/1-0-preview/interpreter/ + +### 4.7 Git + +```ts +// Stable +await sandbox.gitCheckout(repoUrl, { targetDir: "/workspace/repo" }); + +// Preview +const clone = await sandbox.exec( + ["git", "clone", "--depth", "1", "--", repoUrl, "/workspace/repo"], + { cwd: "/workspace" }, +); +const result = await clone.output({ encoding: "utf8" }); +if (result.exitCode !== 0) throw new Error(result.stderr); +``` + +### 4.8 Long-running work across requests + +Process IDs are **not** durable jobs. Same sandbox ID ≠ same container forever. + +**Store:** argv (or script), `cwd`, `env`, app checkpoint — and optionally `process.id` while it might still be alive. + +```ts +// Later request — prefer fresh lookup +const existing = processId ? await sandbox.getProcess(processId) : null; +if (existing) { + const stream = await existing.logs({ since: cursor, replay: true, follow: true }); + // ... +} else { + // null: no container or unknown id — relaunch from stored job + const p = await sandbox.exec(storedArgv, { cwd: storedCwd, env: storedEnv }); + // save p.id +} +// Reusing an old handle object after replace → StaleProcessHandleError; relaunch. +``` + +Depth: https://developers.cloudflare.com/sandbox/1-0-preview/processes/ + +### 4.9 Errors (minimum handlers) + +| Error | What to do | +| ----- | ---------- | +| `ContainerUnavailableError` | Container did not start the work — back off (`retryAfterMs` if set), retry **new** operation | +| `OperationInterruptedError` | Work may have started — read `reason` / `retryable`; inspect before repeating side effects | +| `RPCTransportError` | Lost contact mid-call — later calls may work; **this** call may already have run | +| `StaleProcessHandleError` / `StaleTerminalHandleError` | Previous container — relaunch from stored work | +| `ProcessWaitTimeoutError` / `ProcessAbortedError` | Wait ended only — process may still run | +| `RuntimeControlProtocolError` / broken image after deploy | Worker and image not on same `@next` line — fix deploy, not slow-start retry | + +Prefer `instanceof` on classes from `@cloudflare/sandbox`. +Depth: https://developers.cloudflare.com/sandbox/1-0-preview/errors/ + +`getProcess` / `getTerminal` / `list*` do **not** start a container; they return `null` / `[]` when none is running. + +### 4.10 Bridge + +This runbook covers Worker SDK applications on `@next`. + +The self-deployed bridge stays on the stable release line. Keep its Worker package, container image, and HTTP clients on matching stable versions. Do not pair a bridge deployment with `@cloudflare/sandbox@next`. + +### 4.11 Deploy cutover + +Finish code on a branch/staging first. Production is **one** deploy of matching Worker + image: + +```sh +npx wrangler deploy --containers-rollout=immediate +``` + +- Does **not** clear `rollout_active_grace_period`. Leave grace at default `0` for cutover (or set `0` if raised). +- Before cutover: finish or stop work you must keep. +- After cutover: treat pre-deploy process/terminal IDs as invalid; start work again; run Validate. + +Depth: https://developers.cloudflare.com/sandbox/1-0-preview/migrate/ +Containers rollouts: https://developers.cloudflare.com/containers/platform-details/rollouts/ + +## 5. Validate + +1. Lockfile + Dockerfile both on the same `@next` line +2. Typecheck against `@next` +3. Smoke argv `exec` + `output({ encoding: "utf8" })` +4. Smoke long process (`waitForPort` / `logs`) if used +5. Smoke terminal create + `connect` if used +6. Smoke interpreter if used (correct image variant) +7. Error handling distinguishes unavailable / interrupted-RPC / stale / local wait +8. No live secrets in sandbox env +9. Grep again for removed Worker SDK APIs +10. Production cutover used `--containers-rollout=immediate` + +## Red flags — stop and fix + +- Mixing `@next` Worker with stable image (or reverse) +- Gradual container rollout for this control-plane cutover +- Treating `await exec` as command completion +- Assuming `cd` / exports persist across `exec` calls +- One retry wrapper for every sandbox error +- Inventing `gitCheckout`, process stdin, or undocumented extension APIs +- Keeping pre-cutover process/terminal IDs after deploy +- Forcing production cutover without user agreement +- Putting live secrets in `setEnvVars` / launch `env` From 45c187dbe96743876221dae253d7f8da5b9a67ad Mon Sep 17 00:00:00 2001 From: Naresh Date: Fri, 7 Aug 2026 17:32:13 +0100 Subject: [PATCH 2/5] Split Sandbox skills by package line Agents need separate build paths for stable and @next so they do not mix incompatible exec models. Keep migration as its own performable upgrade skill. --- README.md | 6 +- skills/sandbox-2026-deprecation/SKILL.md | 43 ---- skills/sandbox-migrate-to-next/SKILL.md | 237 ++++++++++++++++++ skills/sandbox-sdk/SKILL.md | 134 ++++------ skills/sandbox-stable/SKILL.md | 133 ++++++++++ skills/sandbox-v1-migration/SKILL.md | 301 ----------------------- 6 files changed, 424 insertions(+), 430 deletions(-) delete mode 100644 skills/sandbox-2026-deprecation/SKILL.md create mode 100644 skills/sandbox-migrate-to-next/SKILL.md create mode 100644 skills/sandbox-stable/SKILL.md delete mode 100644 skills/sandbox-v1-migration/SKILL.md diff --git a/README.md b/README.md index 59e9af9..562eca1 100644 --- a/README.md +++ b/README.md @@ -57,9 +57,9 @@ Skills are contextual and auto-loaded based on your conversation. When a request | cloudflare | Comprehensive platform skill covering Workers, Pages, storage (KV, D1, R2), AI (Workers AI, Vectorize, Agents SDK), networking (Tunnel, Spectrum), security (WAF, DDoS), and IaC (Terraform, Pulumi) | | agents-sdk | Building stateful AI agents with state, scheduling, RPC, MCP servers, email, and streaming chat | | durable-objects | Stateful coordination (chat rooms, games, booking), RPC, SQLite, alarms, WebSockets | -| sandbox-sdk | Secure code execution on Sandbox SDK; prefer `@cloudflare/sandbox@next` for new work | -| sandbox-v1-migration | Migrate a stable Sandbox app to `@cloudflare/sandbox@next` (1.0 preview) | -| sandbox-2026-deprecation | Clean up deprecated APIs while staying on the current stable Sandbox package | +| sandbox-sdk | Build on Sandbox SDK 1.0 preview (`@cloudflare/sandbox@next`); recommended for new projects | +| sandbox-stable | Build on the current stable `@cloudflare/sandbox` package | +| sandbox-migrate-to-next | Port a stable Sandbox app to `@cloudflare/sandbox@next` | | wrangler | Deploying and managing Workers, KV, R2, D1, Vectorize, Queues, Workflows | | web-perf | Auditing Core Web Vitals (FCP, LCP, TBT, CLS), render-blocking resources, network chains | | building-mcp-server-on-cloudflare | Building remote MCP servers with tools, OAuth, and deployment | diff --git a/skills/sandbox-2026-deprecation/SKILL.md b/skills/sandbox-2026-deprecation/SKILL.md deleted file mode 100644 index 04372ba..0000000 --- a/skills/sandbox-2026-deprecation/SKILL.md +++ /dev/null @@ -1,43 +0,0 @@ ---- -name: sandbox-2026-deprecation -description: Use when cleaning up a Cloudflare Sandbox SDK app that stays on the current stable package—HTTP/WebSocket transports, exposePort, default sessions, stream-specific helpers, or other APIs deprecated on stable. Not for full migration to @next (use sandbox-v1-migration). ---- - -# Sandbox SDK stable deprecation cleanup - -For apps that **remain on the current stable** `@cloudflare/sandbox` package and must leave deprecated features. Installed via [cloudflare/skills](https://github.com/cloudflare/skills) / [Agent setup](https://developers.cloudflare.com/agent-setup/). - -**Not** the path to Sandbox SDK 1.0. For `@cloudflare/sandbox@next`, use **`sandbox-v1-migration`**. - -**Docs:** [Deprecation guide](https://developers.cloudflare.com/sandbox/guides/2026-deprecation/) · [Changelog](https://developers.cloudflare.com/changelog/sandbox/2026-06-09-deprecating-sandbox-sdk-features/) - -## Checklist - -1. Update `@cloudflare/sandbox` and the matching container image before changing runtime config. -2. Search: - - ```sh - rg 'SANDBOX_TRANSPORT|transport:|exposePort\(|enableDefaultSession|execStream\(|readFileStream|writeFileStream' - ``` - -3. Switch every sandbox to **RPC** (`SANDBOX_TRANSPORT=rpc` or `getSandbox(..., { transport: "rpc" })`). -4. Replace `exposePort()` with `sandbox.tunnels.get()` when tunnels fit. Keep `exposePort` + `proxyToSandbox` if the Worker must authenticate or rewrite responses. -5. Set `enableDefaultSession: false` (requires SDK **0.10.3+**). Use explicit `createSession()` when shell state must persist across commands on stable. -6. Move stream-specific file/command helpers to base `readFile` / `writeFile` / `exec` where streaming is supported (often needs RPC). -7. Desktop demo APIs are removed on recent stable lines—do not restore them; rebuild in-sandbox computer-use only if the product still needs it. -8. Deploy and smoke-test commands, files, public URLs, and any remaining explicit sessions. - -## Replacements - -| Deprecated | Replacement | -| ---------- | ----------- | -| HTTP / WebSocket transport | RPC | -| `exposePort()` (typical public URL) | `sandbox.tunnels.get()` | -| Default sessions | `enableDefaultSession: false` + explicit sessions or per-command `cwd`/`env` | -| Stream-only helpers | Base APIs with streaming support | - -## Notes - -- Tunnels and large/binary streaming expect RPC—configure transport first. -- If `cd` must carry across `exec` on **stable**, use an explicit session with `cwd` (stable-only; gone on `@next`). -- After this cleanup, plan **`sandbox-v1-migration`** when moving to 1.0. diff --git a/skills/sandbox-migrate-to-next/SKILL.md b/skills/sandbox-migrate-to-next/SKILL.md new file mode 100644 index 0000000..a7579e3 --- /dev/null +++ b/skills/sandbox-migrate-to-next/SKILL.md @@ -0,0 +1,237 @@ +--- +name: sandbox-migrate-to-next +description: Use when porting a Cloudflare Sandbox app from stable @cloudflare/sandbox to @cloudflare/sandbox@next (Sandbox SDK 1.0 preview), or when the user asks to migrate or upgrade to Sandbox 1.0 / @next. Not for day-to-day stable work (sandbox-stable) or new @next apps (sandbox-sdk). +--- + +# Migrate to Sandbox SDK 1.0 preview (`@next`) + +**Perform** the port from the current stable package to `@cloudflare/sandbox@next`. Follow the steps in order. Human depth: [Migrate](https://developers.cloudflare.com/sandbox/1-0-preview/migrate/) · [1.0 preview](https://developers.cloudflare.com/sandbox/1-0-preview/). + +We recommend **new** projects start on `@next` (**`sandbox-sdk`**). Existing apps should migrate **when you can**, so you are ready when 1.0 becomes the stable release. The main [Sandbox docs](https://developers.cloudflare.com/sandbox/) still describe today’s stable package (**`sandbox-stable`**). + +Do **not** force production cutover without the user agreeing. + +**Not this skill:** day-to-day stable feature work → **`sandbox-stable`**. New `@next` work → **`sandbox-sdk`**. Deprecated-API cleanup **without** moving to `@next` → [2026 deprecation guide](https://developers.cloudflare.com/sandbox/guides/2026-deprecation/) on the stable package first if needed. + +## Workflow + +1. **Review** the hard rules and replacement map below (and the migrate doc if needed). +2. **Audit** the codebase; list every hit and its target shape. +3. **Clarify** uncertainty with the user (cutover timing, bridge, Python image, unclear call sites). +4. **Upgrade** package + image and apply code changes. +5. **Validate** typecheck, smokes, and a second grep. + +Stop after any step that needs a user decision. + +## Hard rules + +- Worker package and container image must be the **same** `@next` line. +- Production cutover uses **immediate** container rollout (`--containers-rollout=immediate`). Stable and `@next` control protocols are incompatible both ways; gradual rollout leaves a broken mixed window. In-flight container work can stop. +- `await sandbox.exec(...)` means the process **started**, not that the command **finished**. +- Argv is passed **as-is** (no implicit shell). Shell syntax needs an explicit shell binary. +- Process handles have **no stdin**. Interactive input → terminals. +- Observation `timeout` / `AbortSignal` cancel **only that wait**. They do **not** kill the process. +- Do **not** use one retry loop for every error. +- Do **not** invent APIs (`gitCheckout` on core, process stdin, string-exec completion helper). +- Prefer installed `@next` types over guesses. +- Self-deployed bridge is not on the preview — keep bridge Worker, image, and clients on **stable**. + +## Replacement map + +| Stable | Preview | +| ------ | ------- | +| `SANDBOX_TRANSPORT` / `transport` / `setTransport` | Remove — RPC only | +| `await sandbox.exec("cmd")` → buffered result | `await sandbox.exec(argv)` → handle, then `output` / waits | +| `execStream` / `startProcess` | Same handle: `logs`, `waitFor*`, `kill` | +| Default / named sessions | Gone — `cwd`/`env` per launch, or one shell script | +| `sandbox.terminal(request)` / session terminal | `createTerminal` + `terminal.connect(request)` | +| xterm `sessionId` | `terminalId` | +| Interpreter on `Sandbox` | `withInterpreter` → `sandbox.interpreter.*` | +| `gitCheckout` | argv `git` via `exec` | +| String kill signals | Numeric only | +| Files, mounts, backups, ports, tunnels, `proxyToSandbox` | Mostly unchanged (ignore session/transport bits) | + +## Audit + +```sh +rg 'SANDBOX_TRANSPORT|transport:|setTransport|enableDefaultSession|createSession|getSession|deleteSession|execStream\(|startProcess\(|killProcess\(|sandbox\.terminal\(|sessionId|gitCheckout\(|SandboxTransport|ExecutionSession' +``` + +Also: string `exec(`, `cd` then a later `exec`, bare `createCodeContext` / `runCode` on `Sandbox`. + +## Clarify (ask when needed) + +- OK to cut production with immediate container rollout (live processes/terminals/streams may stop)? +- Self-deployed bridge present? Leave it on stable. +- Python interpreter → **`-python`** image variant? +- Call sites not covered below? + +## Upgrade + +### Package and image + +```sh +npm install @cloudflare/sandbox@next +``` + +```dockerfile +FROM cloudflare/sandbox:next +# Python interpreter: cloudflare/sandbox:next-python +``` + +Use the same prerelease tag on Worker and image when not on floating `next`. + +### Transport + +Delete `SANDBOX_TRANSPORT`, `transport` on `getSandbox()`, `setTransport()`, `SandboxTransport`. No replacement setting. + +### Commands + +```ts +// Stable +const result = await sandbox.exec("npm test"); + +// Preview +const process = await sandbox.exec(["/bin/bash", "-lc", "npm test"]); +// or: await sandbox.exec(["npm", "test"], { cwd: "/workspace/app" }); +const result = await process.output({ encoding: "utf8" }); +``` + +Default `output()` streams are **bytes**. Pass `{ encoding: "utf8" }` for strings. + +```ts +const server = await sandbox.exec(["/bin/bash", "-lc", "npm run dev"], { + cwd: "/workspace/app", +}); +await server.waitForPort(3000, { timeout: 60_000 }); // default mode: tcp +const stream = await server.logs({ follow: true, replay: true }); +await server.kill(); // default 15 +``` + +```ts +// One shot — do not rely on cd across separate exec calls +await sandbox.exec(["/bin/bash", "-lc", "cd /app && npm test"]); +// or +await sandbox.exec(["npm", "test"], { cwd: "/app", env: { NODE_ENV: "test" } }); +``` + +- `setEnvVars` remains for sandbox-wide **non-secret** config. +- Do **not** put live API keys in `setEnvVars` or launch `env`. [Outbound traffic](https://developers.cloudflare.com/sandbox/guides/outbound-traffic/). + +| Goal | API | +| ---- | --- | +| Limit process lifetime | `exec(argv, { timeout })` | +| Limit how long you wait | `timeout` / `signal` on `output` / `waitFor*` / `logs` — does not kill | + +### Sessions + +Remove `createSession`, `getSession`, `deleteSession`, `enableDefaultSession`, `sessionId` options. Isolate users with **separate sandbox IDs**. + +### Terminals + +```ts +const terminal = await sandbox.createTerminal({ + command: ["bash"], + cwd: "/workspace", +}); +const t = await sandbox.getTerminal(terminal.id); +if (!t) return new Response("terminal gone", { status: 410 }); +return t.connect(request, { cursor, cols, rows }); +``` + +Browser `@cloudflare/sandbox/xterm`: pass `terminalId` (not `sessionId`). + +### Interpreter + +```ts +import { Sandbox as BaseSandbox } from "@cloudflare/sandbox"; +import { withInterpreter } from "@cloudflare/sandbox/interpreter"; + +export class Sandbox extends BaseSandbox { + interpreter = withInterpreter(this); +} + +const ctx = await sandbox.interpreter.createCodeContext({ language: "python" }); +const result = await sandbox.interpreter.runCode('print("hi")', { context: ctx }); +``` + +Python requires the **`-python`** image. Same `@next` Worker + image line. + +### Git + +```ts +const clone = await sandbox.exec( + ["git", "clone", "--depth", "1", "--", repoUrl, "/workspace/repo"], + { cwd: "/workspace" }, +); +const result = await clone.output({ encoding: "utf8" }); +if (result.exitCode !== 0) throw new Error(result.stderr); +``` + +### Work across requests + +Process IDs are **not** durable jobs. Store argv (or script), `cwd`, `env`, and app checkpoint — optionally `process.id` while it might still be alive. + +```ts +const existing = processId ? await sandbox.getProcess(processId) : null; +if (existing) { + await existing.logs({ since: cursor, replay: true, follow: true }); +} else { + const p = await sandbox.exec(storedArgv, { cwd: storedCwd, env: storedEnv }); + // save p.id +} +``` + +`getProcess` / `getTerminal` / `list*` do not start a container; they return `null` / `[]` when none is running. + +### Errors + +| Error | What to do | +| ----- | ---------- | +| `ContainerUnavailableError` | Back off; retry **new** operation | +| `OperationInterruptedError` | Work may have started — inspect before repeating side effects | +| `RPCTransportError` | This call may already have run | +| `StaleProcessHandleError` / `StaleTerminalHandleError` | Relaunch from stored work | +| `ProcessWaitTimeoutError` / `ProcessAbortedError` | Wait ended only — process may still run | +| `RuntimeControlProtocolError` | Worker and image not on same `@next` line — fix deploy | + +Prefer `instanceof` on classes from `@cloudflare/sandbox`. + +### Bridge + +Leave self-deployed bridge on the stable release line. Do not pair bridge with `@cloudflare/sandbox@next`. + +### Deploy cutover + +Finish code on a branch/staging first. Production is **one** deploy of matching Worker + image: + +```sh +npx wrangler deploy --containers-rollout=immediate +``` + +- Does not clear `rollout_active_grace_period`. Leave grace at default `0` (or set `0` if raised). +- Before: finish or stop work you must keep. +- After: treat pre-deploy process/terminal IDs as invalid; start work again. + +## Validate + +1. Lockfile + Dockerfile on the same `@next` line +2. Typecheck against `@next` +3. Smoke argv `exec` + `output({ encoding: "utf8" })` +4. Smoke long process / terminal / interpreter if used +5. Error handling distinguishes unavailable / interrupted-RPC / stale / local wait +6. No live secrets in sandbox env +7. Grep again for removed APIs +8. Production cutover used `--containers-rollout=immediate` + +## Red flags — stop and fix + +- Mixing `@next` Worker with stable image (or reverse) +- Gradual container rollout for this control-plane cutover +- Treating `await exec` as command completion +- Assuming `cd` / exports persist across `exec` calls +- One retry wrapper for every sandbox error +- Inventing `gitCheckout`, process stdin, or undocumented extension APIs +- Keeping pre-cutover process/terminal IDs after deploy +- Forcing production cutover without user agreement +- Putting live secrets in `setEnvVars` / launch `env` diff --git a/skills/sandbox-sdk/SKILL.md b/skills/sandbox-sdk/SKILL.md index c7b8118..7ca453f 100644 --- a/skills/sandbox-sdk/SKILL.md +++ b/skills/sandbox-sdk/SKILL.md @@ -1,54 +1,58 @@ --- name: sandbox-sdk -description: Build apps with Cloudflare Sandbox SDK for secure code execution. Use for new sandboxes, AI code execution, interpreters, CI-like jobs, and interactive environments. Prefer @cloudflare/sandbox@next (Sandbox SDK 1.0 preview) for new work. Load sandbox-v1-migration when moving a stable app to @next; load sandbox-2026-deprecation for stable-only cleanup of transports, exposePort, and default sessions. +description: Use when building or changing Cloudflare Sandbox apps on @cloudflare/sandbox@next (Sandbox SDK 1.0 preview)—code execution, AI runners, interpreters, CI-like jobs, terminals, mounts, tunnels, or preview URLs. Not for the default stable package (use sandbox-stable) or for porting stable to @next (use sandbox-migrate-to-next). --- -# Cloudflare Sandbox SDK +# Cloudflare Sandbox SDK (`@next`) Isolated Linux environments on [Cloudflare Containers](https://developers.cloudflare.com/containers/), driven from Workers. -## Choose the right track +This skill is the **1.0 preview** line: `@cloudflare/sandbox@next` and a matching `cloudflare/sandbox:next` image. We recommend this line for **new projects**. Existing apps on the default package should keep using **`sandbox-stable`** until they are ready to move; then use **`sandbox-migrate-to-next`**. -| Situation | Package | Skill / docs | -| --------- | ------- | ------------ | -| **New project** | `@cloudflare/sandbox@next` | This skill + [1.0 preview](https://developers.cloudflare.com/sandbox/1-0-preview/) | -| **Migrate stable → 1.0** | `@next` | **`sandbox-v1-migration`** + [Migrate](https://developers.cloudflare.com/sandbox/1-0-preview/migrate/) | -| **Stay on stable; remove deprecated APIs** | current stable | **`sandbox-2026-deprecation`** + [2026 deprecation guide](https://developers.cloudflare.com/sandbox/guides/2026-deprecation/) | -| **Stable-only maintenance** | current stable | [Main Sandbox docs](https://developers.cloudflare.com/sandbox/) | +Prefer preview docs and installed `@next` types over memory. Stable and `@next` APIs differ. -Do not mix a preview Worker package with a stable container image (or the reverse). +## Confirm the package line -**Agent setup (install these skills):** [Agent setup](https://developers.cloudflare.com/agent-setup/) · [cloudflare/skills](https://github.com/cloudflare/skills) +Before writing code, check the app: -## Retrieval (prefer docs over memory) +- Dependency is `@cloudflare/sandbox@next` (or another preview tag), **and** +- Container image matches (for example `cloudflare/sandbox:next` or `next-python`) + +| If you find… | Do this | +| ------------ | ------- | +| Default `@cloudflare/sandbox` (no `@next`) | Stop. Use **`sandbox-stable`** and the [main Sandbox docs](https://developers.cloudflare.com/sandbox/). Do not apply `@next` APIs. | +| User wants to **port** stable → `@next` | Stop. Use **`sandbox-migrate-to-next`**. | +| Self-deployed **bridge** only | Bridge is not on the 1.0 preview line yet. Keep bridge on the stable package + image. [Bridge](https://developers.cloudflare.com/sandbox/bridge/). | + +Never mix an `@next` Worker package with a stable container image (or the reverse). + +Install skills: [Agent setup](https://developers.cloudflare.com/agent-setup/) · [cloudflare/skills](https://github.com/cloudflare/skills). + +## Retrieval | Topic | URL | | ----- | --- | -| 1.0 overview | https://developers.cloudflare.com/sandbox/1-0-preview/ | -| Get started (`@next`) | https://developers.cloudflare.com/sandbox/1-0-preview/get-started/ | +| Overview | https://developers.cloudflare.com/sandbox/1-0-preview/ | +| Get started | https://developers.cloudflare.com/sandbox/1-0-preview/get-started/ | | Processes | https://developers.cloudflare.com/sandbox/1-0-preview/processes/ | | Process API | https://developers.cloudflare.com/sandbox/1-0-preview/api/processes/ | | Terminals | https://developers.cloudflare.com/sandbox/1-0-preview/terminals/ | | Errors | https://developers.cloudflare.com/sandbox/1-0-preview/errors/ | | Environment | https://developers.cloudflare.com/sandbox/1-0-preview/environment/ | | Interpreter | https://developers.cloudflare.com/sandbox/1-0-preview/interpreter/ | -| Examples | https://github.com/cloudflare/sandbox-sdk/tree/next/examples | -| Stable docs | https://developers.cloudflare.com/sandbox/ | - -Fetch the relevant page when implementing. Installed `@next` types win over guesses. +| Examples (`next` branch) | https://github.com/cloudflare/sandbox-sdk/tree/next/examples | +| API quick ref | [references/api-quick-ref.md](references/api-quick-ref.md) | -## Install (`@next`) +## Install ```bash npm install @cloudflare/sandbox@next -docker info # required for local container dev +docker info # local container dev ``` -Container image must match the Worker line, for example `cloudflare/sandbox:next` (Python interpreter: `next-python` variant). - -## Required Worker shape +## Worker shape -Re-export `Sandbox` and bind the Durable Object / container in wrangler (see preview get-started). Minimal Worker: +Re-export `Sandbox` and bind the Durable Object / container (see get-started): ```ts import { getSandbox, proxyToSandbox, Sandbox } from "@cloudflare/sandbox"; @@ -71,37 +75,29 @@ export default { }; ``` -## Core model (`@next`) +## Core model -- `exec(argv)` takes an **argv array**, resolves when the process **starts**, returns a **handle**. -- Collect results with `output()`, `logs()`, `waitForExit()`, `waitForPort()`, `waitForLog()`, `kill(signal?)`. -- No implicit shell and no shell-escaping of argv. Shell syntax needs e.g. `["/bin/bash", "-lc", script]`. -- No hidden sessions: `cd` / `export` in one process do not affect the next. Pass `cwd` / `env` per launch or one shell script. +- `exec(argv)` takes an **argv** list and resolves when the process **starts**. It returns a **handle**. +- Observe or control with `output()`, `logs()`, `waitForExit()`, `waitForPort()`, `waitForLog()`, `kill(signal?)`. +- No implicit shell. Shell syntax needs an explicit shell, for example `["/bin/bash", "-lc", script]`. +- Each launch is independent. A `cd` in one `exec()` is not remembered in the next. Pass `cwd` and `env` when you need them. - Process handles have **no stdin**. Interactive PTY → `createTerminal` + `connect`. -- Local wait `timeout` / `AbortSignal` cancel the wait only — they do not kill the process. +- Wait `timeout` / `AbortSignal` cancel the **wait only** — they do not kill the process. Use `kill` or `exec` remote `timeout`. - `getProcess` / `listProcesses` do not start a container; they return `null` / `[]` when none is up. -- Process IDs are per **current container**, not forever for a sandbox ID. Store the job to relaunch after stop/replace. - -### Short command +- Process IDs live in the **current container**. Store the full job (argv, cwd, env) to relaunch after stop or replace. ```ts -const process = await sandbox.exec(["node", "--version"]); -const result = await process.output({ encoding: "utf8" }); -// result.stdout, result.exitCode, result.truncated, ... -``` - -### Long-running + readiness +const p = await sandbox.exec(["node", "--version"]); +const result = await p.output({ encoding: "utf8" }); -```ts const server = await sandbox.exec(["/bin/bash", "-lc", "npm run dev"], { cwd: "/workspace/app", }); await server.waitForPort(3000, { timeout: 60_000 }); // default mode: tcp -const stream = await server.logs({ follow: true, replay: true }); -await server.kill(); // numeric signal, default 15 +await server.kill(); // numeric signal; default 15 ``` -### Interpreter (extension) +### Interpreter ```ts import { Sandbox as BaseSandbox } from "@cloudflare/sandbox"; @@ -110,57 +106,29 @@ import { withInterpreter } from "@cloudflare/sandbox/interpreter"; export class Sandbox extends BaseSandbox { interpreter = withInterpreter(this); } - -const ctx = await sandbox.interpreter.createCodeContext({ language: "python" }); -const result = await sandbox.interpreter.runCode("print(1+1)", { context: ctx }); +// sandbox.interpreter.createCodeContext / runCode +// Python needs the -python image variant ``` -Python needs the **`-python`** image variant. - ### Terminals ```ts const terminal = await sandbox.createTerminal({ command: ["bash"] }); -// WebSocket upgrade: const t = await sandbox.getTerminal(terminal.id); if (t) return t.connect(request, { cursor }); ``` -### Files, mounts, ports, tunnels - -Still on the sandbox. Prefer main docs for signatures; ignore stable-only session/transport/`sandbox.terminal` bits. Preview env: [Environment variables](https://developers.cloudflare.com/sandbox/1-0-preview/environment/). - -Non-secret config only in `setEnvVars` / launch `env`. Live credentials: Worker secrets + [outbound traffic](https://developers.cloudflare.com/sandbox/guides/outbound-traffic/). - -### Errors (do not one-loop retry) - -| Error | Action | -| ----- | ------ | -| `ContainerUnavailableError` | Back off; retry as a **new** operation | -| `OperationInterruptedError` / `RPCTransportError` | Inspect; work may have started — no blind replay | -| `StaleProcessHandleError` / `StaleTerminalHandleError` | Relaunch from stored job | -| Local wait timeout / abort | Observation only; process may still run | - -See [Errors and recovery](https://developers.cloudflare.com/sandbox/1-0-preview/errors/). +### Env, URLs, errors -### Public URLs +- Non-secret config only in `setEnvVars` / launch `env`. Secrets stay in the Worker; use [outbound traffic](https://developers.cloudflare.com/sandbox/guides/outbound-traffic/) when processes call external APIs. +- Public URLs: `sandbox.tunnels` when it fits; `exposePort` + `proxyToSandbox` when the Worker must front the request. Production hostnames need wildcard DNS on a custom domain. +- Do not use one retry loop for every error. `ContainerUnavailableError` → back off, new operation. `OperationInterruptedError` / `RPCTransportError` → inspect (work may have started). Stale handle → relaunch from stored job. Local wait timeout → observation only. -Prefer `sandbox.tunnels` where appropriate; `exposePort` + `proxyToSandbox` when the Worker must front the request. Production preview hostnames need wildcard DNS on a custom domain. +## Common mistakes -### Bridge - -Self-deployed HTTP bridge is **not** on the 1.0 preview line yet. Keep bridge Worker + image + clients on **stable**. See [Bridge](https://developers.cloudflare.com/sandbox/bridge/). - -## Anti-patterns - -- String `exec` that expects buffered completion (stable) on `@next` -- Mixing `@next` Worker with stable image -- Assuming session/`cd` state across `exec` calls +- Using this skill on the default stable package +- Treating `await exec` as “command finished” +- Mixing `@next` Worker with a stable image +- Assuming shell state across `exec` calls - Putting API keys in sandbox env -- Inventing `gitCheckout` on core — use argv `git` via `exec` -- Using general knowledge instead of `@next` types + preview docs - -## Related skills - -- **`sandbox-v1-migration`** — stable → `@next` -- **`sandbox-2026-deprecation`** — deprecated APIs while staying on stable +- Inventing `gitCheckout` on core — run `git` via argv `exec` diff --git a/skills/sandbox-stable/SKILL.md b/skills/sandbox-stable/SKILL.md new file mode 100644 index 0000000..d1d99b9 --- /dev/null +++ b/skills/sandbox-stable/SKILL.md @@ -0,0 +1,133 @@ +--- +name: sandbox-stable +description: Use when building or changing Cloudflare Sandbox apps on the current stable @cloudflare/sandbox package (default npm tag)—commands, sessions, files, ports, tunnels, bridge, or deprecated-API cleanup while staying on stable. Not for @cloudflare/sandbox@next (use sandbox-sdk) or for porting to 1.0 (use sandbox-migrate-to-next). +--- + +# Cloudflare Sandbox SDK (stable package) + +Isolated Linux environments on [Cloudflare Containers](https://developers.cloudflare.com/containers/), driven from Workers. + +This skill is the **current stable** line: default `@cloudflare/sandbox` (today’s published package) and a **matching** stable container image. The main [Sandbox documentation](https://developers.cloudflare.com/sandbox/) describes this package. + +We recommend starting **new** projects on the [1.0 preview](https://developers.cloudflare.com/sandbox/1-0-preview/) (`@cloudflare/sandbox@next`) with **`sandbox-sdk`**. Existing apps can stay on stable and keep shipping. When you can, plan a move with **`sandbox-migrate-to-next`** so you are ready when 1.0 becomes the stable release. + +Prefer stable docs and installed package types over memory. Do not apply `@next` API shapes here. + +## Confirm the package line + +Before writing code, check the app: + +- Dependency is default `@cloudflare/sandbox` (**not** `@next` / preview tags), **and** +- Container image matches that stable line (not `cloudflare/sandbox:next`) + +| If you find… | Do this | +| ------------ | ------- | +| `@cloudflare/sandbox@next` (or preview image) | Stop. Use **`sandbox-sdk`**. | +| User wants to **port** to 1.0 / `@next` | Stop. Use **`sandbox-migrate-to-next`**. Do not half-apply preview APIs while the package is still stable. | +| Only cleaning deprecated stable APIs | Stay on this skill + [2026 deprecation guide](https://developers.cloudflare.com/sandbox/guides/2026-deprecation/). That is **not** a move to `@next`. | + +Never mix a stable Worker package with an `@next` container image (or the reverse). + +Install skills: [Agent setup](https://developers.cloudflare.com/agent-setup/) · [cloudflare/skills](https://github.com/cloudflare/skills). + +## Retrieval + +| Topic | URL | +| ----- | --- | +| Overview | https://developers.cloudflare.com/sandbox/ | +| Get started | https://developers.cloudflare.com/sandbox/get-started/ | +| Commands | https://developers.cloudflare.com/sandbox/api/commands/ | +| Sessions | https://developers.cloudflare.com/sandbox/concepts/sessions/ · https://developers.cloudflare.com/sandbox/api/sessions/ | +| Lifecycle / options | https://developers.cloudflare.com/sandbox/api/lifecycle/ · https://developers.cloudflare.com/sandbox/configuration/sandbox-options/ | +| Files | https://developers.cloudflare.com/sandbox/api/files/ | +| Ports / tunnels | https://developers.cloudflare.com/sandbox/api/ports/ · https://developers.cloudflare.com/sandbox/api/tunnels/ | +| Terminal | https://developers.cloudflare.com/sandbox/api/terminal/ · https://developers.cloudflare.com/sandbox/concepts/terminal/ | +| Code interpreter | https://developers.cloudflare.com/sandbox/api/interpreter/ · https://developers.cloudflare.com/sandbox/guides/code-execution/ | +| Environment | https://developers.cloudflare.com/sandbox/configuration/environment-variables/ | +| Bridge | https://developers.cloudflare.com/sandbox/bridge/ | +| Deprecated APIs (stay on stable) | https://developers.cloudflare.com/sandbox/guides/2026-deprecation/ | +| 1.0 preview (when ready to move) | https://developers.cloudflare.com/sandbox/1-0-preview/ | + +Fetch the relevant page when implementing. Installed **stable** types win over guesses. + +## Install + +```bash +npm install @cloudflare/sandbox +docker info # local container dev +``` + +Use a stable container image tag that matches your SDK release (see Dockerfile in the template / docs). Do not switch the image to `next` unless the Worker package moves too. + +## Worker shape + +```ts +import { getSandbox, proxyToSandbox, Sandbox } from "@cloudflare/sandbox"; + +export { Sandbox }; + +export default { + async fetch(request: Request, env: Env): Promise { + const proxy = await proxyToSandbox(request, env); + if (proxy) return proxy; + + const sandbox = getSandbox(env.Sandbox, "user-123"); + // Stable: exec takes a command string and resolves when the command finishes + const result = await sandbox.exec('python3 -c "print(2 + 2)"'); + return Response.json({ + output: result.stdout, + exitCode: result.exitCode, + success: result.success, + }); + }, +}; +``` + +See [Get started](https://developers.cloudflare.com/sandbox/get-started/) for wrangler / Dockerfile binding details. + +## Core model (stable) + +- `await sandbox.exec(command)` runs a **shell command string** and resolves when the command **finishes**, with buffered `stdout` / `stderr` / `exitCode`. +- Long-running or streaming work often uses **`startProcess`** / **`execStream`** (and related helpers) — not the `@next` single-handle model. Follow [Commands](https://developers.cloudflare.com/sandbox/api/commands/). +- **Sessions** can preserve working directory and env across commands (`createSession`, default session / `enableDefaultSession`). See [Sessions](https://developers.cloudflare.com/sandbox/concepts/sessions/). +- Interactive browser terminals often use **`sandbox.terminal(request)`** and related session/xterm helpers — [Terminal](https://developers.cloudflare.com/sandbox/api/terminal/). +- Code interpreter methods may live on `Sandbox` on stable — [Interpreter API](https://developers.cloudflare.com/sandbox/api/interpreter/). +- Files, mounts, ports, tunnels, backups, and lifecycle options: use main docs for signatures. +- Prefer **RPC** transport for tunnels and large/binary streaming. HTTP/WebSocket transports are deprecated — see cleanup below. +- Non-secret config in sandbox env; live credentials in the Worker. [Outbound traffic](https://developers.cloudflare.com/sandbox/guides/outbound-traffic/) when processes call external APIs. +- Production preview hostnames need wildcard DNS on a custom domain (`.workers.dev` is not enough for those patterns). + +```ts +// Short command (stable) +const result = await sandbox.exec("node --version"); +console.log(result.stdout, result.exitCode); + +// Background-style work — use stable APIs from the Commands docs, e.g. startProcess +// const proc = await sandbox.startProcess("node server.js"); +``` + +## Deprecated APIs while staying on stable + +If the app still uses HTTP/WebSocket transport, default sessions you want off, `exposePort` where tunnels fit, or stream-only helpers, follow the checklist in the [2026 deprecation guide](https://developers.cloudflare.com/sandbox/guides/2026-deprecation/). That cleanup **keeps** the stable package; it is not Sandbox SDK 1.0. + +```sh +rg 'SANDBOX_TRANSPORT|transport:|exposePort\(|enableDefaultSession|execStream\(|readFileStream|writeFileStream' +``` + +Update package + matching image first, switch to RPC, then adjust ports/sessions/streaming per that guide. + +## Bridge + +Self-deployed Sandbox bridge stays on the **stable** package and image. Keep Worker, image, and clients on the same stable line. [Bridge](https://developers.cloudflare.com/sandbox/bridge/). + +## When to upgrade + +Stable remains published and supported for existing apps. When the team has time, move to `@cloudflare/sandbox@next` with **`sandbox-migrate-to-next`** and the [Migrate guide](https://developers.cloudflare.com/sandbox/1-0-preview/migrate/). Do **not** force production cutover unless the user asked for it. + +## Common mistakes + +- Applying `@next` argv/`output()` handle APIs while the package is still stable +- Mixing stable Worker with `cloudflare/sandbox:next` image +- Treating “deprecated API cleanup” as “must move to `@next` today” +- Putting API keys in sandbox env +- Guessing APIs instead of stable docs + installed types diff --git a/skills/sandbox-v1-migration/SKILL.md b/skills/sandbox-v1-migration/SKILL.md deleted file mode 100644 index b24b93c..0000000 --- a/skills/sandbox-v1-migration/SKILL.md +++ /dev/null @@ -1,301 +0,0 @@ ---- -name: sandbox-v1-migration -description: Use when migrating a Cloudflare Sandbox SDK app from the stable package to @cloudflare/sandbox@next (Sandbox SDK 1.0 preview), or when stable APIs such as string exec, sessions, execStream, startProcess, sandbox.terminal, gitCheckout, or SANDBOX_TRANSPORT appear in code that should move to 1.0. ---- - -# Migrate to Sandbox SDK 1.0 preview (`@next`) - -Portable migration runbook for agents installed via [cloudflare/skills](https://github.com/cloudflare/skills) / [Agent setup](https://developers.cloudflare.com/agent-setup/). Enough to audit, edit, deploy, and validate without fetching docs. Human docs deepen edge cases. - -Prefer `@next` for **new** work (`sandbox-sdk` skill). For migrations: do not force production cutover without the user agreeing. For **stable-only** deprecated-API cleanup (not full 1.0), use **`sandbox-2026-deprecation`** first if needed. - -**Human docs:** https://developers.cloudflare.com/sandbox/1-0-preview/migrate/ · https://developers.cloudflare.com/sandbox/1-0-preview/ -**Stable docs:** https://developers.cloudflare.com/sandbox/ - -## Workflow - -1. **Review** the rules and replacement map below. -2. **Audit** the codebase with the search; list every hit and its target shape. -3. **Clarify** with the user: cutover timing, bridge Worker, Python image, unclear call sites. -4. **Upgrade** package + image, apply code edits from this file, then deploy cutover. -5. **Validate** typecheck, smokes, and a second grep. - -Stop after any step that needs a user decision. - -## Hard rules - -- Worker npm package and container image must be the **same** `@next` line. Never mix `@next` Worker code with a stable image (or the reverse). -- Production cutover uses immediate container rollout (command below). Stable and `@next` control protocols are incompatible both ways; a gradual container rollout leaves a broken mixed window. -- `await sandbox.exec(...)` means **process launched**, not **command finished**. -- Argv is passed to the process **as-is** (no implicit shell, no shell-escaping of argv). Shell syntax needs an explicit shell binary. -- Process handles have **no stdin**. Interactive input → terminals. -- Observation `timeout` / `AbortSignal` on `output` / waits / `logs` cancel **only that wait**. They do **not** kill the process. Use `kill(signal?)` (numeric; default `15`) or `exec` remote `timeout`. -- Do **not** use one retry loop for every error (table below). -- Do **not** invent APIs: no `gitCheckout` on core, no process stdin, no string-exec completion helper, no custom extension authoring guide. -- No internal release calendars in user-facing text. -- Prefer installed `@next` TypeScript types when resolving API details. -- The self-deployed bridge is not part of the preview. Keep bridge deployments, clients, the Worker package, and the container image on the stable release line. - -## 1. Review — what changes - -| Stable | Preview | -| ------ | ------- | -| `SANDBOX_TRANSPORT` / `transport` / `setTransport` | Remove — RPC only | -| `await sandbox.exec("cmd")` → buffered result | `await sandbox.exec(argv)` → handle, then `output` / waits | -| `execStream` / `startProcess` | Same handle: `logs`, `waitFor*`, `kill` | -| Default / named sessions | Gone — `cwd`/`env` per launch, or one shell script argv | -| `sandbox.terminal(request)` / session terminal | `createTerminal` + `terminal.connect(request)` | -| xterm `sessionId` | `terminalId` | -| Interpreter methods on `Sandbox` | `withInterpreter` → `sandbox.interpreter.*` | -| `gitCheckout` | argv `git` via `exec` | -| String kill signals | Numeric only | -| Files, mounts, backups, ports, tunnels, `proxyToSandbox` | Mostly unchanged (ignore session/transport bits on stable pages) | - -## 2. Audit - -```sh -rg 'SANDBOX_TRANSPORT|transport:|setTransport|enableDefaultSession|createSession|getSession|deleteSession|execStream\(|startProcess\(|killProcess\(|sandbox\.terminal\(|sessionId|gitCheckout\(|SandboxTransport|ExecutionSession' -``` - -Also search: string `exec(`, patterns of `cd` then a later `exec`, bare `createCodeContext` / `runCode` on `Sandbox`. - -For each hit, note the replacement from this file. Ask the user before guessing. - -## 3. Clarify (ask when needed) - -- OK to cut production with immediate container rollout (live container processes/terminals/streams stop)? -- Self-deployed bridge Worker present? Leave it on the stable release line; this runbook is for Worker SDK apps only. -- Python interpreter → must use **`-python`** image variant? -- Any call site not covered below? - -## 4. Upgrade - -### 4.1 Package and image - -```sh -npm install @cloudflare/sandbox@next -# or pnpm / yarn equivalent -``` - -Dockerfile / container must match, for example: - -```dockerfile -FROM cloudflare/sandbox:next -# Python interpreter: -# FROM cloudflare/sandbox:next-python -``` - -Use the same exact prerelease tag on Worker and image when not on the floating `next` tag. - -### 4.2 Remove transport - -Delete `SANDBOX_TRANSPORT`, `transport` on `getSandbox()`, `setTransport()`, and `SandboxTransport` types. No replacement setting. - -### 4.3 Command execution - -**Buffered command** - -```ts -// Stable -const result = await sandbox.exec("npm test"); -console.log(result.stdout, result.exitCode); - -// Preview -const process = await sandbox.exec(["/bin/bash", "-lc", "npm test"]); -// single binary without shell: -// const process = await sandbox.exec(["npm", "test"], { cwd: "/workspace/app" }); -const result = await process.output({ encoding: "utf8" }); -console.log(result.stdout, result.exitCode); -``` - -- Default `output()` streams are **bytes** (`Uint8Array`). Pass `{ encoding: "utf8" }` for strings. -- Depth: https://developers.cloudflare.com/sandbox/1-0-preview/api/processes/ - -**Background / streaming** - -```ts -// Stable-ish: startProcess / execStream -// Preview: -const server = await sandbox.exec(["/bin/bash", "-lc", "npm run dev"], { - cwd: "/workspace/app", -}); -await server.waitForPort(3000, { timeout: 60_000 }); -// HTTP readiness: { mode: "http", path: "/health", timeout: 60_000 } -// Default waitForPort mode is tcp. - -const stream = await server.logs({ follow: true, replay: true }); -// consume stream... -await server.kill(); // default signal 15 -``` - -**Shell state / cwd / env** - -```ts -// Stable (broken assumption on preview) -await sandbox.exec("cd /app"); -await sandbox.exec("npm test"); - -// Preview — one shot -await sandbox.exec(["/bin/bash", "-lc", "cd /app && npm test"]); -// or -await sandbox.exec(["npm", "test"], { cwd: "/app", env: { NODE_ENV: "test" } }); -``` - -- `setEnvVars` still exists for sandbox-wide **non-secret** config. -- Do **not** put live API keys in `setEnvVars` or launch `env`. Keep secrets in the Worker; use outbound handlers when processes call external APIs: https://developers.cloudflare.com/sandbox/guides/outbound-traffic/ -- Depth: https://developers.cloudflare.com/sandbox/1-0-preview/environment/ - -**Timeouts** - -| Goal | API | -| ---- | --- | -| Limit process lifetime | `exec(argv, { timeout })` → completion may have `timedOut: true` | -| Limit how long you wait | `timeout` / `signal` on `output` / `waitFor*` / `logs` — does not kill | - -### 4.4 Drop sessions - -Remove `createSession`, `getSession`, `deleteSession`, `enableDefaultSession`, and `sessionId` options. Isolate users with **separate sandbox IDs**, not sessions inside one sandbox. - -### 4.5 Terminals - -```ts -// Stable -return sandbox.terminal(request); - -// Preview — create once, store id with sandbox id -const terminal = await sandbox.createTerminal({ - command: ["bash"], - cwd: "/workspace", -}); -// later request / WebSocket upgrade: -const t = await sandbox.getTerminal(terminal.id); -if (!t) { - // container gone or unknown id — createTerminal again from app state - return new Response("terminal gone", { status: 410 }); -} -return t.connect(request, { cursor, cols, rows }); -``` - -Browser `@cloudflare/sandbox/xterm`: pass `terminalId` (not `sessionId`) when building the WebSocket URL. - -Depth: https://developers.cloudflare.com/sandbox/1-0-preview/terminals/ - -### 4.6 Interpreter - -```ts -// Stable: sandbox.createCodeContext / sandbox.runCode -// Preview: -import { Sandbox as BaseSandbox } from "@cloudflare/sandbox"; -import { withInterpreter } from "@cloudflare/sandbox/interpreter"; - -export class Sandbox extends BaseSandbox { - interpreter = withInterpreter(this); -} - -const ctx = await sandbox.interpreter.createCodeContext({ language: "python" }); -const result = await sandbox.interpreter.runCode('print("hi")', { context: ctx }); -// result is plain serializable ExecutionResult -``` - -Python requires the **`-python`** image. Same `@next` Worker + image line. - -Depth: https://developers.cloudflare.com/sandbox/1-0-preview/interpreter/ - -### 4.7 Git - -```ts -// Stable -await sandbox.gitCheckout(repoUrl, { targetDir: "/workspace/repo" }); - -// Preview -const clone = await sandbox.exec( - ["git", "clone", "--depth", "1", "--", repoUrl, "/workspace/repo"], - { cwd: "/workspace" }, -); -const result = await clone.output({ encoding: "utf8" }); -if (result.exitCode !== 0) throw new Error(result.stderr); -``` - -### 4.8 Long-running work across requests - -Process IDs are **not** durable jobs. Same sandbox ID ≠ same container forever. - -**Store:** argv (or script), `cwd`, `env`, app checkpoint — and optionally `process.id` while it might still be alive. - -```ts -// Later request — prefer fresh lookup -const existing = processId ? await sandbox.getProcess(processId) : null; -if (existing) { - const stream = await existing.logs({ since: cursor, replay: true, follow: true }); - // ... -} else { - // null: no container or unknown id — relaunch from stored job - const p = await sandbox.exec(storedArgv, { cwd: storedCwd, env: storedEnv }); - // save p.id -} -// Reusing an old handle object after replace → StaleProcessHandleError; relaunch. -``` - -Depth: https://developers.cloudflare.com/sandbox/1-0-preview/processes/ - -### 4.9 Errors (minimum handlers) - -| Error | What to do | -| ----- | ---------- | -| `ContainerUnavailableError` | Container did not start the work — back off (`retryAfterMs` if set), retry **new** operation | -| `OperationInterruptedError` | Work may have started — read `reason` / `retryable`; inspect before repeating side effects | -| `RPCTransportError` | Lost contact mid-call — later calls may work; **this** call may already have run | -| `StaleProcessHandleError` / `StaleTerminalHandleError` | Previous container — relaunch from stored work | -| `ProcessWaitTimeoutError` / `ProcessAbortedError` | Wait ended only — process may still run | -| `RuntimeControlProtocolError` / broken image after deploy | Worker and image not on same `@next` line — fix deploy, not slow-start retry | - -Prefer `instanceof` on classes from `@cloudflare/sandbox`. -Depth: https://developers.cloudflare.com/sandbox/1-0-preview/errors/ - -`getProcess` / `getTerminal` / `list*` do **not** start a container; they return `null` / `[]` when none is running. - -### 4.10 Bridge - -This runbook covers Worker SDK applications on `@next`. - -The self-deployed bridge stays on the stable release line. Keep its Worker package, container image, and HTTP clients on matching stable versions. Do not pair a bridge deployment with `@cloudflare/sandbox@next`. - -### 4.11 Deploy cutover - -Finish code on a branch/staging first. Production is **one** deploy of matching Worker + image: - -```sh -npx wrangler deploy --containers-rollout=immediate -``` - -- Does **not** clear `rollout_active_grace_period`. Leave grace at default `0` for cutover (or set `0` if raised). -- Before cutover: finish or stop work you must keep. -- After cutover: treat pre-deploy process/terminal IDs as invalid; start work again; run Validate. - -Depth: https://developers.cloudflare.com/sandbox/1-0-preview/migrate/ -Containers rollouts: https://developers.cloudflare.com/containers/platform-details/rollouts/ - -## 5. Validate - -1. Lockfile + Dockerfile both on the same `@next` line -2. Typecheck against `@next` -3. Smoke argv `exec` + `output({ encoding: "utf8" })` -4. Smoke long process (`waitForPort` / `logs`) if used -5. Smoke terminal create + `connect` if used -6. Smoke interpreter if used (correct image variant) -7. Error handling distinguishes unavailable / interrupted-RPC / stale / local wait -8. No live secrets in sandbox env -9. Grep again for removed Worker SDK APIs -10. Production cutover used `--containers-rollout=immediate` - -## Red flags — stop and fix - -- Mixing `@next` Worker with stable image (or reverse) -- Gradual container rollout for this control-plane cutover -- Treating `await exec` as command completion -- Assuming `cd` / exports persist across `exec` calls -- One retry wrapper for every sandbox error -- Inventing `gitCheckout`, process stdin, or undocumented extension APIs -- Keeping pre-cutover process/terminal IDs after deploy -- Forcing production cutover without user agreement -- Putting live secrets in `setEnvVars` / launch `env` From 7bd001b1766cbaa0bc22ab609c26715220f4ab66 Mon Sep 17 00:00:00 2001 From: Naresh Date: Fri, 7 Aug 2026 17:34:08 +0100 Subject: [PATCH 3/5] Rename sandbox-sdk skill to sandbox-next Pair build skills as sandbox-next and sandbox-stable so the package line is obvious from the skill name. --- README.md | 2 +- skills/sandbox-migrate-to-next/SKILL.md | 6 +++--- skills/{sandbox-sdk => sandbox-next}/SKILL.md | 2 +- .../references/api-quick-ref.md | 0 skills/{sandbox-sdk => sandbox-next}/references/examples.md | 0 skills/sandbox-stable/SKILL.md | 6 +++--- 6 files changed, 8 insertions(+), 8 deletions(-) rename skills/{sandbox-sdk => sandbox-next}/SKILL.md (99%) rename skills/{sandbox-sdk => sandbox-next}/references/api-quick-ref.md (100%) rename skills/{sandbox-sdk => sandbox-next}/references/examples.md (100%) diff --git a/README.md b/README.md index 562eca1..b1b8bde 100644 --- a/README.md +++ b/README.md @@ -57,7 +57,7 @@ Skills are contextual and auto-loaded based on your conversation. When a request | cloudflare | Comprehensive platform skill covering Workers, Pages, storage (KV, D1, R2), AI (Workers AI, Vectorize, Agents SDK), networking (Tunnel, Spectrum), security (WAF, DDoS), and IaC (Terraform, Pulumi) | | agents-sdk | Building stateful AI agents with state, scheduling, RPC, MCP servers, email, and streaming chat | | durable-objects | Stateful coordination (chat rooms, games, booking), RPC, SQLite, alarms, WebSockets | -| sandbox-sdk | Build on Sandbox SDK 1.0 preview (`@cloudflare/sandbox@next`); recommended for new projects | +| sandbox-next | Build on Sandbox SDK 1.0 preview (`@cloudflare/sandbox@next`); recommended for new projects | | sandbox-stable | Build on the current stable `@cloudflare/sandbox` package | | sandbox-migrate-to-next | Port a stable Sandbox app to `@cloudflare/sandbox@next` | | wrangler | Deploying and managing Workers, KV, R2, D1, Vectorize, Queues, Workflows | diff --git a/skills/sandbox-migrate-to-next/SKILL.md b/skills/sandbox-migrate-to-next/SKILL.md index a7579e3..b7c3355 100644 --- a/skills/sandbox-migrate-to-next/SKILL.md +++ b/skills/sandbox-migrate-to-next/SKILL.md @@ -1,17 +1,17 @@ --- name: sandbox-migrate-to-next -description: Use when porting a Cloudflare Sandbox app from stable @cloudflare/sandbox to @cloudflare/sandbox@next (Sandbox SDK 1.0 preview), or when the user asks to migrate or upgrade to Sandbox 1.0 / @next. Not for day-to-day stable work (sandbox-stable) or new @next apps (sandbox-sdk). +description: Use when porting a Cloudflare Sandbox app from stable @cloudflare/sandbox to @cloudflare/sandbox@next (Sandbox SDK 1.0 preview), or when the user asks to migrate or upgrade to Sandbox 1.0 / @next. Not for day-to-day stable work (sandbox-stable) or new @next apps (sandbox-next). --- # Migrate to Sandbox SDK 1.0 preview (`@next`) **Perform** the port from the current stable package to `@cloudflare/sandbox@next`. Follow the steps in order. Human depth: [Migrate](https://developers.cloudflare.com/sandbox/1-0-preview/migrate/) · [1.0 preview](https://developers.cloudflare.com/sandbox/1-0-preview/). -We recommend **new** projects start on `@next` (**`sandbox-sdk`**). Existing apps should migrate **when you can**, so you are ready when 1.0 becomes the stable release. The main [Sandbox docs](https://developers.cloudflare.com/sandbox/) still describe today’s stable package (**`sandbox-stable`**). +We recommend **new** projects start on `@next` (**`sandbox-next`**). Existing apps should migrate **when you can**, so you are ready when 1.0 becomes the stable release. The main [Sandbox docs](https://developers.cloudflare.com/sandbox/) still describe today’s stable package (**`sandbox-stable`**). Do **not** force production cutover without the user agreeing. -**Not this skill:** day-to-day stable feature work → **`sandbox-stable`**. New `@next` work → **`sandbox-sdk`**. Deprecated-API cleanup **without** moving to `@next` → [2026 deprecation guide](https://developers.cloudflare.com/sandbox/guides/2026-deprecation/) on the stable package first if needed. +**Not this skill:** day-to-day stable feature work → **`sandbox-stable`**. New `@next` work → **`sandbox-next`**. Deprecated-API cleanup **without** moving to `@next` → [2026 deprecation guide](https://developers.cloudflare.com/sandbox/guides/2026-deprecation/) on the stable package first if needed. ## Workflow diff --git a/skills/sandbox-sdk/SKILL.md b/skills/sandbox-next/SKILL.md similarity index 99% rename from skills/sandbox-sdk/SKILL.md rename to skills/sandbox-next/SKILL.md index 7ca453f..88aa0ec 100644 --- a/skills/sandbox-sdk/SKILL.md +++ b/skills/sandbox-next/SKILL.md @@ -1,5 +1,5 @@ --- -name: sandbox-sdk +name: sandbox-next description: Use when building or changing Cloudflare Sandbox apps on @cloudflare/sandbox@next (Sandbox SDK 1.0 preview)—code execution, AI runners, interpreters, CI-like jobs, terminals, mounts, tunnels, or preview URLs. Not for the default stable package (use sandbox-stable) or for porting stable to @next (use sandbox-migrate-to-next). --- diff --git a/skills/sandbox-sdk/references/api-quick-ref.md b/skills/sandbox-next/references/api-quick-ref.md similarity index 100% rename from skills/sandbox-sdk/references/api-quick-ref.md rename to skills/sandbox-next/references/api-quick-ref.md diff --git a/skills/sandbox-sdk/references/examples.md b/skills/sandbox-next/references/examples.md similarity index 100% rename from skills/sandbox-sdk/references/examples.md rename to skills/sandbox-next/references/examples.md diff --git a/skills/sandbox-stable/SKILL.md b/skills/sandbox-stable/SKILL.md index d1d99b9..f50ff19 100644 --- a/skills/sandbox-stable/SKILL.md +++ b/skills/sandbox-stable/SKILL.md @@ -1,6 +1,6 @@ --- name: sandbox-stable -description: Use when building or changing Cloudflare Sandbox apps on the current stable @cloudflare/sandbox package (default npm tag)—commands, sessions, files, ports, tunnels, bridge, or deprecated-API cleanup while staying on stable. Not for @cloudflare/sandbox@next (use sandbox-sdk) or for porting to 1.0 (use sandbox-migrate-to-next). +description: Use when building or changing Cloudflare Sandbox apps on the current stable @cloudflare/sandbox package (default npm tag)—commands, sessions, files, ports, tunnels, bridge, or deprecated-API cleanup while staying on stable. Not for @cloudflare/sandbox@next (use sandbox-next) or for porting to 1.0 (use sandbox-migrate-to-next). --- # Cloudflare Sandbox SDK (stable package) @@ -9,7 +9,7 @@ Isolated Linux environments on [Cloudflare Containers](https://developers.cloudf This skill is the **current stable** line: default `@cloudflare/sandbox` (today’s published package) and a **matching** stable container image. The main [Sandbox documentation](https://developers.cloudflare.com/sandbox/) describes this package. -We recommend starting **new** projects on the [1.0 preview](https://developers.cloudflare.com/sandbox/1-0-preview/) (`@cloudflare/sandbox@next`) with **`sandbox-sdk`**. Existing apps can stay on stable and keep shipping. When you can, plan a move with **`sandbox-migrate-to-next`** so you are ready when 1.0 becomes the stable release. +We recommend starting **new** projects on the [1.0 preview](https://developers.cloudflare.com/sandbox/1-0-preview/) (`@cloudflare/sandbox@next`) with **`sandbox-next`**. Existing apps can stay on stable and keep shipping. When you can, plan a move with **`sandbox-migrate-to-next`** so you are ready when 1.0 becomes the stable release. Prefer stable docs and installed package types over memory. Do not apply `@next` API shapes here. @@ -22,7 +22,7 @@ Before writing code, check the app: | If you find… | Do this | | ------------ | ------- | -| `@cloudflare/sandbox@next` (or preview image) | Stop. Use **`sandbox-sdk`**. | +| `@cloudflare/sandbox@next` (or preview image) | Stop. Use **`sandbox-next`**. | | User wants to **port** to 1.0 / `@next` | Stop. Use **`sandbox-migrate-to-next`**. Do not half-apply preview APIs while the package is still stable. | | Only cleaning deprecated stable APIs | Stay on this skill + [2026 deprecation guide](https://developers.cloudflare.com/sandbox/guides/2026-deprecation/). That is **not** a move to `@next`. | From c63fe52ff695a1aef0d5fdb3514955d7a7a47c56 Mon Sep 17 00:00:00 2001 From: Naresh Date: Fri, 7 Aug 2026 17:43:03 +0100 Subject: [PATCH 4/5] Restructure Sandbox skills as retrieval maps Build skills gate the package line, state the contract, and route to docs by task. Keep migrate as a stepwise port runbook. --- README.md | 4 +- skills/sandbox-migrate-to-next/SKILL.md | 190 +++++++----------- skills/sandbox-next/SKILL.md | 173 ++++++---------- .../sandbox-next/references/api-quick-ref.md | 35 ++-- skills/sandbox-next/references/examples.md | 16 +- skills/sandbox-stable/SKILL.md | 177 +++++++--------- 6 files changed, 232 insertions(+), 363 deletions(-) diff --git a/README.md b/README.md index b1b8bde..442b517 100644 --- a/README.md +++ b/README.md @@ -57,8 +57,8 @@ Skills are contextual and auto-loaded based on your conversation. When a request | cloudflare | Comprehensive platform skill covering Workers, Pages, storage (KV, D1, R2), AI (Workers AI, Vectorize, Agents SDK), networking (Tunnel, Spectrum), security (WAF, DDoS), and IaC (Terraform, Pulumi) | | agents-sdk | Building stateful AI agents with state, scheduling, RPC, MCP servers, email, and streaming chat | | durable-objects | Stateful coordination (chat rooms, games, booking), RPC, SQLite, alarms, WebSockets | -| sandbox-next | Build on Sandbox SDK 1.0 preview (`@cloudflare/sandbox@next`); recommended for new projects | -| sandbox-stable | Build on the current stable `@cloudflare/sandbox` package | +| sandbox-next | Sandbox on `@cloudflare/sandbox@next` (1.0 preview); recommended for new projects | +| sandbox-stable | Sandbox on the current stable `@cloudflare/sandbox` package | | sandbox-migrate-to-next | Port a stable Sandbox app to `@cloudflare/sandbox@next` | | wrangler | Deploying and managing Workers, KV, R2, D1, Vectorize, Queues, Workflows | | web-perf | Auditing Core Web Vitals (FCP, LCP, TBT, CLS), render-blocking resources, network chains | diff --git a/skills/sandbox-migrate-to-next/SKILL.md b/skills/sandbox-migrate-to-next/SKILL.md index b7c3355..745bcc5 100644 --- a/skills/sandbox-migrate-to-next/SKILL.md +++ b/skills/sandbox-migrate-to-next/SKILL.md @@ -3,42 +3,43 @@ name: sandbox-migrate-to-next description: Use when porting a Cloudflare Sandbox app from stable @cloudflare/sandbox to @cloudflare/sandbox@next (Sandbox SDK 1.0 preview), or when the user asks to migrate or upgrade to Sandbox 1.0 / @next. Not for day-to-day stable work (sandbox-stable) or new @next apps (sandbox-next). --- -# Migrate to Sandbox SDK 1.0 preview (`@next`) +# Migrate stable → Sandbox SDK 1.0 preview (`@next`) -**Perform** the port from the current stable package to `@cloudflare/sandbox@next`. Follow the steps in order. Human depth: [Migrate](https://developers.cloudflare.com/sandbox/1-0-preview/migrate/) · [1.0 preview](https://developers.cloudflare.com/sandbox/1-0-preview/). +**Perform** the port. Follow the steps in order. Depth lives in docs—fetch the linked page when a step needs detail. -We recommend **new** projects start on `@next` (**`sandbox-next`**). Existing apps should migrate **when you can**, so you are ready when 1.0 becomes the stable release. The main [Sandbox docs](https://developers.cloudflare.com/sandbox/) still describe today’s stable package (**`sandbox-stable`**). +Human guide: [Migrate](https://developers.cloudflare.com/sandbox/1-0-preview/migrate/) · [1.0 preview](https://developers.cloudflare.com/sandbox/1-0-preview/) -Do **not** force production cutover without the user agreeing. +**New projects** should start on `@next` (**`sandbox-next`**), not this skill. **Day-to-day stable work** → **`sandbox-stable`**. Deprecated-API cleanup **without** moving to `@next` → [2026 deprecation guide](https://developers.cloudflare.com/sandbox/guides/2026-deprecation/) first if needed. -**Not this skill:** day-to-day stable feature work → **`sandbox-stable`**. New `@next` work → **`sandbox-next`**. Deprecated-API cleanup **without** moving to `@next` → [2026 deprecation guide](https://developers.cloudflare.com/sandbox/guides/2026-deprecation/) on the stable package first if needed. +Existing apps should migrate **when you can**, so you are ready when 1.0 becomes the stable release. Do **not** force production cutover without the user agreeing. + +**Prefer installed `@next` types and the migrate doc over memory.** ## Workflow -1. **Review** the hard rules and replacement map below (and the migrate doc if needed). -2. **Audit** the codebase; list every hit and its target shape. -3. **Clarify** uncertainty with the user (cutover timing, bridge, Python image, unclear call sites). -4. **Upgrade** package + image and apply code changes. -5. **Validate** typecheck, smokes, and a second grep. +1. **Review** hard rules and the replacement map +2. **Audit** the codebase; list hits and target shapes +3. **Clarify** with the user (cutover, bridge, Python image, unclear sites) +4. **Upgrade** package, image, and code +5. **Validate** Stop after any step that needs a user decision. ## Hard rules -- Worker package and container image must be the **same** `@next` line. -- Production cutover uses **immediate** container rollout (`--containers-rollout=immediate`). Stable and `@next` control protocols are incompatible both ways; gradual rollout leaves a broken mixed window. In-flight container work can stop. -- `await sandbox.exec(...)` means the process **started**, not that the command **finished**. -- Argv is passed **as-is** (no implicit shell). Shell syntax needs an explicit shell binary. -- Process handles have **no stdin**. Interactive input → terminals. -- Observation `timeout` / `AbortSignal` cancel **only that wait**. They do **not** kill the process. -- Do **not** use one retry loop for every error. -- Do **not** invent APIs (`gitCheckout` on core, process stdin, string-exec completion helper). -- Prefer installed `@next` types over guesses. -- Self-deployed bridge is not on the preview — keep bridge Worker, image, and clients on **stable**. +- Worker package and container image must be the **same** `@next` line. +- Production cutover uses **immediate** container rollout. Stable and `@next` control protocols are incompatible both ways; gradual rollout leaves a broken mixed window. In-flight container work can stop. +- After cutover, `await sandbox.exec(...)` means process **started**, not command **finished**. +- Argv is as-is (no implicit shell). Shell syntax needs an explicit shell binary. +- Process handles have **no stdin** → terminals for interactive input. +- Observation `timeout` / `AbortSignal` cancel the **wait only**, not the process. +- No single retry loop for every error. +- Do not invent APIs (`gitCheckout` on core, process stdin, string-exec completion helper). +- Self-deployed bridge stays on **stable** (not part of the preview line yet). ## Replacement map -| Stable | Preview | +| Stable | `@next` | | ------ | ------- | | `SANDBOX_TRANSPORT` / `transport` / `setTransport` | Remove — RPC only | | `await sandbox.exec("cmd")` → buffered result | `await sandbox.exec(argv)` → handle, then `output` / waits | @@ -46,10 +47,12 @@ Stop after any step that needs a user decision. | Default / named sessions | Gone — `cwd`/`env` per launch, or one shell script | | `sandbox.terminal(request)` / session terminal | `createTerminal` + `terminal.connect(request)` | | xterm `sessionId` | `terminalId` | -| Interpreter on `Sandbox` | `withInterpreter` → `sandbox.interpreter.*` | +| Interpreter methods on `Sandbox` | `withInterpreter` → `sandbox.interpreter.*` | | `gitCheckout` | argv `git` via `exec` | | String kill signals | Numeric only | -| Files, mounts, backups, ports, tunnels, `proxyToSandbox` | Mostly unchanged (ignore session/transport bits) | +| Files, mounts, backups, ports, tunnels, `proxyToSandbox` | Mostly unchanged (ignore session/transport bits on stable pages) | + +Depth: [Migrate](https://developers.cloudflare.com/sandbox/1-0-preview/migrate/) · after port, day-to-day → **`sandbox-next`** ## Audit @@ -61,10 +64,10 @@ Also: string `exec(`, `cd` then a later `exec`, bare `createCodeContext` / `runC ## Clarify (ask when needed) -- OK to cut production with immediate container rollout (live processes/terminals/streams may stop)? -- Self-deployed bridge present? Leave it on stable. -- Python interpreter → **`-python`** image variant? -- Call sites not covered below? +- OK to cut production with `--containers-rollout=immediate` (live processes/terminals/streams may stop)? +- Self-deployed bridge? Leave on stable. +- Python interpreter → **`-python`** image variant? +- Call sites not covered by the map? ## Upgrade @@ -76,72 +79,54 @@ npm install @cloudflare/sandbox@next ```dockerfile FROM cloudflare/sandbox:next -# Python interpreter: cloudflare/sandbox:next-python +# Python: cloudflare/sandbox:next-python ``` -Use the same prerelease tag on Worker and image when not on floating `next`. +Same prerelease tag on Worker and image when not on floating `next`. -### Transport +### Code by area -Delete `SANDBOX_TRANSPORT`, `transport` on `getSandbox()`, `setTransport()`, `SandboxTransport`. No replacement setting. +Apply replacements from the map. For each area, implement from the doc—not from stable habits: + +| Area | Doc | +| ---- | --- | +| Commands / handles / waits | [Processes](https://developers.cloudflare.com/sandbox/1-0-preview/processes/) · [Processes API](https://developers.cloudflare.com/sandbox/1-0-preview/api/processes/) | +| `cwd` / `env` / secrets | [Environment](https://developers.cloudflare.com/sandbox/1-0-preview/environment/) · [Outbound traffic](https://developers.cloudflare.com/sandbox/guides/outbound-traffic/) | +| Drop sessions | [Migrate](https://developers.cloudflare.com/sandbox/1-0-preview/migrate/) · [Lifecycle](https://developers.cloudflare.com/sandbox/1-0-preview/lifecycle/) | +| Terminals | [Terminals](https://developers.cloudflare.com/sandbox/1-0-preview/terminals/) | +| Interpreter | [Interpreter](https://developers.cloudflare.com/sandbox/1-0-preview/interpreter/) | +| Errors | [Errors](https://developers.cloudflare.com/sandbox/1-0-preview/errors/) | +| Durable job across requests | [Process execution — lifetime / durability](https://developers.cloudflare.com/sandbox/1-0-preview/processes/) | -### Commands +**Commands (shape):** ```ts -// Stable +// Before (stable) const result = await sandbox.exec("npm test"); -// Preview +// After (@next) const process = await sandbox.exec(["/bin/bash", "-lc", "npm test"]); -// or: await sandbox.exec(["npm", "test"], { cwd: "/workspace/app" }); const result = await process.output({ encoding: "utf8" }); ``` -Default `output()` streams are **bytes**. Pass `{ encoding: "utf8" }` for strings. - ```ts const server = await sandbox.exec(["/bin/bash", "-lc", "npm run dev"], { cwd: "/workspace/app", }); -await server.waitForPort(3000, { timeout: 60_000 }); // default mode: tcp -const stream = await server.logs({ follow: true, replay: true }); -await server.kill(); // default 15 -``` - -```ts -// One shot — do not rely on cd across separate exec calls -await sandbox.exec(["/bin/bash", "-lc", "cd /app && npm test"]); -// or -await sandbox.exec(["npm", "test"], { cwd: "/app", env: { NODE_ENV: "test" } }); +await server.waitForPort(3000, { timeout: 60_000 }); +await server.kill(); // numeric; default 15 ``` -- `setEnvVars` remains for sandbox-wide **non-secret** config. -- Do **not** put live API keys in `setEnvVars` or launch `env`. [Outbound traffic](https://developers.cloudflare.com/sandbox/guides/outbound-traffic/). - -| Goal | API | -| ---- | --- | -| Limit process lifetime | `exec(argv, { timeout })` | -| Limit how long you wait | `timeout` / `signal` on `output` / `waitFor*` / `logs` — does not kill | - -### Sessions - -Remove `createSession`, `getSession`, `deleteSession`, `enableDefaultSession`, `sessionId` options. Isolate users with **separate sandbox IDs**. - -### Terminals +**Terminals (shape):** ```ts -const terminal = await sandbox.createTerminal({ - command: ["bash"], - cwd: "/workspace", -}); +const terminal = await sandbox.createTerminal({ command: ["bash"], cwd: "/workspace" }); const t = await sandbox.getTerminal(terminal.id); if (!t) return new Response("terminal gone", { status: 410 }); return t.connect(request, { cursor, cols, rows }); ``` -Browser `@cloudflare/sandbox/xterm`: pass `terminalId` (not `sessionId`). - -### Interpreter +**Interpreter (shape):** ```ts import { Sandbox as BaseSandbox } from "@cloudflare/sandbox"; @@ -150,14 +135,9 @@ import { withInterpreter } from "@cloudflare/sandbox/interpreter"; export class Sandbox extends BaseSandbox { interpreter = withInterpreter(this); } - -const ctx = await sandbox.interpreter.createCodeContext({ language: "python" }); -const result = await sandbox.interpreter.runCode('print("hi")', { context: ctx }); ``` -Python requires the **`-python`** image. Same `@next` Worker + image line. - -### Git +**Git (shape):** ```ts const clone = await sandbox.exec( @@ -165,53 +145,19 @@ const clone = await sandbox.exec( { cwd: "/workspace" }, ); const result = await clone.output({ encoding: "utf8" }); -if (result.exitCode !== 0) throw new Error(result.stderr); -``` - -### Work across requests - -Process IDs are **not** durable jobs. Store argv (or script), `cwd`, `env`, and app checkpoint — optionally `process.id` while it might still be alive. - -```ts -const existing = processId ? await sandbox.getProcess(processId) : null; -if (existing) { - await existing.logs({ since: cursor, replay: true, follow: true }); -} else { - const p = await sandbox.exec(storedArgv, { cwd: storedCwd, env: storedEnv }); - // save p.id -} ``` -`getProcess` / `getTerminal` / `list*` do not start a container; they return `null` / `[]` when none is running. - -### Errors - -| Error | What to do | -| ----- | ---------- | -| `ContainerUnavailableError` | Back off; retry **new** operation | -| `OperationInterruptedError` | Work may have started — inspect before repeating side effects | -| `RPCTransportError` | This call may already have run | -| `StaleProcessHandleError` / `StaleTerminalHandleError` | Relaunch from stored work | -| `ProcessWaitTimeoutError` / `ProcessAbortedError` | Wait ended only — process may still run | -| `RuntimeControlProtocolError` | Worker and image not on same `@next` line — fix deploy | - -Prefer `instanceof` on classes from `@cloudflare/sandbox`. - -### Bridge - -Leave self-deployed bridge on the stable release line. Do not pair bridge with `@cloudflare/sandbox@next`. +Delete transport settings entirely. Remove session APIs. Isolate users with **separate sandbox IDs**. ### Deploy cutover -Finish code on a branch/staging first. Production is **one** deploy of matching Worker + image: +Staging/branch first. Production is **one** deploy of matching Worker + image: ```sh npx wrangler deploy --containers-rollout=immediate ``` -- Does not clear `rollout_active_grace_period`. Leave grace at default `0` (or set `0` if raised). -- Before: finish or stop work you must keep. -- After: treat pre-deploy process/terminal IDs as invalid; start work again. +Leave `rollout_active_grace_period` at default `0` (or set `0` if raised). After cutover, pre-deploy process/terminal IDs are invalid. Details: [Migrate](https://developers.cloudflare.com/sandbox/1-0-preview/migrate/) · [Container rollouts](https://developers.cloudflare.com/containers/platform-details/rollouts/) ## Validate @@ -219,19 +165,21 @@ npx wrangler deploy --containers-rollout=immediate 2. Typecheck against `@next` 3. Smoke argv `exec` + `output({ encoding: "utf8" })` 4. Smoke long process / terminal / interpreter if used -5. Error handling distinguishes unavailable / interrupted-RPC / stale / local wait +5. Errors distinguished: unavailable / interrupted-RPC / stale / local wait 6. No live secrets in sandbox env 7. Grep again for removed APIs -8. Production cutover used `--containers-rollout=immediate` +8. Production used `--containers-rollout=immediate` + +Then day-to-day work uses **`sandbox-next`**. ## Red flags — stop and fix -- Mixing `@next` Worker with stable image (or reverse) -- Gradual container rollout for this control-plane cutover -- Treating `await exec` as command completion -- Assuming `cd` / exports persist across `exec` calls -- One retry wrapper for every sandbox error -- Inventing `gitCheckout`, process stdin, or undocumented extension APIs -- Keeping pre-cutover process/terminal IDs after deploy -- Forcing production cutover without user agreement -- Putting live secrets in `setEnvVars` / launch `env` +- Mixing `@next` Worker with stable image (or reverse) +- Gradual container rollout for this cutover +- Treating `await exec` as command completion +- Assuming `cd` / exports persist across `exec` calls +- One retry wrapper for every error +- Inventing `gitCheckout`, process stdin, or undocumented APIs +- Keeping pre-cutover process/terminal IDs after deploy +- Forcing production cutover without user agreement +- Putting live secrets in `setEnvVars` / launch `env` diff --git a/skills/sandbox-next/SKILL.md b/skills/sandbox-next/SKILL.md index 88aa0ec..777403a 100644 --- a/skills/sandbox-next/SKILL.md +++ b/skills/sandbox-next/SKILL.md @@ -1,134 +1,91 @@ --- name: sandbox-next -description: Use when building or changing Cloudflare Sandbox apps on @cloudflare/sandbox@next (Sandbox SDK 1.0 preview)—code execution, AI runners, interpreters, CI-like jobs, terminals, mounts, tunnels, or preview URLs. Not for the default stable package (use sandbox-stable) or for porting stable to @next (use sandbox-migrate-to-next). +description: Use when building or changing Cloudflare Sandbox apps on @cloudflare/sandbox@next (Sandbox SDK 1.0 preview)—code execution, AI runners, interpreters, CI-like jobs, terminals, files, mounts, tunnels, preview URLs, lifecycle, or errors. Not for the default stable package (use sandbox-stable) or for porting stable to @next (use sandbox-migrate-to-next). --- -# Cloudflare Sandbox SDK (`@next`) +# Sandbox SDK — `@next` (1.0 preview) Isolated Linux environments on [Cloudflare Containers](https://developers.cloudflare.com/containers/), driven from Workers. -This skill is the **1.0 preview** line: `@cloudflare/sandbox@next` and a matching `cloudflare/sandbox:next` image. We recommend this line for **new projects**. Existing apps on the default package should keep using **`sandbox-stable`** until they are ready to move; then use **`sandbox-migrate-to-next`**. +**Prefer preview docs and installed `@next` types over memory.** APIs change; this skill is a gate, a contract, and a retrieval map—not a full manual. -Prefer preview docs and installed `@next` types over memory. Stable and `@next` APIs differ. +We recommend **new projects** on this line. Apps still on the default package use **`sandbox-stable`**. Port only when asked, via **`sandbox-migrate-to-next`**. -## Confirm the package line +## 1. Gate — confirm the package line -Before writing code, check the app: +Before writing code, inspect the app: -- Dependency is `@cloudflare/sandbox@next` (or another preview tag), **and** -- Container image matches (for example `cloudflare/sandbox:next` or `next-python`) +| Check | Must match | +| ----- | ---------- | +| npm dependency | `@cloudflare/sandbox@next` (or another preview tag) | +| Container image | Same line (e.g. `cloudflare/sandbox:next`, `next-python`) | -| If you find… | Do this | -| ------------ | ------- | -| Default `@cloudflare/sandbox` (no `@next`) | Stop. Use **`sandbox-stable`** and the [main Sandbox docs](https://developers.cloudflare.com/sandbox/). Do not apply `@next` APIs. | -| User wants to **port** stable → `@next` | Stop. Use **`sandbox-migrate-to-next`**. | -| Self-deployed **bridge** only | Bridge is not on the 1.0 preview line yet. Keep bridge on the stable package + image. [Bridge](https://developers.cloudflare.com/sandbox/bridge/). | +| If you find… | Action | +| ------------ | ------ | +| Default `@cloudflare/sandbox` (no `@next`) | **Stop.** Load **`sandbox-stable`**. Do not apply this skill’s APIs. | +| User wants to port stable → `@next` | **Stop.** Load **`sandbox-migrate-to-next`**. | +| Self-deployed **bridge** only | Bridge is **not** on the 1.0 preview line yet. Keep bridge on stable package + image. [Bridge (stable)](https://developers.cloudflare.com/sandbox/bridge/) | Never mix an `@next` Worker package with a stable container image (or the reverse). -Install skills: [Agent setup](https://developers.cloudflare.com/agent-setup/) · [cloudflare/skills](https://github.com/cloudflare/skills). +Skills install: [Agent setup](https://developers.cloudflare.com/agent-setup/) · [cloudflare/skills](https://github.com/cloudflare/skills) -## Retrieval +## 2. Contract — non-negotiables -| Topic | URL | -| ----- | --- | -| Overview | https://developers.cloudflare.com/sandbox/1-0-preview/ | -| Get started | https://developers.cloudflare.com/sandbox/1-0-preview/get-started/ | -| Processes | https://developers.cloudflare.com/sandbox/1-0-preview/processes/ | -| Process API | https://developers.cloudflare.com/sandbox/1-0-preview/api/processes/ | -| Terminals | https://developers.cloudflare.com/sandbox/1-0-preview/terminals/ | -| Errors | https://developers.cloudflare.com/sandbox/1-0-preview/errors/ | -| Environment | https://developers.cloudflare.com/sandbox/1-0-preview/environment/ | -| Interpreter | https://developers.cloudflare.com/sandbox/1-0-preview/interpreter/ | -| Examples (`next` branch) | https://github.com/cloudflare/sandbox-sdk/tree/next/examples | -| API quick ref | [references/api-quick-ref.md](references/api-quick-ref.md) | +- `sandbox.exec(argv)` takes an **argv** list and resolves when the process **starts**. It returns a **handle**, not a finished command result. +- Collect results with handle methods: `output()`, `logs()`, `waitForExit()`, `waitForPort()`, `waitForLog()`, `kill(signal?)`. +- No implicit shell. Shell syntax needs an explicit shell, e.g. `["/bin/bash", "-lc", script]`. +- Each launch is independent. A `cd` / `export` in one `exec` is not visible to the next. Pass `cwd` and `env` per launch, or one shell script. +- Process handles have **no stdin**. Interactive use → terminals (`createTerminal` + `connect`). +- Local wait `timeout` / `AbortSignal` cancel the **wait only**. They do not kill the process. Use `kill` or `exec`’s remote `timeout`. +- `getProcess` / `listProcesses` / `getTerminal` / `listTerminals` do **not** start a container; they return `null` / `[]` when none is up. +- Process and terminal IDs belong to the **current container**, not forever to a sandbox ID. For work that must survive replace, store the full job (argv, cwd, env, app state)—not only an id. +- Non-secret config only in `setEnvVars` / launch `env`. Live credentials stay in the Worker; use outbound handlers when the sandbox calls external APIs. +- Do **not** invent removed stable APIs (`gitCheckout` on core, string-`exec` completion, session execution, `sandbox.terminal(request)`). +- Do **not** use one retry loop for every error (see Errors docs). -## Install - -```bash -npm install @cloudflare/sandbox@next -docker info # local container dev -``` - -## Worker shape - -Re-export `Sandbox` and bind the Durable Object / container (see get-started): +Minimal shape: ```ts import { getSandbox, proxyToSandbox, Sandbox } from "@cloudflare/sandbox"; export { Sandbox }; -export default { - async fetch(request: Request, env: Env): Promise { - const proxy = await proxyToSandbox(request, env); - if (proxy) return proxy; - - const sandbox = getSandbox(env.Sandbox, "user-123"); - const process = await sandbox.exec(["python3", "-c", "print(2 + 2)"]); - const output = await process.output({ encoding: "utf8" }); - return Response.json({ - stdout: output.stdout, - exitCode: output.exitCode, - }); - }, -}; -``` - -## Core model - -- `exec(argv)` takes an **argv** list and resolves when the process **starts**. It returns a **handle**. -- Observe or control with `output()`, `logs()`, `waitForExit()`, `waitForPort()`, `waitForLog()`, `kill(signal?)`. -- No implicit shell. Shell syntax needs an explicit shell, for example `["/bin/bash", "-lc", script]`. -- Each launch is independent. A `cd` in one `exec()` is not remembered in the next. Pass `cwd` and `env` when you need them. -- Process handles have **no stdin**. Interactive PTY → `createTerminal` + `connect`. -- Wait `timeout` / `AbortSignal` cancel the **wait only** — they do not kill the process. Use `kill` or `exec` remote `timeout`. -- `getProcess` / `listProcesses` do not start a container; they return `null` / `[]` when none is up. -- Process IDs live in the **current container**. Store the full job (argv, cwd, env) to relaunch after stop or replace. - -```ts -const p = await sandbox.exec(["node", "--version"]); -const result = await p.output({ encoding: "utf8" }); - -const server = await sandbox.exec(["/bin/bash", "-lc", "npm run dev"], { - cwd: "/workspace/app", -}); -await server.waitForPort(3000, { timeout: 60_000 }); // default mode: tcp -await server.kill(); // numeric signal; default 15 -``` - -### Interpreter - -```ts -import { Sandbox as BaseSandbox } from "@cloudflare/sandbox"; -import { withInterpreter } from "@cloudflare/sandbox/interpreter"; - -export class Sandbox extends BaseSandbox { - interpreter = withInterpreter(this); -} -// sandbox.interpreter.createCodeContext / runCode -// Python needs the -python image variant -``` - -### Terminals - -```ts -const terminal = await sandbox.createTerminal({ command: ["bash"] }); -const t = await sandbox.getTerminal(terminal.id); -if (t) return t.connect(request, { cursor }); +const sandbox = getSandbox(env.Sandbox, "user-123"); +const process = await sandbox.exec(["python3", "-c", "print(2 + 2)"]); +const result = await process.output({ encoding: "utf8" }); +// result.stdout, result.exitCode ``` -### Env, URLs, errors - -- Non-secret config only in `setEnvVars` / launch `env`. Secrets stay in the Worker; use [outbound traffic](https://developers.cloudflare.com/sandbox/guides/outbound-traffic/) when processes call external APIs. -- Public URLs: `sandbox.tunnels` when it fits; `exposePort` + `proxyToSandbox` when the Worker must front the request. Production hostnames need wildcard DNS on a custom domain. -- Do not use one retry loop for every error. `ContainerUnavailableError` → back off, new operation. `OperationInterruptedError` / `RPCTransportError` → inspect (work may have started). Stale handle → relaunch from stored job. Local wait timeout → observation only. - -## Common mistakes - -- Using this skill on the default stable package -- Treating `await exec` as “command finished” -- Mixing `@next` Worker with a stable image -- Assuming shell state across `exec` calls -- Putting API keys in sandbox env -- Inventing `gitCheckout` on core — run `git` via argv `exec` +Optional signature cheat sheet: [references/api-quick-ref.md](references/api-quick-ref.md) +Examples index (`next` branch): [references/examples.md](references/examples.md) + +## 3. Retrieve — open the doc for the task + +Fetch the page before implementing. Installed `@next` types win over guesses. + +| You need to… | Open | +| ------------ | ---- | +| Orient / choose preview | [1.0 preview overview](https://developers.cloudflare.com/sandbox/1-0-preview/) | +| First Worker, wrangler, Dockerfile | [Get started](https://developers.cloudflare.com/sandbox/1-0-preview/get-started/) | +| `exec`, handles, readiness, durability | [Process execution](https://developers.cloudflare.com/sandbox/1-0-preview/processes/) | +| Process API signatures | [Processes API](https://developers.cloudflare.com/sandbox/1-0-preview/api/processes/) | +| Sandbox ID vs container vs sleep/destroy | [Lifecycle](https://developers.cloudflare.com/sandbox/1-0-preview/lifecycle/) | +| `cwd` / `env` / `setEnvVars` | [Environment](https://developers.cloudflare.com/sandbox/1-0-preview/environment/) | +| Interactive PTY / browser terminal | [Terminals](https://developers.cloudflare.com/sandbox/1-0-preview/terminals/) · [Terminals API](https://developers.cloudflare.com/sandbox/1-0-preview/api/terminals/) | +| Python/JS code interpreter | [Interpreter](https://developers.cloudflare.com/sandbox/1-0-preview/interpreter/) · [Interpreter API](https://developers.cloudflare.com/sandbox/1-0-preview/api/interpreter/) | +| Extensions model | [Extensions](https://developers.cloudflare.com/sandbox/1-0-preview/extensions/) | +| Error classes and recovery | [Errors](https://developers.cloudflare.com/sandbox/1-0-preview/errors/) · [Errors API](https://developers.cloudflare.com/sandbox/1-0-preview/api/errors/) | +| Common failures | [Troubleshooting](https://developers.cloudflare.com/sandbox/1-0-preview/troubleshooting/) | +| API hub | [API reference](https://developers.cloudflare.com/sandbox/1-0-preview/api/) | +| Files, mounts, backups, ports, tunnels, `proxyToSandbox` | Main docs for shared surfaces (ignore stable-only session/transport/`sandbox.terminal`): [Files](https://developers.cloudflare.com/sandbox/api/files/) · [Storage / mounts](https://developers.cloudflare.com/sandbox/api/storage/) · [Ports](https://developers.cloudflare.com/sandbox/api/ports/) · [Tunnels](https://developers.cloudflare.com/sandbox/api/tunnels/) · [Backups](https://developers.cloudflare.com/sandbox/api/backups/) · [Outbound traffic](https://developers.cloudflare.com/sandbox/guides/outbound-traffic/) · [Expose services](https://developers.cloudflare.com/sandbox/guides/expose-services/) · [Production](https://developers.cloudflare.com/sandbox/guides/production-deployment/) | +| Example apps | [examples on `next`](https://github.com/cloudflare/sandbox-sdk/tree/next/examples) | +| Still on stable package | **`sandbox-stable`** · [Main Sandbox docs](https://developers.cloudflare.com/sandbox/) | +| Porting an existing stable app | **`sandbox-migrate-to-next`** · [Migrate](https://developers.cloudflare.com/sandbox/1-0-preview/migrate/) | + +## 4. Before you ship + +- Lockfile and Dockerfile on the **same** `@next` line +- Typecheck against installed `@next` types +- No live secrets in sandbox env +- Production preview hostnames need wildcard DNS on a custom domain when using those URL patterns diff --git a/skills/sandbox-next/references/api-quick-ref.md b/skills/sandbox-next/references/api-quick-ref.md index ee641be..bdff423 100644 --- a/skills/sandbox-next/references/api-quick-ref.md +++ b/skills/sandbox-next/references/api-quick-ref.md @@ -1,8 +1,8 @@ -# Sandbox SDK API quick reference (`@next`) +# `@next` API quick reference -Canonical docs: https://developers.cloudflare.com/sandbox/1-0-preview/api/ +Canonical: https://developers.cloudflare.com/sandbox/1-0-preview/api/ -Prefer installed `@cloudflare/sandbox@next` types. Stable package APIs differ (string `exec`, sessions, etc.). +Prefer installed `@cloudflare/sandbox@next` types. This file is a scan aid only. ## Lifecycle @@ -11,12 +11,13 @@ getSandbox(binding, sandboxId, options?: { sleepAfter?: string | number; keepAlive?: boolean; normalizeId?: boolean; - // no transport / enableDefaultSession on @next }): Sandbox await sandbox.destroy(): Promise ``` +No `transport` / `enableDefaultSession` on `@next`. + ## Processes ```ts @@ -26,12 +27,9 @@ await sandbox.exec(argv: readonly [string, ...string[]], options?: { timeout?: number; // remote process lifetime }): Promise -await sandbox.getProcess(id: string): Promise // non-waking +await sandbox.getProcess(id: string): Promise await sandbox.listProcesses(): Promise -// handle -process.id -process.pid await process.output({ encoding?: "utf8"; maxBytes?; timeout?; signal? }) await process.logs({ since?; replay?; follow?; signal? }) await process.waitForExit({ timeout?; signal? }) @@ -41,16 +39,12 @@ await process.kill(signal?: number) // default 15 await process.status() ``` -`await exec` = launch succeeded, not exit. No process stdin. +`await exec` = launch succeeded. No process stdin. ## Terminals ```ts -await sandbox.createTerminal({ - command: readonly [string, ...string[]]; - cwd?; env?; cols?; rows?; bufferSize?; -}): Promise - +await sandbox.createTerminal({ command: readonly [string, ...string[]]; cwd?; env?; cols?; rows?; bufferSize? }) await sandbox.getTerminal(id): Promise await sandbox.listTerminals(): Promise @@ -62,7 +56,7 @@ await terminal.interrupt() await terminal.terminate() ``` -## Interpreter (extension) +## Interpreter ```ts import { withInterpreter } from "@cloudflare/sandbox/interpreter"; @@ -70,7 +64,7 @@ import { withInterpreter } from "@cloudflare/sandbox/interpreter"; await sandbox.interpreter.createCodeContext({ language?, cwd? }) await sandbox.interpreter.runCode(code, { context?, language?, onStdout?, ... }) -await sandbox.interpreter.runCodeStream(code, { context?, language? }) // SSE; callbacks not used +await sandbox.interpreter.runCodeStream(code, { context?, language? }) await sandbox.interpreter.listCodeContexts() await sandbox.interpreter.deleteCodeContext(id) ``` @@ -78,12 +72,7 @@ await sandbox.interpreter.deleteCodeContext(id) ## Environment ```ts -await sandbox.setEnvVars(Record) // undefined removes -// plus env on exec / createTerminal +await sandbox.setEnvVars(Record) ``` -Non-secret config only. Secrets: Worker + outbound handlers. - -## Errors (common) - -`ContainerUnavailableError`, `OperationInterruptedError`, `RPCTransportError`, `StaleProcessHandleError`, `StaleTerminalHandleError`, process wait/spawn errors — see https://developers.cloudflare.com/sandbox/1-0-preview/api/errors/ +Non-secret only. Secrets: Worker + outbound handlers. diff --git a/skills/sandbox-next/references/examples.md b/skills/sandbox-next/references/examples.md index 39cb0ca..d0f9368 100644 --- a/skills/sandbox-next/references/examples.md +++ b/skills/sandbox-next/references/examples.md @@ -1,15 +1,13 @@ -# Sandbox SDK examples +# `@next` examples -Branch aligned with preview: https://github.com/cloudflare/sandbox-sdk/tree/next/examples +https://github.com/cloudflare/sandbox-sdk/tree/next/examples -| Example | Use case | +| Example | Use when | | ------- | -------- | -| `minimal` | Basic `@next` setup | +| `minimal` | Basic `@next` Worker | | `code-interpreter` | `withInterpreter` | -| `openai-agents` | OpenAI adapters | -| `opencode` | OpenCode extension | -| `claude-code` / `codex` | Agent harnesses + argv `exec` / git via exec | -| `collaborative-terminal` / `s3-mount` | Terminals | +| `openai-agents` / `opencode` / `claude-code` / `codex` | Agent harnesses | +| `collaborative-terminal` / `s3-mount` | Terminals / mounts | | `authentication` | Multi-user sandbox IDs | -Prefer examples on the **`next`** branch when building for `@cloudflare/sandbox@next`. +Use the **`next`** branch for `@cloudflare/sandbox@next`. diff --git a/skills/sandbox-stable/SKILL.md b/skills/sandbox-stable/SKILL.md index f50ff19..8faf22b 100644 --- a/skills/sandbox-stable/SKILL.md +++ b/skills/sandbox-stable/SKILL.md @@ -1,133 +1,110 @@ --- name: sandbox-stable -description: Use when building or changing Cloudflare Sandbox apps on the current stable @cloudflare/sandbox package (default npm tag)—commands, sessions, files, ports, tunnels, bridge, or deprecated-API cleanup while staying on stable. Not for @cloudflare/sandbox@next (use sandbox-next) or for porting to 1.0 (use sandbox-migrate-to-next). +description: Use when building or changing Cloudflare Sandbox apps on the current stable @cloudflare/sandbox package (default npm tag)—commands, sessions, files, ports, tunnels, terminals, bridge, production, or deprecated-API cleanup while staying on stable. Not for @cloudflare/sandbox@next (use sandbox-next) or for porting to 1.0 (use sandbox-migrate-to-next). --- -# Cloudflare Sandbox SDK (stable package) +# Sandbox SDK — stable package Isolated Linux environments on [Cloudflare Containers](https://developers.cloudflare.com/containers/), driven from Workers. -This skill is the **current stable** line: default `@cloudflare/sandbox` (today’s published package) and a **matching** stable container image. The main [Sandbox documentation](https://developers.cloudflare.com/sandbox/) describes this package. +**Prefer the main Sandbox docs and installed stable types over memory.** This skill is a gate, a contract, and a retrieval map—not a full manual. -We recommend starting **new** projects on the [1.0 preview](https://developers.cloudflare.com/sandbox/1-0-preview/) (`@cloudflare/sandbox@next`) with **`sandbox-next`**. Existing apps can stay on stable and keep shipping. When you can, plan a move with **`sandbox-migrate-to-next`** so you are ready when 1.0 becomes the stable release. +This line is the **current stable** default npm package. The main [Sandbox documentation](https://developers.cloudflare.com/sandbox/) describes it. Existing apps can stay here and keep shipping. -Prefer stable docs and installed package types over memory. Do not apply `@next` API shapes here. +We recommend **new projects** on `@cloudflare/sandbox@next` with **`sandbox-next`**. When you can, plan a move with **`sandbox-migrate-to-next`** so you are ready when 1.0 becomes the stable release. Do not force that port unless the user asks. -## Confirm the package line +## 1. Gate — confirm the package line -Before writing code, check the app: +Before writing code, inspect the app: -- Dependency is default `@cloudflare/sandbox` (**not** `@next` / preview tags), **and** -- Container image matches that stable line (not `cloudflare/sandbox:next`) +| Check | Must match | +| ----- | ---------- | +| npm dependency | Default `@cloudflare/sandbox` (**not** `@next` / preview tags) | +| Container image | Matching **stable** image (not `cloudflare/sandbox:next`) | -| If you find… | Do this | -| ------------ | ------- | -| `@cloudflare/sandbox@next` (or preview image) | Stop. Use **`sandbox-next`**. | -| User wants to **port** to 1.0 / `@next` | Stop. Use **`sandbox-migrate-to-next`**. Do not half-apply preview APIs while the package is still stable. | -| Only cleaning deprecated stable APIs | Stay on this skill + [2026 deprecation guide](https://developers.cloudflare.com/sandbox/guides/2026-deprecation/). That is **not** a move to `@next`. | +| If you find… | Action | +| ------------ | ------ | +| `@cloudflare/sandbox@next` or a `next` image | **Stop.** Load **`sandbox-next`**. | +| User wants to port to 1.0 / `@next` | **Stop.** Load **`sandbox-migrate-to-next`**. Do not half-apply preview APIs on a stable package. | +| Only cleaning deprecated stable APIs | Stay here; use the [2026 deprecation guide](https://developers.cloudflare.com/sandbox/guides/2026-deprecation/). That is **not** a move to `@next`. | Never mix a stable Worker package with an `@next` container image (or the reverse). -Install skills: [Agent setup](https://developers.cloudflare.com/agent-setup/) · [cloudflare/skills](https://github.com/cloudflare/skills). - -## Retrieval - -| Topic | URL | -| ----- | --- | -| Overview | https://developers.cloudflare.com/sandbox/ | -| Get started | https://developers.cloudflare.com/sandbox/get-started/ | -| Commands | https://developers.cloudflare.com/sandbox/api/commands/ | -| Sessions | https://developers.cloudflare.com/sandbox/concepts/sessions/ · https://developers.cloudflare.com/sandbox/api/sessions/ | -| Lifecycle / options | https://developers.cloudflare.com/sandbox/api/lifecycle/ · https://developers.cloudflare.com/sandbox/configuration/sandbox-options/ | -| Files | https://developers.cloudflare.com/sandbox/api/files/ | -| Ports / tunnels | https://developers.cloudflare.com/sandbox/api/ports/ · https://developers.cloudflare.com/sandbox/api/tunnels/ | -| Terminal | https://developers.cloudflare.com/sandbox/api/terminal/ · https://developers.cloudflare.com/sandbox/concepts/terminal/ | -| Code interpreter | https://developers.cloudflare.com/sandbox/api/interpreter/ · https://developers.cloudflare.com/sandbox/guides/code-execution/ | -| Environment | https://developers.cloudflare.com/sandbox/configuration/environment-variables/ | -| Bridge | https://developers.cloudflare.com/sandbox/bridge/ | -| Deprecated APIs (stay on stable) | https://developers.cloudflare.com/sandbox/guides/2026-deprecation/ | -| 1.0 preview (when ready to move) | https://developers.cloudflare.com/sandbox/1-0-preview/ | - -Fetch the relevant page when implementing. Installed **stable** types win over guesses. - -## Install - -```bash -npm install @cloudflare/sandbox -docker info # local container dev -``` +Skills install: [Agent setup](https://developers.cloudflare.com/agent-setup/) · [cloudflare/skills](https://github.com/cloudflare/skills) + +## 2. Contract — non-negotiables -Use a stable container image tag that matches your SDK release (see Dockerfile in the template / docs). Do not switch the image to `next` unless the Worker package moves too. +- `await sandbox.exec(command)` takes a **command string** and resolves when the command **finishes**, with buffered `stdout` / `stderr` / `exitCode` (and related fields). +- Long-running and streaming work use the **stable** command APIs (`startProcess`, `execStream`, and related helpers)—not the `@next` single-handle model. Open the Commands docs; do not invent `@next` `output()` handles on stable. +- **Sessions** can preserve working directory and environment across commands (default session / `enableDefaultSession`, `createSession`). See Sessions docs when state must carry across calls. +- Interactive browser terminals often use **`sandbox.terminal(request)`** and session/xterm helpers on stable—not preview `createTerminal` unless the package is `@next`. +- Prefer **RPC** transport when using tunnels or large/binary streaming. HTTP/WebSocket transports are deprecated (cleanup guide below). +- Files, mounts, ports, tunnels, backups, lifecycle, and interpreter: use main docs for signatures; trust installed **stable** types. +- Non-secret config in sandbox env; live credentials in the Worker. Use outbound handlers when processes call external APIs. +- Production preview hostnames need wildcard DNS on a custom domain when using those URL patterns. +- Do **not** apply `@next` argv/`process.output()` APIs while the dependency is still stable. +- Self-deployed **bridge** stays on the stable package and image. [Bridge](https://developers.cloudflare.com/sandbox/bridge/) -## Worker shape +Minimal shape: ```ts import { getSandbox, proxyToSandbox, Sandbox } from "@cloudflare/sandbox"; export { Sandbox }; -export default { - async fetch(request: Request, env: Env): Promise { - const proxy = await proxyToSandbox(request, env); - if (proxy) return proxy; - - const sandbox = getSandbox(env.Sandbox, "user-123"); - // Stable: exec takes a command string and resolves when the command finishes - const result = await sandbox.exec('python3 -c "print(2 + 2)"'); - return Response.json({ - output: result.stdout, - exitCode: result.exitCode, - success: result.success, - }); - }, -}; -``` - -See [Get started](https://developers.cloudflare.com/sandbox/get-started/) for wrangler / Dockerfile binding details. - -## Core model (stable) - -- `await sandbox.exec(command)` runs a **shell command string** and resolves when the command **finishes**, with buffered `stdout` / `stderr` / `exitCode`. -- Long-running or streaming work often uses **`startProcess`** / **`execStream`** (and related helpers) — not the `@next` single-handle model. Follow [Commands](https://developers.cloudflare.com/sandbox/api/commands/). -- **Sessions** can preserve working directory and env across commands (`createSession`, default session / `enableDefaultSession`). See [Sessions](https://developers.cloudflare.com/sandbox/concepts/sessions/). -- Interactive browser terminals often use **`sandbox.terminal(request)`** and related session/xterm helpers — [Terminal](https://developers.cloudflare.com/sandbox/api/terminal/). -- Code interpreter methods may live on `Sandbox` on stable — [Interpreter API](https://developers.cloudflare.com/sandbox/api/interpreter/). -- Files, mounts, ports, tunnels, backups, and lifecycle options: use main docs for signatures. -- Prefer **RPC** transport for tunnels and large/binary streaming. HTTP/WebSocket transports are deprecated — see cleanup below. -- Non-secret config in sandbox env; live credentials in the Worker. [Outbound traffic](https://developers.cloudflare.com/sandbox/guides/outbound-traffic/) when processes call external APIs. -- Production preview hostnames need wildcard DNS on a custom domain (`.workers.dev` is not enough for those patterns). - -```ts -// Short command (stable) -const result = await sandbox.exec("node --version"); -console.log(result.stdout, result.exitCode); - -// Background-style work — use stable APIs from the Commands docs, e.g. startProcess -// const proc = await sandbox.startProcess("node server.js"); +const sandbox = getSandbox(env.Sandbox, "user-123"); +const result = await sandbox.exec('python3 -c "print(2 + 2)"'); +// result.stdout, result.exitCode, result.success ``` -## Deprecated APIs while staying on stable - -If the app still uses HTTP/WebSocket transport, default sessions you want off, `exposePort` where tunnels fit, or stream-only helpers, follow the checklist in the [2026 deprecation guide](https://developers.cloudflare.com/sandbox/guides/2026-deprecation/). That cleanup **keeps** the stable package; it is not Sandbox SDK 1.0. +## 3. Retrieve — open the doc for the task + +Fetch the page before implementing. Installed stable types win over guesses. + +| You need to… | Open | +| ------------ | ---- | +| Orient | [Sandbox overview](https://developers.cloudflare.com/sandbox/) | +| First Worker, template, Docker | [Get started](https://developers.cloudflare.com/sandbox/get-started/) | +| `exec`, streaming, background processes | [Commands API](https://developers.cloudflare.com/sandbox/api/commands/) · [Execute commands](https://developers.cloudflare.com/sandbox/guides/execute-commands/) · [Background processes](https://developers.cloudflare.com/sandbox/guides/background-processes/) · [Streaming output](https://developers.cloudflare.com/sandbox/guides/streaming-output/) | +| Sessions / shell state across commands | [Sessions concept](https://developers.cloudflare.com/sandbox/concepts/sessions/) · [Sessions API](https://developers.cloudflare.com/sandbox/api/sessions/) | +| `getSandbox` options, sleep, destroy | [Lifecycle API](https://developers.cloudflare.com/sandbox/api/lifecycle/) · [Sandbox options](https://developers.cloudflare.com/sandbox/configuration/sandbox-options/) | +| Env vars | [Environment variables](https://developers.cloudflare.com/sandbox/configuration/environment-variables/) | +| Files | [Files API](https://developers.cloudflare.com/sandbox/api/files/) · [Manage files](https://developers.cloudflare.com/sandbox/guides/manage-files/) · [File watching](https://developers.cloudflare.com/sandbox/api/file-watching/) | +| Buckets / mounts | [Storage API](https://developers.cloudflare.com/sandbox/api/storage/) · [Mount buckets](https://developers.cloudflare.com/sandbox/guides/mount-buckets/) | +| Backups | [Backups API](https://developers.cloudflare.com/sandbox/api/backups/) · [Backup and restore](https://developers.cloudflare.com/sandbox/guides/backup-restore/) | +| Ports, preview URLs, expose | [Ports API](https://developers.cloudflare.com/sandbox/api/ports/) · [Expose services](https://developers.cloudflare.com/sandbox/guides/expose-services/) | +| Tunnels | [Tunnels API](https://developers.cloudflare.com/sandbox/api/tunnels/) | +| Proxy / Workers connections | [Proxy requests](https://developers.cloudflare.com/sandbox/guides/proxy-requests/) · [Workers connections](https://developers.cloudflare.com/sandbox/guides/workers-connections/) | +| Browser / PTY terminal | [Terminal API](https://developers.cloudflare.com/sandbox/api/terminal/) · [Terminal concept](https://developers.cloudflare.com/sandbox/concepts/terminal/) · [Browser terminals](https://developers.cloudflare.com/sandbox/guides/browser-terminals/) | +| Code interpreter | [Interpreter API](https://developers.cloudflare.com/sandbox/api/interpreter/) · [Code execution](https://developers.cloudflare.com/sandbox/guides/code-execution/) | +| Git in the sandbox | [Git workflows](https://developers.cloudflare.com/sandbox/guides/git-workflows/) | +| Secrets / egress | [Outbound traffic](https://developers.cloudflare.com/sandbox/guides/outbound-traffic/) | +| WebSockets | [WebSocket connections](https://developers.cloudflare.com/sandbox/guides/websocket-connections/) | +| Docker-in-Docker | [Docker in Docker](https://developers.cloudflare.com/sandbox/guides/docker-in-docker/) | +| Production deploy | [Production deployment](https://developers.cloudflare.com/sandbox/guides/production-deployment/) | +| Containers concept | [Containers](https://developers.cloudflare.com/sandbox/concepts/containers/) | +| How-to index | [Guides](https://developers.cloudflare.com/sandbox/guides/) | +| API index | [API reference](https://developers.cloudflare.com/sandbox/api/) | +| Deprecated APIs **while staying on stable** | [2026 deprecation guide](https://developers.cloudflare.com/sandbox/guides/2026-deprecation/) | +| Self-deployed bridge | [Bridge](https://developers.cloudflare.com/sandbox/bridge/) · [Bridge HTTP API](https://developers.cloudflare.com/sandbox/bridge/http-api/) | +| Examples (stable/`main`) | [examples on GitHub](https://github.com/cloudflare/sandbox-sdk/tree/main/examples) | +| New work on 1.0 preview | **`sandbox-next`** · [1.0 preview](https://developers.cloudflare.com/sandbox/1-0-preview/) | +| Port existing app to `@next` | **`sandbox-migrate-to-next`** · [Migrate](https://developers.cloudflare.com/sandbox/1-0-preview/migrate/) | + +### Deprecated-API cleanup (stay on stable) + +Update package + matching image first, then follow the guide. Typical search: ```sh rg 'SANDBOX_TRANSPORT|transport:|exposePort\(|enableDefaultSession|execStream\(|readFileStream|writeFileStream' ``` -Update package + matching image first, switch to RPC, then adjust ports/sessions/streaming per that guide. - -## Bridge - -Self-deployed Sandbox bridge stays on the **stable** package and image. Keep Worker, image, and clients on the same stable line. [Bridge](https://developers.cloudflare.com/sandbox/bridge/). - -## When to upgrade - -Stable remains published and supported for existing apps. When the team has time, move to `@cloudflare/sandbox@next` with **`sandbox-migrate-to-next`** and the [Migrate guide](https://developers.cloudflare.com/sandbox/1-0-preview/migrate/). Do **not** force production cutover unless the user asked for it. +This path does **not** switch you to `@next`. -## Common mistakes +## 4. Before you ship -- Applying `@next` argv/`output()` handle APIs while the package is still stable -- Mixing stable Worker with `cloudflare/sandbox:next` image -- Treating “deprecated API cleanup” as “must move to `@next` today” -- Putting API keys in sandbox env -- Guessing APIs instead of stable docs + installed types +- Worker package and container image on the **same stable** line +- Typecheck against installed stable types +- No live secrets in sandbox env +- If using deprecated transports/helpers, finish or track [2026 deprecation](https://developers.cloudflare.com/sandbox/guides/2026-deprecation/) cleanup +- When the team is ready for 1.0, use **`sandbox-migrate-to-next`**—do not force cutover unprompted From 6ac5694a2a23bb03fb1d891afc770601e39b7c0f Mon Sep 17 00:00:00 2001 From: Naresh Date: Fri, 7 Aug 2026 17:47:47 +0100 Subject: [PATCH 5/5] Clarify @next API file is a cheatsheet only Point exhaustive reading at types and docs so agents do not treat the process/terminal stub as the full Sandbox surface. --- skills/sandbox-next/SKILL.md | 2 +- .../sandbox-next/references/api-quick-ref.md | 34 ++++++++++++++----- skills/sandbox-next/references/examples.md | 6 ++-- 3 files changed, 30 insertions(+), 12 deletions(-) diff --git a/skills/sandbox-next/SKILL.md b/skills/sandbox-next/SKILL.md index 777403a..6384327 100644 --- a/skills/sandbox-next/SKILL.md +++ b/skills/sandbox-next/SKILL.md @@ -57,7 +57,7 @@ const result = await process.output({ encoding: "utf8" }); // result.stdout, result.exitCode ``` -Optional signature cheat sheet: [references/api-quick-ref.md](references/api-quick-ref.md) +Optional **non-exhaustive** cheatsheet (process/terminal/interpreter only): [references/api-quick-ref.md](references/api-quick-ref.md) Examples index (`next` branch): [references/examples.md](references/examples.md) ## 3. Retrieve — open the doc for the task diff --git a/skills/sandbox-next/references/api-quick-ref.md b/skills/sandbox-next/references/api-quick-ref.md index bdff423..8c2eec1 100644 --- a/skills/sandbox-next/references/api-quick-ref.md +++ b/skills/sandbox-next/references/api-quick-ref.md @@ -1,10 +1,21 @@ -# `@next` API quick reference +# `@next` cheatsheet (not the full API) -Canonical: https://developers.cloudflare.com/sandbox/1-0-preview/api/ +Scan aid for the **process / terminal / interpreter** shapes that differ most from stable. **Not exhaustive.** -Prefer installed `@cloudflare/sandbox@next` types. This file is a scan aid only. +| For… | Go here | +| ---- | ------- | +| Full signatures and types | Installed `@cloudflare/sandbox@next` package types | +| Preview API hub | https://developers.cloudflare.com/sandbox/1-0-preview/api/ | +| Processes · terminals · errors · interpreter | Same hub (dedicated pages) | +| Files, mounts, backups, ports, tunnels, lifecycle options | Main docs linked from the hub and from **`sandbox-next`** § Retrieve — ignore stable-only session/transport bits | +| Mental model (exec, durability, ID vs container) | https://developers.cloudflare.com/sandbox/1-0-preview/processes/ · https://developers.cloudflare.com/sandbox/1-0-preview/lifecycle/ | +| `Sandbox` extends `Container` | [Cloudflare Containers](https://developers.cloudflare.com/containers/) + Sandbox lifecycle docs above | -## Lifecycle +If something is missing here, it is almost certainly **documented elsewhere or in types**—do not invent it from this file. + +--- + +## Lifecycle (common options) ```ts getSandbox(binding, sandboxId, options?: { @@ -39,12 +50,16 @@ await process.kill(signal?: number) // default 15 await process.status() ``` -`await exec` = launch succeeded. No process stdin. +`await exec` = launch succeeded, not exit. No process stdin. ## Terminals ```ts -await sandbox.createTerminal({ command: readonly [string, ...string[]]; cwd?; env?; cols?; rows?; bufferSize? }) +await sandbox.createTerminal({ + command: readonly [string, ...string[]]; + cwd?; env?; cols?; rows?; bufferSize?; +}): Promise + await sandbox.getTerminal(id): Promise await sandbox.listTerminals(): Promise @@ -56,7 +71,7 @@ await terminal.interrupt() await terminal.terminate() ``` -## Interpreter +## Interpreter (extension) ```ts import { withInterpreter } from "@cloudflare/sandbox/interpreter"; @@ -72,7 +87,8 @@ await sandbox.interpreter.deleteCodeContext(id) ## Environment ```ts -await sandbox.setEnvVars(Record) +await sandbox.setEnvVars(Record) // undefined removes +// plus env on exec / createTerminal ``` -Non-secret only. Secrets: Worker + outbound handlers. +Non-secret config only. Secrets: Worker + outbound handlers. diff --git a/skills/sandbox-next/references/examples.md b/skills/sandbox-next/references/examples.md index d0f9368..49c75aa 100644 --- a/skills/sandbox-next/references/examples.md +++ b/skills/sandbox-next/references/examples.md @@ -1,4 +1,6 @@ -# `@next` examples +# `@next` examples index + +Pointers only—not a full catalog. Prefer the repo tree and docs. https://github.com/cloudflare/sandbox-sdk/tree/next/examples @@ -10,4 +12,4 @@ https://github.com/cloudflare/sandbox-sdk/tree/next/examples | `collaborative-terminal` / `s3-mount` | Terminals / mounts | | `authentication` | Multi-user sandbox IDs | -Use the **`next`** branch for `@cloudflare/sandbox@next`. +Use the **`next`** branch for `@cloudflare/sandbox@next`. \ No newline at end of file