Skip to content
105 changes: 95 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,27 +9,87 @@ Universal library for AI code execution sandboxes.

`sandboxes` provides a unified interface for sandboxed code execution across multiple providers:

- **Current providers**: E2B, Modal, Daytona, Hopx
- **Current providers**: E2B, Modal, Daytona, Hopx, Sprites (Fly.io)
- **Experimental**: Cloudflare (requires self-hosted Worker deployment)

Write your code once and switch between providers with a single line change, or let the library automatically select a provider.
Includes a Python API plus full-featured CLI for use from any runtime.

## Installation

Add to your project:
```bash
uv pip install cased-sandboxes
```

Or add to your project:

```bash
uv add cased-sandboxes
```

or install with your preferred Python package manager and use the CLI
for any language, e.g.,:
## Claude Code Integration

Run [Claude Code](https://docs.anthropic.com/en/docs/claude-code) in a secure sandbox with one command:

```bash
uv pip install cased-sandboxes
sandboxes claude
```

That's it. You get an interactive Claude Code session in an isolated, cloud environment.

### Setup (Sprites - recommended)

```bash
# Install and login to Sprites
curl https://sprites.dev/install.sh | bash
sprite login

# Start Claude Code
sandboxes claude
```

### Setup (E2B - alternative)

```bash
# Install E2B SDK and CLI
uv pip install e2b
npm install -g @e2b/cli

# Set your API keys
export E2B_API_KEY=your_key
export ANTHROPIC_API_KEY=your_key

# Start Claude Code
sandboxes claude -p e2b
```

### Persistent Development Environment (Sprites only)

```bash
# Create a named sandbox (automatically kept)
sandboxes claude -n myproject

# Work on your project...
# Exit when done (/exit or Ctrl+C)

# Come back later - your files are still there
sandboxes claude -n myproject

# List your sandboxes
sandboxes claude --list

# Or just get a raw shell (no Claude Code)
sandboxes shell -n mydev --keep
```

### Why Sandboxes?

Claude Code can read, write, and execute code. Running it in a sandbox means:
- **Safe**: Can't touch your local files or system
- **Isolated**: Each project gets its own environment
- **Persistent**: Named sandboxes keep your files across sessions
- **Pre-configured**: Claude Code, Python, Node.js ready to go

## Quick Start

### One-line Execution + Auto-select Provider
Expand Down Expand Up @@ -352,6 +412,7 @@ export E2B_API_KEY="..."
export MODAL_TOKEN_ID="..." # Or use `modal token set`
export DAYTONA_API_KEY="..."
export HOPX_API_KEY="hopx_live_<keyId>.<secret>"
export SPRITES_TOKEN="..." # Or use `sprite login` for CLI mode
export CLOUDFLARE_SANDBOX_BASE_URL="https://your-worker.workers.dev"
export CLOUDFLARE_API_TOKEN="..."
```
Expand All @@ -373,9 +434,10 @@ When you call `Sandbox.create()` or `run()`, the library checks for providers in

1. **Daytona** - Looks for `DAYTONA_API_KEY`
2. **E2B** - Looks for `E2B_API_KEY`
3. **Hopx** - Looks for `HOPX_API_KEY`
4. **Modal** - Looks for `~/.modal.toml` or `MODAL_TOKEN_ID`
5. **Cloudflare** *(experimental)* - Looks for `CLOUDFLARE_SANDBOX_BASE_URL` + `CLOUDFLARE_API_TOKEN`
3. **Sprites** - Looks for `SPRITES_TOKEN` or `sprite` CLI login
4. **Hopx** - Looks for `HOPX_API_KEY`
5. **Modal** - Looks for `~/.modal.toml` or `MODAL_TOKEN_ID`
6. **Cloudflare** *(experimental)* - Looks for `CLOUDFLARE_SANDBOX_BASE_URL` + `CLOUDFLARE_API_TOKEN`

**The first provider with valid credentials becomes the default.** Cloudflare requires deploying your own Worker.

Expand Down Expand Up @@ -433,6 +495,7 @@ from sandboxes.providers import (
ModalProvider,
DaytonaProvider,
HopxProvider,
SpritesProvider,
CloudflareProvider,
)

Expand All @@ -448,6 +511,10 @@ provider = DaytonaProvider()
# Hopx - Uses HOPX_API_KEY env var
provider = HopxProvider()

# Sprites - Uses SPRITES_TOKEN or sprite CLI login
provider = SpritesProvider() # SDK mode with SPRITES_TOKEN
provider = SpritesProvider(use_cli=True) # CLI mode with sprite login

# Cloudflare - Requires base_url and token
provider = CloudflareProvider(
base_url="https://your-worker.workers.dev",
Expand All @@ -460,6 +527,7 @@ Each provider requires appropriate authentication:
- **Modal**: Run `modal token set` to configure
- **Daytona**: Set `DAYTONA_API_KEY` environment variable
- **Hopx**: Set `HOPX_API_KEY` environment variable (format: `hopx_live_<keyId>.<secret>`)
- **Sprites**: Set `SPRITES_TOKEN` environment variable, or run `sprite login` for CLI mode
- **Cloudflare** *(experimental)*: Deploy the [Cloudflare sandbox Worker](https://github.com/cloudflare/sandbox-sdk) and set `CLOUDFLARE_SANDBOX_BASE_URL`, `CLOUDFLARE_API_TOKEN`, and (optionally) `CLOUDFLARE_ACCOUNT_ID`

> **Cloudflare setup tips (experimental)**
Expand All @@ -471,14 +539,24 @@ Each provider requires appropriate authentication:
> 3. Define a secret (e.g. `SANDBOX_API_TOKEN`) in Wrangler and reuse the same value for `CLOUDFLARE_API_TOKEN` locally.
> 4. Set `CLOUDFLARE_SANDBOX_BASE_URL` to the Worker URL (e.g. `https://cf-sandbox.your-subdomain.workers.dev`).

> **Sprites (Fly.io) - Best for Claude Code**
>
> [Sprites](https://sprites.dev) are persistent Linux sandboxes with Claude Code pre-installed:
> - **Claude Code 2.0+** ready to go - just run `sandboxes claude`
> - **100GB persistent storage** - files persist across sessions
> - **Checkpoint/restore** - save and restore state in ~300ms
> - **~$0.46 for 4-hour session** - scale-to-zero billing
>
> See [Simon Willison's writeup](https://simonwillison.net/2026/Jan/9/sprites-dev/) for more details.

## Advanced Usage

### Multi-Provider Orchestration

```python
import asyncio
from sandboxes import Manager, SandboxConfig
from sandboxes.providers import E2BProvider, ModalProvider, DaytonaProvider, CloudflareProvider
from sandboxes.providers import E2BProvider, ModalProvider, DaytonaProvider, SpritesProvider, CloudflareProvider

async def main():
# Initialize manager and register providers
Expand All @@ -488,6 +566,7 @@ async def main():
manager.register_provider("modal", ModalProvider, {})
manager.register_provider("daytona", DaytonaProvider, {})
manager.register_provider("hopx", HopxProvider, {})
manager.register_provider("sprites", SpritesProvider, {"use_cli": True})
manager.register_provider(
"cloudflare",
CloudflareProvider,
Expand Down Expand Up @@ -605,6 +684,12 @@ export DAYTONA_API_KEY="dtn_..."
export MODAL_TOKEN_ID="..."
export MODAL_TOKEN_SECRET="..."

# Hopx
export HOPX_API_KEY="hopx_live_..."

# Sprites (or use `sprite login` for CLI mode)
export SPRITES_TOKEN="..."

# Cloudflare
export CLOUDFLARE_SANDBOX_BASE_URL="https://your-worker.workers.dev"
export CLOUDFLARE_API_TOKEN="..."
Expand Down Expand Up @@ -874,4 +959,4 @@ MIT License - see [LICENSE](LICENSE) file for details.

Built by [Cased](https://cased.com)

Thanks to the teams at E2B, Modal, Daytona, and Cloudflare for their excellent sandbox platforms.
Thanks to the teams at E2B, Modal, Daytona, Hopx, Fly.io (Sprites), and Cloudflare for their excellent sandbox platforms.
Loading