codecapsules-sandbox
Ephemeral isolated Linux environments via REST API. Create a sandbox, run code, delete it — in three lines.
Powered by Firecracker microVMs. Built for AI agents, code execution APIs, and any workload that needs strong isolation without managing infrastructure.
pip install codecapsules-sandbox
Quick Start
from codecapsules_sandbox import Sandbox
# Create → exec → auto-delete
with Sandbox.create(flavor="python-3.12") as sb:
result = sb.exec("python --version")
print(result.stdout) # "Python 3.12.3\n"
print(result.exit_code) # 0
Set your API key:
export CODECAPSULES_API_KEY=your_api_key
Or pass it directly:
sb = Sandbox.create(api_key="your_api_key")
Install
pip install codecapsules-sandbox
# or
uv add codecapsules-sandbox
# or
poetry add codecapsules-sandbox
Requires Python ≥ 3.9.
Usage
Create a sandbox
from codecapsules_sandbox import Sandbox
# Default: Python 3.12, 512MB RAM, 1 vCPU, 60-minute TTL
sb = Sandbox.create()
# With options
sb = Sandbox.create(
flavor="node-20", # python-3.12 | node-20 | browser | full
memory=2048, # MB
cpu=2, # vCPUs
ttl=30, # minutes
metadata={"project": "my-agent"},
)
print(sb.id) # "sb_01hx..."
print(sb.status) # "running"
# Always clean up
sb.delete()
Context manager (recommended)
with Sandbox.create(flavor="python-3.12") as sb:
result = sb.exec("python --version")
print(result.stdout)
# Sandbox is automatically deleted here — even if an exception was raised
Execute commands
with Sandbox.create() as sb:
result = sb.exec("python --version")
print(result.stdout) # "Python 3.12.3\n"
print(result.stderr) # ""
print(result.exit_code) # 0
print(result.duration_ms) # 82
# With options
result = sb.exec(
"python /workspace/train.py",
timeout=120, # seconds (default: 30)
env={"EPOCHS": "10", "LR": "0.001"}, # environment variables
stdin="input data", # stdin content
)
# Run multiple commands
sb.exec("pip install numpy pandas")
sb.exec('python -c "import numpy; print(numpy.__version__)"')
Stream long-running commands
with Sandbox.create() as sb:
for chunk in sb.exec_stream("python train.py"):
print(chunk, end="", flush=True)
Upload and download files
with Sandbox.create() as sb:
# Upload
sb.upload("/workspace/script.py", open("script.py", "rb").read())
sb.upload("/workspace/config.json", '{"learning_rate": 0.001}')
# Run
result = sb.exec("python /workspace/script.py")
# Download the output
output = sb.download("/workspace/output.json")
import json
data = json.loads(output)
Fetch an existing sandbox
sb = Sandbox.get("sb_01hx...")
print(sb.status) # 'running' | 'starting' | 'stopping' | 'stopped' | 'error'
Sandbox logs
with Sandbox.create() as sb:
sb.exec("echo hello")
entries = sb.logs()
for e in entries:
print(f"[{e.ts.isoformat()}] [{e.source}] {e.message}")
# Since a timestamp
from datetime import datetime, timedelta
entries = sb.logs(since=datetime.utcnow() - timedelta(minutes=5), limit=50)
Resource metrics
with Sandbox.create() as sb:
m = sb.metrics()
print(f"CPU: {m.cpu_percent}%")
print(f"RAM: {m.memory_used_mb}MB / {m.memory_limit_mb}MB")
print(f"Disk: {m.disk_used_mb}MB / {m.disk_limit_mb}MB")
Async Usage
import asyncio
from codecapsules_sandbox import AsyncSandbox
async def main():
# Async context manager
async with AsyncSandbox.create(flavor="python-3.12") as sb:
result = await sb.exec("python --version")
print(result.stdout)
# Upload and exec
async with AsyncSandbox.create() as sb:
await sb.upload("/workspace/script.py", open("script.py", "rb").read())
result = await sb.exec("python /workspace/script.py")
output = await sb.download("/workspace/output.json")
# Stream output
async with AsyncSandbox.create() as sb:
async for chunk in sb.exec_stream("python train.py"):
print(chunk, end="", flush=True)
asyncio.run(main())
Environments (Flavors)
| Flavor | Pre-installed |
|---|---|
python-3.12 |
Python 3.12, pip, numpy, pandas, requests, git |
node-20 |
Node.js 20, npm, yarn, git |
browser |
Chromium, Playwright, xvfb, Python 3.12 |
full |
All of the above + jq, ffmpeg, ImageMagick |
AI Agent Integration
Anthropic Claude
import anthropic
from codecapsules_sandbox import Sandbox
client = anthropic.Anthropic()
tools = [{
"name": "run_python",
"description": (
"Execute Python code in an isolated sandbox and return the output. "
"Use this for calculations, data processing, testing code, or any task "
"requiring code execution."
),
"input_schema": {
"type": "object",
"properties": {
"code": {"type": "string", "description": "Python code to execute"},
},
"required": ["code"],
},
}]
def run_python(code: str) -> str:
with Sandbox.create() as sb:
r = sb.exec(f"python -c {repr(code)}")
return r.stdout + (f"\nSTDERR: {r.stderr}" if r.stderr else "")
def process_tool_call(tool_name: str, tool_input: dict) -> str:
if tool_name == "run_python":
return run_python(tool_input["code"])
raise ValueError(f"Unknown tool: {tool_name}")
OpenAI
import openai
from codecapsules_sandbox import Sandbox
client = openai.OpenAI()
tools = [{
"type": "function",
"function": {
"name": "execute_python",
"description": "Run Python code in an isolated sandbox. Returns stdout and stderr.",
"parameters": {
"type": "object",
"properties": {
"code": {"type": "string"},
},
"required": ["code"],
},
},
}]
def execute_python(code: str) -> str:
with Sandbox.create() as sb:
r = sb.exec(f"python -c {repr(code)}")
return f"stdout: {r.stdout}\nstderr: {r.stderr}\nexit_code: {r.exit_code}"
LangChain
from langchain.tools import tool
from codecapsules_sandbox import Sandbox
@tool
def execute_python(code: str) -> str:
"""Execute Python code in an isolated sandbox. Returns stdout, stderr, and exit code."""
with Sandbox.create() as sb:
result = sb.exec(f"python -c {repr(code)}")
return f"stdout: {result.stdout}\nstderr: {result.stderr}\nexit_code: {result.exit_code}"
smolagents (HuggingFace)
from smolagents import tool
from codecapsules_sandbox import Sandbox
@tool
def python_interpreter(code: str) -> str:
"""Execute Python code in a secure isolated environment."""
with Sandbox.create() as sb:
result = sb.exec(f"python -c {repr(code)}")
if result.exit_code != 0:
return f"Error (exit {result.exit_code}):\n{result.stderr}"
return result.stdout
Error Handling
from codecapsules_sandbox import (
Sandbox,
SandboxAuthError,
SandboxNotFoundError,
SandboxExecTimeoutError,
SandboxQuotaError,
SandboxRateLimitError,
SandboxAPIError,
)
try:
with Sandbox.create() as sb:
result = sb.exec("python script.py", timeout=10)
except SandboxAuthError:
print("Invalid API key — set CODECAPSULES_API_KEY")
except SandboxExecTimeoutError as e:
print(f"Command timed out after {e.timeout_seconds}s")
except SandboxNotFoundError as e:
print(f"Sandbox {e.sandbox_id} was deleted or expired")
except SandboxQuotaError:
print("Too many concurrent sandboxes — delete one first")
except SandboxRateLimitError as e:
print(f"Rate limited — retry after {e.retry_after_ms}ms")
except SandboxAPIError as e:
print(f"API error {e.status}: {e}")
All exceptions inherit from SandboxError.
Configuration
| Environment variable | Description | Default |
|---|---|---|
CODECAPSULES_API_KEY |
API key | — (required) |
CODECAPSULES_SANDBOX_URL |
Override API base URL | https://sandbox.codecapsules.io/v1 |
Alternatively, pass keyword arguments to Sandbox.create():
sb = Sandbox.create(
api_key="your_api_key",
base_url="https://...",
timeout=60.0, # seconds (default: 30)
max_retries=3, # on transient errors (default: 2)
)
API Reference
Sandbox.create(...) -> Sandbox
Creates a new sandbox and returns when it is running.
| Parameter | Type | Default | Description |
|---|---|---|---|
flavor |
str | 'python-3.12' |
Environment preset |
memory |
int | 512 |
Memory in MB (max 8192) |
cpu |
int | 1 |
vCPU count (max 4) |
ttl |
int | 60 |
Lifetime in minutes (max 480) |
metadata |
dict | — | Arbitrary key-value metadata |
Sandbox.get(sandbox_id) -> Sandbox
Fetches an existing sandbox by ID.
sb.exec(command, *, timeout, env, stdin) -> ExecResult
Runs a shell command. Returns ExecResult with stdout, stderr, exit_code, and timing.
sb.exec_stream(command, *, timeout, env) -> Iterator[str]
Runs a command and yields output chunks. Use in a for loop.
sb.upload(sandbox_path, content) -> FileInfo
Uploads bytes or str content to a path inside the sandbox.
sb.download(sandbox_path) -> bytes
Downloads a file from the sandbox.
sb.logs(*, since, limit) -> list[LogEntry]
Returns system and exec log entries.
sb.metrics() -> SandboxMetrics
Returns live CPU, memory, and disk usage.
sb.refresh() -> Sandbox
Re-fetches sandbox info from the API (updates cached status).
sb.wait_until_running(*, timeout, interval) -> Sandbox
Polls until status is running. Raises SandboxNotReadyError on timeout.
sb.stop() -> None
Gracefully stops the sandbox.
sb.delete() -> None
Deletes the sandbox and releases all resources.
Types
from codecapsules_sandbox import (
SandboxInfo, # dataclass: id, status, flavor, cpu, memory, created_at, expires_at
ExecResult, # dataclass: exec_id, command, stdout, stderr, exit_code, duration_ms
FileInfo, # dataclass: path, size_bytes, created_at
LogEntry, # dataclass: ts, source, message, exec_id
SandboxMetrics, # dataclass: id, status, cpu_percent, memory_used_mb, ...
SandboxStatus, # Literal["starting", "running", "stopping", "stopped", "error"]
SandboxFlavor, # Literal["python-3.12", "node-20", "browser", "full"]
)
All types are fully typed — compatible with mypy, pyright, and Pylance.
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file codecapsules_sandbox-0.1.0.tar.gz.
File metadata
- Download URL: codecapsules_sandbox-0.1.0.tar.gz
- Upload date:
- Size: 18.3 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via:
twine/6.2.0 CPython/3.11.6
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
c625ab6667d1d7c2a7f5b49d0af508722586ac6aae0f480ea31bbd5db58e12e3
|
|
| MD5 |
cc19aeb829bbacc46f49d7af779fbaed
|
|
| BLAKE2b-256 |
3db7a037f3ceee3981b658bcda822df955493848baa65e25d08784c3c8aac74b
|
File details
Details for the file codecapsules_sandbox-0.1.0-py3-none-any.whl.
File metadata
- Download URL: codecapsules_sandbox-0.1.0-py3-none-any.whl
- Upload date:
- Size: 18.2 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via:
twine/6.2.0 CPython/3.11.6
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
1dc76995efa5143cf1a00685dad446797429296b646e216255fc463b282a5a65
|
|
| MD5 |
c0eeb6c05f2d0d20e081c8f08a3c2004
|
|
| BLAKE2b-256 |
6a47aede334ced0f493a9aa1b4410596ef208ea27badce0c1e7afcdd55c837fc
|