home / skills / digitalocean-labs / do-app-platform-skills / sandbox

sandbox skill

/skills/sandbox

This skill helps you create and manage isolated sandbox environments for safe AI agent code execution and iterative workflow testing.

npx playbooks add skill digitalocean-labs/do-app-platform-skills --skill sandbox

Review the files below or copy the command above to add this skill to your agents.

Files (7)
SKILL.md
9.2 KB
---
name: app-platform-sandbox
version: 1.0.0
min_doctl_version: "1.82.0"
description: Create and manage isolated container sandboxes for AI agent code execution. Use when you need ephemeral environments to run untrusted code, execute agent workflows, or test in isolation. NOT for debugging existing apps (use troubleshooting skill).
related_skills: [troubleshooting]
deprecated: false
---

# Sandbox Skill

Isolated execution environments for AI agents and testing workflows.

## Philosophy

```
Lambda/Functions: Fast cold start, 15-min limit, stateless, per-ms billing
App Platform Sandbox: 30s cold start (or instant with pool), unlimited duration, stateful, per-hour billing

Sweet spot: Long-running, stateful, iterative workflows where agents need to
install packages, run code, check results, modify, repeat.
```

## Quick Decision

```
┌─────────────────────────────────────────────────────────────┐
│         Need isolated execution environment?                 │
└─────────────────────────────────────────────────────────────┘
                            │
              Is this for debugging an EXISTING app?
                            │
            ┌───────────────┴───────────────┐
            │                               │
           YES                              NO
            │                               │
            ▼                               ▼
   ┌─────────────────┐           ┌─────────────────┐
   │ troubleshooting │           │ Need real-time  │
   │ skill           │           │ streaming or    │
   │                 │           │ port exposure?  │
   │ Sandbox.get_    │           │                 │
   │ from_id()       │           └────────┬────────┘
   └─────────────────┘                    │
                          ┌───────────────┴───────────────┐
                          │                               │
                         YES                              NO
                          │                               │
                          ▼                               ▼
                 ┌─────────────────┐           ┌─────────────────┐
                 │ SERVICE MODE    │           │ Is low latency  │
                 │ exec_stream()   │           │ critical?       │
                 │ expose_port()   │           │                 │
                 └─────────────────┘           └────────┬────────┘
                                                        │
                                        ┌───────────────┴───────────────┐
                                        │                               │
                                       YES                              NO
                                        │                               │
                                        ▼                               ▼
                               ┌─────────────────┐           ┌─────────────────┐
                               │ HOT POOL        │           │ COLD SANDBOX    │
                               │ SandboxManager  │           │ Sandbox.create()│
                               │ ~50ms acquire   │           │ ~30s startup    │
                               └─────────────────┘           └─────────────────┘
```

---

## Prerequisites

```bash
# Verify doctl is installed and authenticated
doctl auth whoami

# Install the SDK (choose one)
uv pip install do-app-sandbox
# OR
pip install do-app-sandbox

# For Spaces support (large file transfers)
pip install "do-app-sandbox[spaces]"
```

**Requirements:**
- Python 3.10.12+
- `doctl` CLI installed and authenticated
- DigitalOcean account with App Platform access

---

## Quick Start: Cold Sandbox

Single sandbox creation with ~30s startup time:

```python
from do_app_sandbox import Sandbox

# Create sandbox with Python image
sandbox = Sandbox.create(
    image="python",           # or "node"
    name="my-sandbox",
    region="nyc",
    instance_size="apps-s-1vcpu-1gb"
)

# Execute code
result = sandbox.exec("python3 -c 'import sys; print(sys.version)'")
print(result.stdout)

# File operations
sandbox.filesystem.write_file("/tmp/script.py", "print('hello')")
result = sandbox.exec("python3 /tmp/script.py")

# Clean up
sandbox.delete()
```

**Full guide**: See [cold-sandbox.md](reference/cold-sandbox.md)

---

## Quick Start: Hot Pool

Pre-warmed sandboxes for instant acquisition:

```python
import asyncio
from do_app_sandbox import SandboxManager, PoolConfig

async def main():
    # 1. Configure pool
    manager = SandboxManager(
        pools={"python": PoolConfig(target_ready=3)},
    )

    # 2. Start and warm up (blocks until pool is ready)
    await manager.start()
    await manager.warm_up(timeout=180)

    # 3. Acquire instantly (~500ms from pool vs 30s cold start)
    sandbox = await manager.acquire(image="python")
    result = sandbox.exec("python3 -c 'print(2+2)'")
    print(result.stdout)

    # 4. Delete when done - YOUR responsibility!
    sandbox.delete()

    # 5. Shutdown (cleans up pool, not acquired sandboxes)
    await manager.shutdown()

asyncio.run(main())
```

**Ownership model:** Once you `acquire()` a sandbox, you own it. Always call `sandbox.delete()` when done. The `shutdown()` only cleans up sandboxes still in the pool.

**Full guide**: See [hot-pool.md](reference/hot-pool.md)

---

## Quick Reference: When to Use Sandbox

| Scenario | Recommendation |
|----------|----------------|
| AI code interpreter | Hot Pool (instant response) |
| Multi-step agent workflow | Single sandbox (state persists within one sandbox) |
| One-off script test | Cold Sandbox (simple) |
| CI integration testing | Cold Sandbox (per-job) |
| Short tasks (< 30s) | Consider Lambda instead |
| High concurrency (1000+) | Consider Lambda instead |

---

## Quick Reference: Available Images

| Image | Registry | Use Case |
|-------|----------|----------|
| `python` | `ghcr.io/bikramkgupta/sandbox-python` | Python 3.13, uv, pip |
| `node` | `ghcr.io/bikramkgupta/sandbox-node` | Node.js 24, nvm |

Working directory: `/home/sandbox/app` (with `/app` symlink). Ports: 8080 (user apps), 9090 (health checks).

Custom images supported — any Docker image with HTTP server capability.

---

## Quick Reference: SDK Methods

| Method | Purpose |
|--------|---------|
| `Sandbox.create(image, mode=...)` | Create sandbox (WORKER or SERVICE mode) |
| `Sandbox.get_from_id()` | Connect to existing app |
| `sandbox.exec(cmd)` | Run shell command |
| `sandbox.exec_stream(cmd)` | Streaming output (SERVICE mode) |
| `sandbox.expose_port(port)` | Get public URL for port (SERVICE mode) |
| `sandbox.hibernate()` | Snapshot + delete for cost savings |
| `Sandbox.wake(hibernated)` | Restore hibernated sandbox |
| `sandbox.filesystem.read_file()` | Read file contents |
| `sandbox.filesystem.write_file()` | Write file |
| `sandbox.delete()` | Delete sandbox (always call when done) |
| `SandboxManager(pools={...})` | Configure hot pool |
| `manager.start()` | Start background pool management |
| `manager.warm_up(timeout)` | Block until pool reaches target (async) |
| `manager.acquire(image=...)` | Get sandbox from pool (async) |
| `manager.acquire_with_snapshot()` | Get sandbox with pre-configured state |
| `manager.shutdown()` | Tear down pool (cleans up pool only) |

---

## Reference Files

- **[cold-sandbox.md](reference/cold-sandbox.md)** — Single sandbox lifecycle, file ops, cleanup
- **[hot-pool.md](reference/hot-pool.md)** — Pool management, sizing, cost optimization
- **[service-mode.md](reference/service-mode.md)** — Streaming, port exposure, AI agent patterns
- **[use-cases.md](reference/use-cases.md)** — AI agent patterns, testing patterns
- **[positioning.md](reference/positioning.md)** — Lambda vs Sandbox decision guide

---

## Cost Considerations

```
Sandbox billing: ~$0.01-0.03/hour per container (apps-s-1vcpu-1gb)

Hot Pool trade-off:
- Pool of 5 sandboxes running 8 hours = ~$0.80-2.40/day
- Eliminates 30s cold start per request
- Worth it for interactive AI agents, not for batch jobs
```

---

## Integration with Other Skills

| Direction | Skill | When |
|-----------|-------|------|
| **→** | troubleshooting | Debug an existing sandbox (use `Sandbox.get_from_id()`) |
| **→** | designer | Include sandbox-compatible worker in app spec |
| **←** | deployment | Sandboxes are standalone, not part of main app deployment |

Overview

This skill creates and manages isolated container sandboxes for executing AI agent code and testing workflows. It supports both cold sandboxes for simple, ephemeral runs and pre-warmed hot pools for near-instant acquisition. Use it to run untrusted code, perform iterative stateful workflows, or expose services for agent testing in a controlled environment.

How this skill works

The SDK provisions containers on DigitalOcean App Platform using predefined images (python/node) or custom images. You can create single cold sandboxes (~30s startup) or run a SandboxManager to maintain a hot pool of pre-warmed sandboxes (~50–500ms acquire). It exposes APIs for executing commands, streaming output, managing files, exposing ports, snapshotting (hibernate), and lifecycle cleanup.

When to use it

  • Run untrusted or third-party agent code in isolation.
  • Execute multi-step, stateful agent workflows that need persistence across steps.
  • Interactive or iterative development where agents install packages and modify state.
  • Low-latency interactive agents—use a hot pool for instant responses.
  • One-off script tests and CI jobs where per-job isolation is needed.

Best practices

  • Always call sandbox.delete() when you finish to avoid billing surprises.
  • Use SandboxManager pools for interactive workloads to eliminate cold-start delay.
  • Prefer cold sandboxes for single-run CI or short-lived tasks to reduce overhead.
  • Use sandbox.hibernate() + Sandbox.wake() to persist expensive setup and lower runtime cost.
  • Expose ports and exec_stream() only for SERVICE mode sandboxes; use exec() for short commands.

Example use cases

  • Run a code-executing AI assistant that needs to install packages and iterate on output.
  • Test an agent workflow that launches a local HTTP server and needs a stable working directory.
  • Pre-warm a pool for a user-facing interpreter feature that requires sub-second responsiveness.
  • CI job that runs tests in a fresh environment using a cold sandbox per job.
  • Snapshot a configured environment, hibernate it, and wake it later to resume long-running experiments.

FAQ

What is the difference between cold sandbox and hot pool?

Cold sandboxes are created on demand (~30s startup) and suit one-off runs. Hot pools keep pre-warmed containers ready for near-instant acquisition but incur continuous cost while running.

How do I avoid leaking resources?

Treat acquired sandboxes as owned resources. Always call sandbox.delete() when done. shutdown() only cleans pool members, not sandboxes you acquired.