Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 5 additions & 3 deletions src/content/docs/sandbox/coding-agents/claude-code.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ Run [Claude Code](https://code.claude.com/docs/en/overview) in a Linux sandbox t

</WranglerConfig>

3. In `src/outbound.ts`, make sure the `Outbound` entrypoint removes the `x-api-key` header before it adds the gateway token:
3. In `src/outbound.ts`, make sure that the `Outbound` entrypoint, which receives each HTTP and HTTPS request from the sandbox, removes the `x-api-key` header before it adds the gateway token:

```ts title="src/outbound.ts"
const headers = new Headers(request.headers);
Expand All @@ -72,7 +72,7 @@ Run [Claude Code](https://code.claude.com/docs/en/overview) in a Linux sandbox t

Claude Code sends a placeholder API key. If the `x-api-key` header stays, AI Gateway forwards it to Anthropic, and the model request fails with `Invalid API key`.

4. In `src/sandbox.ts`, replace the `ResultEvent` constant with a schema for the final event from Claude Code:
4. In `src/sandbox.ts`, replace the event schema for the previous agent with this `ResultEvent` schema for the final event from Claude Code:

```ts title="src/sandbox.ts"
const ResultEvent = z.object({
Expand Down Expand Up @@ -184,12 +184,14 @@ Run [Claude Code](https://code.claude.com/docs/en/overview) in a Linux sandbox t
--data "Add a file NOTES.md with a one-sentence summary of this repository. Do not commit."
```

3. Check the task until its state is `succeeded` or `failed`:
3. Check the task until its state is no longer `running`:

```sh
curl "$WORKER_URL/sandboxes/claude-1/task"
```

For what `succeeded`, `failed`, `lost`, and `none` mean, refer to [Read the outcome](/sandbox/get-started/build-a-coding-agent-runner/#read-the-outcome).

A `succeeded` task includes the final reply from Claude Code.

4. Read the changes:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,12 +28,12 @@ The template is alpha software. It is not yet stable and may contain bugs.

## How it works

When an agent session starts or ends, Anthropic sends a webhook to a Worker that the template deploys in your account. The Worker gives each session its own sandbox, applies an egress policy to its outbound traffic, saves the sandbox state while the session sleeps, and shuts the sandbox down when the session ends.
When an agent session starts or ends, Anthropic sends a webhook to a Worker that the template deploys in your account. The Worker gives each session its own sandbox, applies an egress policy (a set of rules for outbound requests) to its outbound traffic, saves the sandbox state while the session sleeps, and shuts the sandbox down when the session ends.

Each agent runs in one of two sandbox types:

- A Linux sandbox on [Containers](/containers/) gives the agent a shell and any process it needs to run. The template builds these sandboxes with [Sandbox SDK 0.x](/sandbox/sdk/).
- A [Dynamic Worker](/dynamic-workers/) starts in milliseconds and costs less than a container session, but runs code in the Workers runtime without a Linux shell or processes.
- A [Dynamic Worker](/dynamic-workers/) runs code in the Workers runtime without a Linux shell or processes.

For more information about the trade-offs, refer to [Choose a sandbox environment](/sandbox/concepts/).

Expand All @@ -42,11 +42,11 @@ For more information about the trade-offs, refer to [Choose a sandbox environmen
The template also gives agents access to other Cloudflare products:

- Agents reach private services over [Workers VPC](/workers-vpc/) and [Cloudflare Mesh](/mesh/) without exposing those services to the Internet.
- Outbound traffic passes through proxies that you configure. A proxy can add credentials to requests without the agent seeing them, restrict the domains an agent can reach, or run your own code on each request.
- Outbound traffic passes through proxies that you configure. A proxy is the handler that applies the egress policy to each request. It can add credentials to requests without the agent seeing them, restrict the domains an agent can reach, or run your own code on each request.
- Each session can have its own email address for sending and receiving messages with [Email Service](/email-service/).
- Agents can use headless browsers from [Browser Run](/browser-run/) to fetch pages, take screenshots, and control a browser over the Chrome DevTools Protocol.
- Agents can generate images with [Workers AI](/workers-ai/).
- You add a tool by adding a function to one file. Tools run in the Worker with access to all of its bindings.
- You add a tool by adding a function to one file. Tools run in the Worker with access to all of its [bindings](/workers/runtime-apis/bindings/), the APIs that connect the Worker to other Cloudflare resources.
- A dashboard lists agents and sessions, shows logs, and opens a shell in a running Linux sandbox.

## When to use it
Expand All @@ -63,10 +63,20 @@ Use a self-managed Cloudflare environment when you need:

Follow the [onboarding guide](https://github.com/cloudflare/claude-managed-agents#onboarding-guide) in the repository. It covers the Anthropic environment and webhook, secrets, D1 migrations, R2 credentials for snapshots, and dashboard security. Deploy with the **Deploy to Cloudflare** button, which builds the template in Workers Builds, or run `npm run deploy` from your terminal.

To check the deployment, open the URL of the Worker, create an agent, and start a session. The dashboard shows the logs of the session.

:::note
You need a Workers Paid plan or an Enterprise account. The template runs Linux sandboxes on [Containers](/containers/), and runs Dynamic Workers and egress proxies through Worker Loader bindings.
:::

## Security

Each session runs in its own sandbox. A Linux sandbox receives the Anthropic environment key as the `ANTHROPIC_ENVIRONMENT_KEY` environment variable, so code that runs in the session can read it. The Worker keeps `ANTHROPIC_API_KEY` and does not pass it to the sandbox. Code in a Dynamic Worker sandbox receives neither key.

The template serves the dashboard at `/`, its API at `/api/*`, and terminal connections at `/ws/terminal` without authentication. Anyone who reaches these routes can start sessions, change secrets and egress policies, and open a shell in a running Linux sandbox. Protect them with [Cloudflare Access](/cloudflare-one/access-controls/applications/http-apps/self-hosted-public-app/) before you expose the deployment. Anthropic calls `/webhooks` without an Access login, so use a [path-specific policy](/cloudflare-one/access-controls/policies/app-paths/) that leaves `/webhooks` reachable. The Worker checks the signature of each webhook with `WEBHOOK_SECRET`.

For setup steps, refer to [Securing access](https://github.com/cloudflare/claude-managed-agents/blob/main/docs/securing-access.md) in the template. For more information about what a sandbox exposes to the code inside it, refer to [Sandbox security](/sandbox/concepts/security/).

## Template documentation

The repository documents each capability:
Expand Down
8 changes: 5 additions & 3 deletions src/content/docs/sandbox/coding-agents/codex.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -128,9 +128,9 @@ Run the [Codex CLI](https://developers.openai.com/codex/cli) in a Linux sandbox

`--dangerously-bypass-approvals-and-sandbox` turns off the approval prompts and the built-in command sandbox of Codex. The container limits what commands from Codex can reach instead.

A custom provider sends no API key, and the `Outbound` entrypoint adds the gateway token.
A custom provider sends no API key, and the `Outbound` entrypoint, which receives each HTTP and HTTPS request from the sandbox, adds the gateway token.

Codex reads the certificate for intercepted HTTPS from `SSL_CERT_FILE`, which `trustEnv` in the runner sets.
Codex reads the certificate for intercepted HTTPS from `SSL_CERT_FILE`. The runner sets it in `trustEnv`, the environment variables that tell tools in the container which certificate to trust. For more information, refer to [Start the sandbox](/sandbox/get-started/build-a-coding-agent-runner/#start-the-sandbox).

5. Replace the `outcome()` method:

Expand Down Expand Up @@ -201,12 +201,14 @@ Run the [Codex CLI](https://developers.openai.com/codex/cli) in a Linux sandbox
--data "Add a file NOTES.md with a one-sentence summary of this repository. Do not commit."
```

3. Check the task until its state is `succeeded` or `failed`:
3. Check the task until its state is no longer `running`:

```sh
curl "$WORKER_URL/sandboxes/codex-1/task"
```

For what `succeeded`, `failed`, `lost`, and `none` mean, refer to [Read the outcome](/sandbox/get-started/build-a-coding-agent-runner/#read-the-outcome).

A `succeeded` task includes the final message that Codex wrote.

4. Read the changes:
Expand Down
16 changes: 12 additions & 4 deletions src/content/docs/sandbox/coding-agents/cursor.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,10 @@ products:
reviewed: 2026-09-24
---

import { Steps } from "~/components";
import { Steps, WranglerConfig } from "~/components";
import { VendorAgentConnections } from "~/components/react/sandbox/VendorAgentConnections";

Run Cursor Cloud Agents on Cloudflare through [self-hosted machines](https://cursor.com/docs/cloud-agent/self-hosted). Each Cursor session assigned to the deployment runs in its own Linux sandbox: a [Container](/containers/) that one Durable Object starts for that session.
Run Cursor Cloud Agents on Cloudflare through [self-hosted machines](https://cursor.com/docs/cloud-agent/self-hosted). Each Cursor session assigned to the deployment runs in its own Linux sandbox: a [Container](/containers/) that one [Durable Object](/durable-objects/) starts for that session.

Cursor hosts the agent loop, inference, and planning. Cloudflare runs commands, file edits, repository operations, and other tools inside infrastructure that you control.

Expand Down Expand Up @@ -44,7 +44,7 @@ For more information, refer to [Cursor team pools](https://cursor.com/docs/cloud

## Deploy the template

The template deploys a Worker, a Durable Object namespace, a container application, an R2 bucket binding, and a cron trigger.
The template deploys a Worker, a Durable Object that coordinates each session, a container, an R2 bucket binding that connects the Worker to its snapshot bucket, and a [cron trigger](/workers/configuration/cron-triggers/) that runs the Worker on a schedule. It uses the [`Container` class](/containers/api/container-class/) from `@cloudflare/containers` and the `default` [scheduling policy](/containers/configuration/scheduling-policy/#use-the-default-scheduling-policy), so `max_instances` and image [rollouts](/containers/configuration/rollouts/) apply to all of its containers.

<Steps>
1. Clone the template and install its dependencies:
Expand Down Expand Up @@ -88,6 +88,8 @@ The template deploys a Worker, a Durable Object namespace, a container applicati

6. In `wrangler.jsonc`, set `vars.CURSOR_POOL` to the Cursor team pool name:

<WranglerConfig>

```jsonc
{
"vars": {
Expand All @@ -96,6 +98,8 @@ The template deploys a Worker, a Durable Object namespace, a container applicati
}
```

</WranglerConfig>

7. Set `containers[].max_instances` to the maximum number of concurrent sessions that the deployment must support.

8. Deploy the Worker and container:
Expand Down Expand Up @@ -158,6 +162,8 @@ Repository snapshots are an optional cache for repository-bound agents. A snapsh

2. In `wrangler.jsonc`, set `vars.WORKER_PUBLIC_URL` to the deployed Worker URL:

<WranglerConfig>

```jsonc
{
"vars": {
Expand All @@ -167,6 +173,8 @@ Repository snapshots are an optional cache for repository-bound agents. A snapsh
}
```

</WranglerConfig>

3. Deploy the updated configuration:

```sh
Expand All @@ -190,7 +198,7 @@ A cron trigger runs the Worker every five minutes. Each run lists the sessions t

The Worker claims each session with a unique worker ID. Cursor then assigns the session only to that Worker. A Durable Object for the session starts one container with the session environment and repository information.

The container stops after five minutes without work, or after `WORKER_IDLE_RELEASE_TIMEOUT_SECONDS` if you set that variable. The Durable Object also stops the container after eight hours, or after `MAX_RUN_LIFETIME_SECONDS` if you set that variable.
`WORKER_IDLE_RELEASE_TIMEOUT_SECONDS` sets how long the container waits without work before it stops. `MAX_RUN_LIFETIME_SECONDS` sets the longest time that the Durable Object keeps the container running. For the default values, refer to [`src/config.ts`](https://github.com/anysphere/cloudflare-workers/blob/main/src/config.ts) in the template.

The container connects out to Cursor, so it needs no inbound port or public IP address. The Worker exposes only its health route and the optional snapshot routes.

Expand Down
12 changes: 7 additions & 5 deletions src/content/docs/sandbox/coding-agents/devin.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ reviewed: 2026-09-24
import { PackageManagers, Steps } from "~/components";
import { VendorAgentConnections } from "~/components/react/sandbox/VendorAgentConnections";

[Devin](https://docs.devin.ai/cloud/outposts/overview) runs its agent loop in its own service. Each session works on a machine where Devin runs commands, edits files, and opens a browser. A Devin Outpost moves that machine to infrastructure that you choose. The Devin Outpost template runs each session in its own Linux sandbox: a [Container](/containers/) that one Durable Object starts for that session.
[Devin](https://docs.devin.ai/cloud/outposts/overview) runs its agent loop in its own service. Each session works on a machine where Devin runs commands, edits files, and opens a browser. A Devin Outpost moves that machine to infrastructure that you choose. The Devin Outpost template runs each session in its own Linux sandbox: a [Container](/containers/) that one [Durable Object](/durable-objects/) starts and stops for that session.

## Prerequisites

Expand Down Expand Up @@ -43,7 +43,7 @@ For more information about outposts, refer to the [Devin Outposts overview](http

## Deploy with one click

The **Deploy to Cloudflare** button creates the Worker, the cron trigger, the Durable Object namespace, and the container application.
The **Deploy to Cloudflare** button deploys the Worker with its Durable Object, its container, and a [cron trigger](/workers/configuration/cron-triggers/) that runs the Worker on a schedule.

[![Deploy to Cloudflare](https://deploy.workers.cloudflare.com/button)](https://deploy.workers.cloudflare.com/?url=https://github.com/cloudflare/sandbox-sdk/tree/main/templates/devin)

Expand Down Expand Up @@ -116,10 +116,12 @@ Deploy manually when you need to add dependencies, tools, or environment variabl

## Run a Devin session

In Devin, create a session and select your outpost from the **Virtual environment** menu. The Worker checks for new sessions every 10 seconds by default, so the sandbox for the session starts shortly after you create it.
In Devin, create a session and select your outpost from the **Virtual environment** menu. The Worker checks Devin for new sessions on a short interval, so the sandbox for the session starts shortly after you create it.

## How the template runs sessions

The template saves each session in a snapshot: a saved copy of the disk of a sandbox, so a later sandbox can start with the same files.

A cron trigger runs the Worker once a minute. During each run, the Worker asks Devin for the sessions of your outpost every 10 seconds, or every `DEVIN_RECONCILE_INTERVAL_MS` milliseconds if you set that variable. The Worker sends the status of each session to the Durable Object for that session:

| Devin status | What the template does |
Expand All @@ -136,12 +138,12 @@ Your Worker connects to Devin on a cron trigger and lists sessions. It sends eac

</VendorAgentConnections>

When Devin suspends a session, the Devin CLI exits. The sandbox keeps running until the Durable Object saves a snapshot of its disk. When the session continues, the sandbox starts from that snapshot and the Devin CLI claims the session again. The snapshot keeps the files and installed packages of the session. It does not keep running processes. If the Devin CLI exits while the session is still running, the template saves a snapshot and starts a new sandbox from it.
When Devin suspends a session, the Devin CLI exits. The template saves a snapshot only after the Devin CLI exits, and the sandbox keeps running until the template saves it. If a sandbox stops before then, the session continues from its previous snapshot, or from the image if it has none. When the session continues, the sandbox starts from the snapshot and the Devin CLI claims the session again. The snapshot keeps the files and installed packages of the session. It does not keep running processes. If the Devin CLI exits while the session is still running, the template saves a snapshot and starts a new sandbox from it.

For more information, refer to [Save and restore a sandbox with snapshots](/sandbox/files/save-and-restore-a-workspace/).

:::note
The template saves a snapshot only after the Devin CLI exits. If a sandbox stops before then, the session continues from its previous snapshot, or from the image if it has none. The Worker API cannot delete snapshots, so the snapshot of a terminated session stays in your account.
Terminating a session removes the snapshot ID that the template stores. The snapshot stays in your account, because the Worker API cannot delete snapshots. For how long a snapshot lasts, refer to [Understand retention](/containers/guides/snapshots/#understand-retention).
:::

## Security
Expand Down
6 changes: 3 additions & 3 deletions src/content/docs/sandbox/coding-agents/index.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,9 @@ Coding agents such as Claude Code, Codex, and OpenCode can run a task on their o

## The agent runs in your sandbox

Your Worker starts the sandbox, holds the credentials, and decides which hostnames the sandbox can reach. The agent calls its model over HTTP, for example through [AI Gateway](/ai-gateway/). Your Worker adds the API token to each request, so the sandbox never receives it.
Your [Worker](/workers/), the application that receives your requests, starts the sandbox, holds the credentials, and decides which hostnames the sandbox can reach. The agent calls its model over HTTP, for example through [AI Gateway](/ai-gateway/). Your Worker adds the API token to each request, so the sandbox never receives it.

Each guide in this section changes only the agent-specific parts of one runner. Build the runner first:
The guides for command-line agents change only the agent-specific parts of one runner. Build the runner first:

<LinkTitleCard
title="Build a coding agent runner"
Expand Down Expand Up @@ -62,7 +62,7 @@ Then switch the runner to another agent:

## The vendor runs the agent loop

Devin, Cursor, Claude Managed Agents, and the OpenAI Agents API run their agent loop in their own service. The loop sends commands and file edits to sandboxes in your Cloudflare account. Each vendor template gives every session its own sandbox. In the Devin, Cursor, and OpenAI Agents API templates, the vendor worker process runs inside the sandbox, so the sandbox also holds a vendor credential.
Devin, Cursor, Claude Managed Agents, and the OpenAI Agents API run their agent loop, the repeated model calls and tool actions that carry out a task, in their own service. The loop sends commands and file edits to sandboxes in your Cloudflare account. Each vendor template gives every session its own sandbox. Each template also passes a vendor credential to its Linux sandboxes, where code that runs in a session can read it. The security section of each guide names that credential.

<CardGrid>
<LinkTitleCard
Expand Down
Loading
Loading