---
description: Move @cloudflare/sandbox 0.12 Docker-in-Docker images, binding handlers, and the opencode, openai, and bridge subpaths to 1.0, and remove WarmPool.
title: Move other 0.x features
image: https://developers.cloudflare.com/sandbox/sdk/migrate/other-features/og.png?v=f9210298c4783c03
---

[Skip to content](#main-content)

> Documentation Index  
> Fetch the complete documentation index at: https://developers.cloudflare.com/sandbox/llms.txt  
> Use this file to discover all available pages before exploring further.

# Move other 0.x features

Last updated Sep 30, 2026|Copy as Markdown| [View as Markdown](https://developers.cloudflare.com/sandbox/sdk/migrate/other-features/index.md)| [Agent setup](https://developers.cloudflare.com/agent-setup/)

This page replaces or removes the Sandbox SDK 0.12 features that have no class in 1.0. Each section stands alone. Follow only the sections for the features that your application uses.

## Before you start

Your 1.0 class replaces the 0.12 `Sandbox` class, and has the `container` getter, the `ensureRunning()` and `startContainer()` methods, and the `ENV` constant from [Replace the Sandbox class](https://developers.cloudflare.com/sandbox/sdk/migrate/replace-the-sandbox-class/). A class that you reach through `this.ctx.exports` needs compatibility date `2025-11-17` or later, or the `enable_ctx_exports` flag.

Each 0.12 feature has one section:

| 0.12 feature | Section |
| --- | --- |
| Docker in a `docker:dind-rootless` image | [Run Docker inside the sandbox](#run-docker-inside-the-sandbox) |
| `outboundByHost` handlers that read bindings | [Reach Workers bindings from the container](#reach-workers-bindings-from-the-container) |
| `@cloudflare/sandbox/opencode` | [Start an OpenCode server](#start-an-opencode-server) |
| `@cloudflare/sandbox/openai` | [Give OpenAI agents a shell and an editor](#give-openai-agents-a-shell-and-an-editor) |
| `@cloudflare/sandbox/bridge` | [Replace the bridge](#replace-the-bridge) |
| `WarmPool` | [Remove WarmPool](#remove-warmpool) |

## Run Docker inside the sandbox

The 0.x Docker setup starts from `docker:dind-rootless`, switches to `USER root`, and copies in the musl build of the 0.x server. On a 1.0 container, its Docker daemon exits with `failed to set IP forwarding '/proc/sys/net/ipv4/ip_forward' = '1': open /proc/sys/net/ipv4/ip_forward: read-only file system`.

1. Replace your `Dockerfile`:

   *Dockerfiledockerfile*

   

   ```dockerfile
   FROM docker:dind

   COPY --from=docker.io/cloudflare/sandbox:1.0.0 /usr/local/bin/sandbox-shim /usr/local/bin/sandbox-shim

   ENTRYPOINT ["sh", "-c", "dockerd-entrypoint.sh dockerd --iptables=false --ip6tables=false --ip-forward=false > /var/log/dockerd.log 2>&1 & exec sleep infinity"]
   ```

   The Docker daemon runs as `root`, with iptables and IP forwarding turned off. It logs to `/var/log`, because the `docker:dind` entrypoint mounts an empty `/tmp`. `sleep infinity` keeps the container running. Keep the `COPY` line only if your class uses `Files` or `S3Mount`. `sandbox-shim` is statically linked, so it runs on the Alpine-based `docker:dind` image.
2. Keep `enableInternet: true` in `start()`, so that Docker can pull images. 0.12 allowed Internet access by default.
3. Wait for Docker, and run containers with `--network=host`:

   *src/index.ts (0.12)ts*

   

   ```ts
   const sandbox = getSandbox(env.Sandbox, "docker-sandbox");
   const run = await sandbox.exec(
   	"docker run --rm --network=host alpine:3.22 " +
   		"echo Hello from Docker",
   );
   ```

   *src/index.ts (1.0)ts*

   

   ```ts
   export class MySandbox extends DurableObject<Env> {
   	// ...

   	private async waitForDocker(): Promise<void> {
   		const wait = await this.container.exec([
   			"timeout",
   			"30",
   			"sh",
   			"-c",
   			"until docker version > /dev/null 2>&1; do sleep 0.2; done",
   		]);

   		if ((await wait.exitCode) !== 0) {
   			throw new Error("Docker did not start within 30 seconds");
   		}
   	}

   	async runImage(): Promise<string> {
   		await this.ensureRunning();
   		// The Docker daemon starts after the container, so wait for it
   		await this.waitForDocker();

   		const run = await this.container.exec(
   			[
   				"docker",
   				"run",
   				"--rm",
   				"--network=host",
   				"alpine:3.22",
   				"echo",
   				"Hello from Docker",
   			],
   			{ env: ENV },
   		);
   		const result = await run.output();
   		return new TextDecoder().decode(result.stdout);
   	}
   }
   ```

   Without `--network=host`, `docker run` fails with `failed to disable IPv6 on container's interface eth0`. A `docker build` step that uses the network, such as a package install, also needs `docker build --network=host`. An inner container started this way shares the network access of the sandbox.
4. Call `runImage()` from your Worker. It returns `Hello from Docker`. The first call also pulls `alpine:3.22`, and Docker writes its progress to `stderr`.

For more information, refer to [Docker-in-Docker in the Containers FAQ](https://developers.cloudflare.com/containers/faq/#can-i-run-docker-inside-a-container-docker-in-docker).

## Reach Workers bindings from the container

In 0.12, an `outboundByHost` handler answered requests to a hostname such as `my.kv`, and read Workers bindings from its `env` argument. In 1.0, a `WorkerEntrypoint` answers them, and your Durable Object registers it for that hostname.

1. Replace each handler with a `WorkerEntrypoint`, and export it from the main module of your Worker:

   *src/index.ts (0.12)ts*

   

   ```ts
   MySandbox.outboundByHost = {
   	"my.kv": async (request: Request, env: Env) => {
   		const key = new URL(request.url).pathname.slice(1);
   		const value = await env.KV.get(key);
   		return new Response(value ?? "", {
   			status: value ? 200 : 404,
   		});
   	},
   };
   ```

   *src/index.ts (1.0)ts*

   

   ```ts
   import { WorkerEntrypoint } from "cloudflare:workers";

   type KvProps = { containerId: string };

   export class KvGateway extends WorkerEntrypoint<Env, KvProps> {
   	async fetch(request: Request): Promise<Response> {
   		const key = new URL(request.url).pathname.slice(1);
   		const value = await this.env.KV.get(key);
   		return new Response(value ?? "", {
   			status: value === null ? 404 : 200,
   		});
   	}
   }
   ```

   `this.env` has the same bindings as the `env` argument. Where a 0.12 handler read `ctx.containerId`, read `this.ctx.props.containerId`.
2. Register the entrypoint in the `try` block of `startContainer()`:

   *src/index.tsts*

   

   ```ts
   export class MySandbox extends DurableObject<Env> {
   	// ...

   	private async startContainer(): Promise<void> {
   		const newContainer = !this.container.running;

   		if (newContainer) {
   			this.container.start({
   				image: this.container.images.sandbox,
   				instance: "standard-1",
   				env: ENV,
   				// 0.12 allowed Internet access by default.
   				enableInternet: true,
   			});
   		}

   		try {
   			if (newContainer) {
   				// Replaces onStart().
   				await this.ctx.storage.put("startedAt", Date.now());
   			}
   			await this.container.interceptOutboundHttp(
   				"my.kv",
   				this.ctx.exports.KvGateway({
   					props: { containerId: this.ctx.id.toString() },
   				}),
   			);
   			await this.container.setInactivityTimeout(
   				INACTIVITY_TIMEOUT_MS,
   			);
   		} catch (error) {
   			// The next request starts a new container.
   			await this.container.destroy();
   			throw error;
   		}
   	}
   }
   ```

   `this.ctx.id.toString()` is the value that 0.12 passed as `containerId`, so keys and paths built from it stay the same. The intercept also works with `enableInternet: false`. Register one entrypoint for each hostname.

   If your class also uses the `Outbound` entrypoint from [Move outbound rules](https://developers.cloudflare.com/sandbox/sdk/migrate/outbound-traffic/), add the handler to its `HANDLERS` map instead. A hostname intercept that you register after `interceptAllOutboundHttp()` receives no requests.
3. Request the hostname from the container. After you store `hello from KV` under the key `greeting`, this command prints the value:

   ```sh
   node -e 'fetch("http://my.kv/greeting").then(async (r) => console.log(r.status, await r.text()))'
   ```

   ```txt
   200 hello from KV
   ```



## Start an OpenCode server

In 0.12, `createOpencode()` started `opencode serve` in the sandbox, and returned an OpenCode SDK client that reached it through the sandbox. In 1.0, your Durable Object starts the server and creates the client, with a `fetch` function that connects to the server port.

1. Install OpenCode in your `Dockerfile`, as in [Run OpenCode in a sandbox](https://developers.cloudflare.com/sandbox/coding-agents/opencode/#switch-the-worker-to-opencode):

   *Dockerfiledockerfile*

   

   ```dockerfile
   RUN npm install --global --ignore-scripts opencode-linux-x64-baseline@1.18.32 \
   	&& ln -s /usr/local/lib/node_modules/opencode-linux-x64-baseline/bin/opencode /usr/local/bin/opencode
   ```

   The 0.12 `opencode` image included OpenCode. Start the container with the `standard-1` instance type or larger, as `startContainer()` does. On `lite`, the server did not answer requests within 30 seconds.
2. Install the OpenCode SDK in your Worker project:npmyarnpnpmbun

   ```
   npm i @opencode-ai/sdk@1.18.32
   ```

   ```
   yarn add @opencode-ai/sdk@1.18.32
   ```

   ```
   pnpm add @opencode-ai/sdk@1.18.32
   ```

   ```
   bun add @opencode-ai/sdk@1.18.32
   ```


3. Replace `createOpencode()` with a method that starts the server once for each container. It uses the scripts and functions from step 1 of [Run a server in the background](https://developers.cloudflare.com/sandbox/commands/run-a-server-in-the-background/#run-a-server):

   *src/index.ts (0.12)ts*

   

   ```ts
   const sandbox = getSandbox(env.Sandbox, "my-agent");
   const { client } = await createOpencode(sandbox, {
   	directory: "/workspace",
   	config: OPENCODE_CONFIG,
   });
   const session = await client.session.create({ title: "Fix tests" });
   ```

   *src/index.ts (1.0)ts*

   

   ```ts
   import {
   	createOpencodeClient,
   	type OpencodeClient,
   } from "@opencode-ai/sdk/v2/client";

   const OPENCODE_PORT = 4096;
   const OPENCODE_DIR = `${SERVERS}/opencode`;

   // Your OpenCode configuration, without apiKey values.
   const OPENCODE_CONFIG = {};

   const OPENCODE = [
   	"opencode",
   	"serve",
   	"--port",
   	String(OPENCODE_PORT),
   	"--hostname",
   	"0.0.0.0",
   ];
   ```

   *src/index.ts (1.0)ts*

   

   ```ts
   export class MySandbox extends DurableObject<Env> {
   	// ...

   	private opencodeReady = false;

   	private async openCode(): Promise<OpencodeClient> {
   		await this.ensureRunning();

   		if (!this.opencodeReady) {
   			await startServer(this.container, OPENCODE_DIR, OPENCODE, {
   				cwd: "/workspace",
   				env: {
   					...ENV,
   					OPENCODE_CONFIG_CONTENT:
   						JSON.stringify(OPENCODE_CONFIG),
   					ANTHROPIC_API_KEY: this.env.ANTHROPIC_API_KEY,
   				},
   			});
   			await waitForServer(
   				this.container,
   				OPENCODE_DIR,
   				OPENCODE_PORT,
   				30_000,
   			);
   			this.opencodeReady = true;
   		}

   		const port = this.container.getTcpPort(OPENCODE_PORT);
   		return createOpencodeClient({
   			baseUrl: "http://opencode",
   			fetch: (request) => port.fetch(request),
   		});
   	}

   	async createSession(title: string): Promise<string> {
   		const client = await this.openCode();
   		const session = await client.session.create({ title });

   		if (!session.data) {
   			throw new Error("OpenCode did not create the session");
   		}

   		return session.data.id;
   	}
   }
   ```

   Remove `apiKey` from your OpenCode configuration, and store each key as a secret. Like 0.12, the method passes the configuration as `OPENCODE_CONFIG_CONTENT` and the key in a provider variable such as `ANTHROPIC_API_KEY`. The container can read the key. To keep model credentials in your Worker, refer to [Run OpenCode in a sandbox](https://developers.cloudflare.com/sandbox/coding-agents/opencode/).

   Set `this.opencodeReady = false` in `startContainer()`, inside `if (newContainer)`, because a new container has no server. If your Durable Object restarts while the container runs, `startServer()` finds the server that already runs. Use the client in methods of your class, such as `createSession()`.
4. Serve the OpenCode web UI from the `fetch()` handler of your Durable Object:

   *src/index.tsts*

   

   ```ts
   export class MySandbox extends DurableObject<Env> {
   	// ...

   	async fetch(request: Request): Promise<Response> {
   		const url = new URL(request.url);
   		const accept = request.headers.get("Accept") ?? "";
   		const page =
   			accept.includes("text/html") || url.pathname === "/";

   		// The UI calls the server at the origin in ?url=.
   		if (
   			request.method === "GET" &&
   			page &&
   			!url.searchParams.has("url")
   		) {
   			url.searchParams.set("url", url.origin);
   			return Response.redirect(url.toString(), 302);
   		}

   		await this.openCode();
   		// The container port accepts only http: URLs.
   		url.protocol = "http:";
   		return this.container
   			.getTcpPort(OPENCODE_PORT)
   			.fetch(new Request(url, request));
   	}
   }
   ```

   This replaces `proxyToOpencode()`, which made the same redirect. The UI loads its files from `/`, so serve it at the root of a hostname and forward every path to your Durable Object, for example with `env.Sandbox.getByName("my-agent").fetch(request)`. The UI can run commands in the sandbox, so authenticate these requests in your Worker.
5. Call `createSession("Fix tests")` from your Worker. It returns the new session ID, such as `ses_f1822cedcffe1CpcMlwM9eQSGZ`. Open your Worker URL in a browser. It redirects to `/?url=` and loads OpenCode.

## Give OpenAI agents a shell and an editor

In 0.12, `Shell` and `Editor` from `@cloudflare/sandbox/openai` ran the commands and file edits of an OpenAI agent in a sandbox, while the agent ran in your Worker. In 1.0, you write both classes over `container.exec()` and `Files`, and run the agent in your Durable Object, where the container is.

1. Add a `Shell` that runs each command with `bash` in `/workspace`:

   *src/index.tsts*

   

   ```ts
   import { Files } from "@cloudflare/sandbox";
   import {
   	Agent,
   	applyDiff,
   	applyPatchTool,
   	run,
   	shellTool,
   	type ApplyPatchOperation,
   	type ApplyPatchResult,
   	type Editor,
   	type Shell,
   	type ShellAction,
   	type ShellResult,
   } from "@openai/agents";

   class SandboxShell implements Shell {
   	constructor(private readonly container: Container) {}

   	async run(action: ShellAction): Promise<ShellResult> {
   		const timeoutMs = action.timeoutMs ?? 60_000;
   		const seconds = String(Math.ceil(timeoutMs / 1000));
   		const limit = ["timeout", "--kill-after=5", seconds];
   		const output: ShellResult["output"] = [];
   		const decoder = new TextDecoder();

   		for (const command of action.commands) {
   			const process = await this.container.exec(
   				[...limit, "bash", "-c", command],
   				{ cwd: "/workspace", env: ENV },
   			);
   			const result = await process.output();
   			const timedOut = result.exitCode === 124;

   			output.push({
   				stdout: decoder.decode(result.stdout),
   				stderr: decoder.decode(result.stderr),
   				outcome: timedOut
   					? { type: "timeout" }
   					: { type: "exit", exitCode: result.exitCode },
   			});

   			// 0.12 also skipped the rest after a timeout.
   			if (timedOut) {
   				break;
   			}
   		}

   		return {
   			output,
   			providerData: { working_directory: "/workspace" },
   		};
   	}
   }
   ```

   `timeout` [stops the command and every process it started](https://developers.cloudflare.com/containers/guides/execute-commands/#stop-the-processes-a-command-starts), and the command exits with code `124`. 0.12 set no time limit when the action had no `timeoutMs`, and this class sets 60 seconds.
2. Add an `Editor` that applies the patches from the agent with `Files`:

   *src/index.tsts*

   

   ```ts
   type Operation<T> = Extract<ApplyPatchOperation, { type: T }>;

   class SandboxEditor implements Editor {
   	constructor(private readonly files: Files) {}

   	// Reads each path as relative to /workspace, as 0.12 did, and throws
   	// when `..` leaves /workspace.
   	private path(path: string): string {
   		const root = "/workspace";
   		const inRoot = path === root || path.startsWith(`${root}/`);
   		const relative = inRoot ? path.slice(root.length) : path;
   		const segments: string[] = [];

   		for (const segment of relative.split("/")) {
   			if (segment === "..") {
   				if (segments.pop() === undefined) {
   					throw new Error(`Operation outside workspace: ${path}`);
   				}
   			} else if (segment !== "" && segment !== ".") {
   				segments.push(segment);
   			}
   		}

   		return [root, ...segments].join("/");
   	}

   	async createFile(
   		operation: Operation<"create_file">,
   	): Promise<ApplyPatchResult> {
   		const path = this.path(operation.path);
   		const parent = path.slice(0, path.lastIndexOf("/"));
   		await this.files.mkdir(parent, { recursive: true });
   		const content = applyDiff("", operation.diff, "create");
   		await this.files.writeFile(path, content);
   		return {
   			status: "completed",
   			output: `Created ${operation.path}`,
   		};
   	}

   	async updateFile(
   		operation: Operation<"update_file">,
   	): Promise<ApplyPatchResult> {
   		const path = this.path(operation.path);
   		const file = await this.files.readFile(path);
   		const current = await file.text();
   		const content = applyDiff(current, operation.diff);
   		await this.files.writeFile(path, content);
   		return {
   			status: "completed",
   			output: `Updated ${operation.path}`,
   		};
   	}

   	async deleteFile(
   		operation: Operation<"delete_file">,
   	): Promise<ApplyPatchResult> {
   		await this.files.remove(this.path(operation.path));
   		return {
   			status: "completed",
   			output: `Deleted ${operation.path}`,
   		};
   	}
   }
   ```

   `path()` reads `/etc/passwd` as `/workspace/etc/passwd`, and throws for `../etc/passwd`, as 0.12 did. It checks the path only. A symbolic link in `/workspace` can still point outside it. For more information, refer to [Accept paths from callers](https://developers.cloudflare.com/sandbox/files/manage-files/#accept-paths-from-callers).

   A failed `Files` call throws `SandboxFileError`. Both 0.12 classes kept a `results` list, and the 0.12 `Editor` added a `failed` result to it before it threw the error again. If your code read the list, record results in each method.
3. Run the agent in a method of your class:

   *src/index.ts (0.12)ts*

   

   ```ts
   const sandbox = getSandbox(env.Sandbox, `session-${sessionId}`);
   const agent = new Agent({
   	name: "Sandbox agent",
   	instructions: INSTRUCTIONS,
   	tools: [
   		shellTool({ shell: new Shell(sandbox) }),
   		applyPatchTool({
   			editor: new Editor(sandbox, "/workspace"),
   		}),
   	],
   });
   const result = await run(agent, input);
   ```

   *src/index.ts (1.0)ts*

   

   ```ts
   export class MySandbox extends DurableObject<Env> {
   	// ...

   	private readonly files = new Files(this.container);

   	async runAgent(input: string): Promise<string | undefined> {
   		await this.ensureRunning();

   		const shell = new SandboxShell(this.container);
   		const editor = new SandboxEditor(this.files);
   		const agent = new Agent({
   			name: "Sandbox agent",
   			instructions: INSTRUCTIONS,
   			tools: [shellTool({ shell }), applyPatchTool({ editor })],
   		});
   		const result = await run(agent, input);
   		return result.finalOutput;
   	}
   }
   ```

   Your Worker calls `runAgent()` on the stub that `getByName()` returns. The Agents SDK reads `OPENAI_API_KEY` from the environment, as it did in your Worker.

   If your class already has the `files` field from [Change file calls](https://developers.cloudflare.com/sandbox/sdk/migrate/files/), keep one of the two.
4. Check both classes without a model by calling them directly. `shell.run({ commands: ["pwd", "sleep 10"], timeoutMs: 2000 })` returns the working directory, then a timeout:

   ```json
   {
   	"output": [
   		{
   			"stdout": "/workspace\n",
   			"stderr": "",
   			"outcome": { "type": "exit", "exitCode": 0 }
   		},
   		{
   			"stdout": "",
   			"stderr": "",
   			"outcome": { "type": "timeout" }
   		}
   	],
   	"providerData": { "working_directory": "/workspace" }
   }
   ```

   `editor.createFile({ type: "create_file", path: "notes/todo.md", diff: "+first\n+second\n" })` returns `{ "status": "completed", "output": "Created notes/todo.md" }`. `/workspace/notes/todo.md` then contains the lines `first` and `second`.

## Replace the bridge

The 0.12 bridge, `bridge()` from `@cloudflare/sandbox/bridge`, served an HTTP API over `Sandbox` calls for clients outside Workers, and checked a `SANDBOX_API_KEY` bearer token. 1.0 has no bridge. Add a Worker route for each call that your client makes, and have the route call a method of your Durable Object. Check the token in your Worker, as the bridge did.

Clients written for the bridge API, such as `CloudflareSandboxClient` in the OpenAI Agents SDK for Python, work only with a 0.x bridge Worker. Keep that Worker on 0.x until your client calls your own routes.

## Remove WarmPool

Start each sandbox when a request needs it, and remove `WarmPool`. The pool kept 0.x sandboxes started ahead of time, because a 0.x start took seconds. On 1.0, a sandbox on a prepared image runs its first command in under 600 ms at the median.

1. Remove the `WarmPool` export from the main module of your Worker, and its binding from `durable_objects` in the Wrangler configuration.
2. Delete the class in the same way your Worker added it. If your Worker uses `migrations`, add a migration:

   ```jsonc
   {
   	"migrations": [
   		{ "new_sqlite_classes": ["Sandbox"], "tag": "v1" },
   		{ "new_sqlite_classes": ["WarmPool"], "tag": "v2" },
   		{ "deleted_classes": ["WarmPool"], "tag": "v3" },
   	],
   }
   ```

   ```toml
   [[migrations]]
   new_sqlite_classes = [ "Sandbox" ]
   tag = "v1"

   [[migrations]]
   new_sqlite_classes = [ "WarmPool" ]
   tag = "v2"

   [[migrations]]
   deleted_classes = [ "WarmPool" ]
   tag = "v3"
   ```

   If your Worker uses `exports`, mark the class as deleted instead:

   ```jsonc
   {
   	"exports": {
   		"WarmPool": {
   			"type": "durable-object",
   			"state": "deleted",
   		},
   	},
   }
   ```

   ```toml
   [exports.WarmPool]
   type = "durable-object"
   state = "deleted"
   ```


3. Remove the `WARM_POOL_TARGET`, `WARM_POOL_REFRESH_INTERVAL`, `WARM_POOL_MAX_INSTANCES`, and `WARM_POOL_SCALE_BATCH_SIZE` variables. `bridge()` filled the pool from its `scheduled()` handler, so remove the cron trigger too if nothing else uses it.

The sandboxes that the pool started are 0.12 sandboxes, so [Plan the move](https://developers.cloudflare.com/sandbox/sdk/migrate/plan-the-move/) covers them like any other.

If your application still needs those last milliseconds, call `start()` for the sandbox that a user is about to use, for example when they open a session. Do not keep a pool of started sandboxes. Each one is billed while it waits, and your code must assign it to a session.

## Related resources

- [Docker-in-Docker in the Containers FAQ](https://developers.cloudflare.com/containers/faq/#can-i-run-docker-inside-a-container-docker-in-docker)
- [Durable Object Container API](https://developers.cloudflare.com/containers/api/durable-object-container/)
- [Move outbound rules](https://developers.cloudflare.com/sandbox/sdk/migrate/outbound-traffic/)
- [Run OpenCode in a sandbox](https://developers.cloudflare.com/sandbox/coding-agents/opencode/)
- [`Files` API](https://developers.cloudflare.com/sandbox/reference/files/)

Was this helpful?

YesNo

## On this page

[![](https://developers.cloudflare.com/_astro/logo.te5VL_aD.svg)Docs](https://developers.cloudflare.com/)

```json
{"@context":"https://schema.org","@type":"TechArticle","@id":"https://developers.cloudflare.com/sandbox/sdk/migrate/other-features/#page","headline":"Move other 0.x features","description":"Move @cloudflare/sandbox 0.12 Docker-in-Docker images, binding handlers, and the opencode, openai, and bridge subpaths to 1.0, and remove WarmPool.","url":"https://developers.cloudflare.com/sandbox/sdk/migrate/other-features/","inLanguage":"en","image":"https://developers.cloudflare.com/sandbox/sdk/migrate/other-features/og.png?v=f9210298c4783c03","dateModified":"2026-09-30","publisher":{"@type":"Organization","name":"Cloudflare","description":"One platform for your apps, agents, and workforce. Build, secure, and scale without managing infrastructure","url":"https://www.cloudflare.com/","sameAs":["https://github.com/cloudflare","https://www.linkedin.com/company/cloudflare","https://x.com/cloudflare"],"logo":{"@type":"ImageObject","url":"https://developers.cloudflare.com/logo.svg"},"address":{"@type":"PostalAddress","streetAddress":"101 Townsend St","addressLocality":"San Francisco","addressRegion":"CA","postalCode":"94107","addressCountry":"US"},"contactPoint":[{"@type":"ContactPoint","contactType":"Customer Support","url":"https://support.cloudflare.com/","availableLanguage":["English"]},{"@type":"ContactPoint","contactType":"Sales","url":"https://www.cloudflare.com/contact/","availableLanguage":["English"]}]},"isPartOf":{"@type":"WebSite","@id":"https://developers.cloudflare.com/#website","name":"Cloudflare Docs","url":"https://developers.cloudflare.com/"}}
```
