---
title: Python SDK
description: "Install and use the official Python SDK for Caged."
---

# Python SDK

The official Python SDK for the Caged platform. Requires Python 3.9+.

## Installation

```bash
pip install caged
```

## Quick Start

```python
from caged import Caged

caged = Caged(api_key="caged_sk_...")

sandbox = caged.sandboxes.create(template="python-312", memory_mb=1024)
print(f"Sandbox {sandbox.id} is {sandbox.status}")
```

## Context Manager

The client can be used as a context manager to ensure connections are closed:

```python
with Caged(api_key="caged_sk_...") as caged:
    sandbox = caged.sandboxes.create(template="node-20")
    # ... use sandbox ...
    caged.sandboxes.destroy(sandbox.id)
```

## Sandboxes

```python
# Create with options
sandbox = caged.sandboxes.create(
    template="node-20",
    cpus=2,
    memory_mb=1024,
    repo="https://github.com/user/repo",
    env={"NODE_ENV": "development"},
)

# Create with an AI agent and a budget cap
agent_box = caged.sandboxes.create(
    template="python-312",
    agents=["claude"],
    budget=5.00,  # USD
    env={"ANTHROPIC_API_KEY": os.environ["ANTHROPIC_API_KEY"]},
)

# List all
sandboxes = caged.sandboxes.list()

# Get by ID
sb = caged.sandboxes.get("cage_abc123")

# Lifecycle
caged.sandboxes.pause("cage_abc123")
caged.sandboxes.resume("cage_abc123")
caged.sandboxes.destroy("cage_abc123")
```

## Executing Commands

Run shell commands inside a sandbox — including prompting installed AI agents:

```python
# Run a command
result = caged.sandboxes.exec(sandbox.id, "pytest -x")
print(result.output)
if not result.ok:
    print(f"Tests failed with exit code {result.exit_code}")

# Prompt Claude Code (requires agents=["claude"] at creation)
answer = caged.sandboxes.exec(
    sandbox.id,
    'cd /workspace && claude -p "Find and fix the failing test"',
)
print(answer.output)
```

<Note>
A non-zero `exit_code` does not raise — it means the command ran and failed.
Only infrastructure failures (sandbox unreachable) set `result.error`.
Exec calls default to a 5-minute timeout; pass `timeout=600` to override.
</Note>

## Files

```python
# List directory
files = caged.files.list(sandbox.id, "/workspace")

# Read file
content = caged.files.read(sandbox.id, "/workspace/main.py")

# Write file
caged.files.write(sandbox.id, "/workspace/main.py", "print('hello')")

# Git diff
diff = caged.files.git_diff(sandbox.id)
```

## Snapshots

```python
import time

# Create
snapshot = caged.snapshots.create(sandbox.id, name="checkpoint-1")

# Wait for completion
while snapshot.status == "pending":
    time.sleep(1)
    snapshot = caged.snapshots.get(snapshot.id)

# Restore
caged.snapshots.restore(snapshot.id)

# Download URL
url = caged.snapshots.download_url(snapshot.id)
```

## Error Handling

```python
from caged import Caged, CagedAPIError, CagedTimeoutError

caged = Caged(api_key="caged_sk_...")

try:
    caged.sandboxes.get("nonexistent")
except CagedAPIError as e:
    print(f"API error {e.status}: {e}")
except CagedTimeoutError as e:
    print(f"Timeout: {e}")
```

## Type Safety

The SDK uses dataclasses with full type annotations. All return types are typed:

```python
from caged import Sandbox, FileEntry, Snapshot

sandbox: Sandbox = caged.sandboxes.get("cage_abc123")
files: list[FileEntry] = caged.files.list(sandbox.id)
```
