Install any skill in seconds. Free to start, no credit card required.
Get Started Free →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.
.claude/skills/kunanonj-cursor-plugin-cf-sandbox-sdk/SKILL.md| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-01 | ✗→✓ | ▲ Improved | 42% | 0% |
| case-02 | ✗→✓ | ▲ Improved | 70% | 0% |
| case-03 | ✗→✓ | ▲ Improved | 2% | 0% |
| case-04 | ✗→✓ | ▲ Improved | -14% | 0% |
| case-05 | ✗→✓ | ▲ Improved | -14% | 0% |
Build secure, isolated code execution environments on Cloudflare Workers.
bashnpm install @cloudflare/sandbox docker info # Must succeed - Docker required for local dev
Your knowledge of the Sandbox SDK may be outdated. Prefer retrieval over pre-training for any Sandbox SDK task.
| 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/ |
When implementing features, fetch the relevant doc page or example first.
wrangler.jsonc (exact - do not modify structure):
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" }] }
Worker entry - must re-export Sandbox class:
typescriptimport { getSandbox } from '@cloudflare/sandbox'; export { Sandbox } from '@cloudflare/sandbox'; // Required export
| 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() |
typescriptconst sandbox = getSandbox(env.Sandbox, 'user-123'); const result = await sandbox.exec('python --version'); // result: { stdout, stderr, exitCode, success }
Use runCode() for executing LLM-generated code with rich outputs:
typescriptconst ctx = await sandbox.createCodeContext({ language: 'python' }); 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"
Languages: python, javascript, typescript
State persists within context. Create explicit contexts for production.
typescriptawait 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');
| 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 |
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:
dockerfileFROM docker.io/cloudflare/sandbox:0.7.0 # Python packages RUN pip install requests beautifulsoup4 # Node packages (global) RUN npm install -g typescript # System packages RUN apt-get update && apt-get install -y ffmpeg && rm -rf /var/lib/apt/lists/* EXPOSE 8080 # Required for local dev port exposure
Keep images lean - affects cold start time.
Expose HTTP services running in sandboxes:
typescriptconst { 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.
See: https://developers.cloudflare.com/sandbox/guides/expose-services/
The SDK provides helpers for OpenAI Agents at @cloudflare/sandbox/openai:
typescriptimport { Shell, Editor } from '@cloudflare/sandbox/openai';
See examples/openai-agents for complete integration pattern.
getSandbox() returns immediately - container starts lazily on first operationsleepAfter)destroy() to immediately free resourcessandboxId always returns same sandbox instanceCommandClient, FileClient) - use sandbox.* methodsexport { Sandbox }destroy() for temporary sandboxes| Case | Status | Duration (ms) | Turns | Tokens | Tool calls | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Without | With | Δ | Without | With | Δ | Without | With | Δ | Without | With | Δ | ||
case-01 | fail→pass | 10,067 | 7,021 | -30% | 1 | 1 | 0% | 2,365 | 3,356 | +42% | 0 | 0 | — |
case-02 | fail→pass | 29,501 | 7,639 | -74% | 1 | 1 | 0% | 2,014 | 3,428 | +70% | 0 | 0 | — |
case-03 | fail→pass | 12,461 | 6,021 | -52% | 1 | 1 | 0% | 2,855 | 2,925 | +2% | 0 | 0 | — |
case-04 | fail→pass | 10,261 | 2,454 | -76% | 1 | 1 | 0% | 2,352 | 2,029 | -14% | 0 | 0 | — |
case-05 | fail→pass | 15,811 | 5,520 | -65% | 1 | 1 | 0% | 3,074 | 2,641 | -14% | 0 | 0 | — |
case-19 | pass→pass | 10,905 | 5,858 | -46% | 1 | 1 | 0% | 2,084 | 2,665 | +28% | 0 | 0 | — |
case-06 | fail→pass | 7,215 | 3,964 | -45% | 1 | 1 | 0% | 1,454 | 2,361 | +62% | 0 | 0 | — |
case-07 | fail→pass | 11,461 | 5,597 | -51% | 1 | 1 | 0% | 2,584 | 2,743 | +6% | 0 | 0 | — |
case-08 | pass→pass | 8,907 | 3,664 | -59% | 1 | 1 | 0% | 1,776 | 1,709 | -4% | 0 | 0 | — |
case-09 | fail→pass | 5,778 | 2,340 | -60% | 1 | 1 | 0% | 1,229 | 1,940 | +58% | 0 | 0 | — |
case-10 | fail→pass | 5,805 | 2,067 | -64% | 1 | 1 | 0% | 1,299 | 1,824 | +40% | 0 | 0 | — |
case-11 | fail→pass | 9,475 | 2,330 | -75% | 1 | 1 | 0% | 2,183 | 1,925 | -12% | 0 | 0 | — |
case-12 | pass→pass | 9,560 | 1,426 | -85% | 1 | 1 | 0% | 1,626 | 1,696 | +4% | 0 | 0 | — |
case-13 | fail→pass | 7,463 | 1,853 | -75% | 1 | 1 | 0% | 1,432 | 1,752 | +22% | 0 | 0 | — |
case-14 | fail→pass | 12,267 | 2,536 | -79% | 1 | 1 | 0% | 1,072 | 1,905 | +78% | 0 | 0 | — |
case-15 | fail→pass | 8,390 | 1,849 | -78% | 1 | 1 | 0% | 1,693 | 1,775 | +5% | 0 | 0 | — |
case-16 | pass→pass | 9,914 | 5,555 | -44% | 1 | 1 | 0% | 1,903 | 2,514 | +32% | 0 | 0 | — |
case-17 | fail→pass | 14,254 | 5,938 | -58% | 1 | 1 | 0% | 2,945 | 2,769 | -6% | 0 | 0 | — |
case-18 | fail→pass | 3,597 | 1,156 | -68% | 1 | 1 | 0% | 757 | 1,586 | +110% | 0 | 0 | — |
case-20 | pass→pass | 6,488 | 5,357 | -17% | 1 | 1 | 0% | 1,471 | 2,605 | +77% | 0 | 0 | — |
case-21 | pass→pass | 5,921 | 3,275 | -45% | 1 | 1 | 0% | 1,234 | 2,203 | +79% | 0 | 0 | — |
case-22 | pass→pass | 10,060 | 6,282 | -38% | 1 | 1 | 0% | 2,035 | 2,804 | +38% | 0 | 0 | — |
DecimalAI ran this skill against gemini-3.6-flash twice over the same eval suite — once with the skill loaded and once without — and compared the two runs case by case. 22 cases were attempted, and 20 counted toward the lift figure. The other 2 produced results that are not comparable between the two arms, so they are excluded from the headline rather than averaged into it. The headline lift of +68 percentage points is the difference between those two pass rates over the 20 comparable cases.
Without the skill loaded, the model failed this case. With it loaded, the same prompt on the same model passed. This is one improved case from the latest verified run; every case, including any that regressed, is in the table above.
Other measured skills in the registry, with their headline benchmark lift.