Sandboxes
This skill teaches Claude how to effectively build and deploy applications on Modal's serverless platform.
npx -y skills add samarth777/modal-skills --skill sandboxesAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
One thing to look at
- 1 stars1 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
SKILL.md
6.3 KB, as published. Nobody here has run it
Modal Sandboxes Reference
Detailed reference for running arbitrary code in isolated containers.
Overview
Sandboxes are containers you can create, interact with, and terminate at runtime. They're ideal for:
- Executing LLM-generated code
- Running untrusted user code
- Interactive development environments
- Dynamic code analysis
Basic Usage
import modal
# Get or create an App reference
app = modal.App.lookup("sandbox-app", create_if_missing=True)
# Create a sandbox
sb = modal.Sandbox.create(app=app)
# Execute commands
p = sb.exec("python", "-c", "print('Hello!')")
print(p.stdout.read()) # "Hello!\n"
# Clean up
sb.terminate()
Configuration
Custom Images
image = (
modal.Image.debian_slim()
.pip_install("pandas", "numpy", "matplotlib")
)
with modal.enable_output(): # Show build logs
sb = modal.Sandbox.create(
image=image,
app=app,
)
Volumes
volume = modal.Volume.from_name("my-volume", create_if_missing=True)
sb = modal.Sandbox.create(
volumes={"/data": volume},
app=app,
)
# Files written to /data persist across sandboxes
sb.exec("bash", "-c", "echo 'hello' > /data/output.txt").wait()
Secrets
secret = modal.Secret.from_dict({"API_KEY": "xxx"})
sb = modal.Sandbox.create(
secrets=[secret],
app=app,
)
p = sb.exec("bash", "-c", "echo $API_KEY")
print(p.stdout.read()) # "xxx\n"
GPU Access
sb = modal.Sandbox.create(
gpu="A100",
app=app,
)
p = sb.exec("nvidia-smi")
print(p.stdout.read())
Timeouts
sb = modal.Sandbox.create(
timeout=600, # Max 10 minutes total
idle_timeout=60, # Auto-terminate after 60s idle
app=app,
)
Working Directory
sb = modal.Sandbox.create(
workdir="/app",
app=app,
)
Executing Commands
Basic Execution
# Simple command
p = sb.exec("python", "-c", "print(1+1)")
p.wait() # Wait for completion
print(p.returncode) # 0
# Read output
print(p.stdout.read()) # "2\n"
print(p.stderr.read()) # ""
Streaming Output
p = sb.exec("bash", "-c", "for i in {1..5}; do echo $i; sleep 1; done")
# Stream line by line
for line in p.stdout:
print(line, end="")
With Timeout
p = sb.exec("sleep", "100", timeout=5)
# Raises TimeoutError after 5 seconds
With Entrypoint
Run a single command as the sandbox's main process:
sb = modal.Sandbox.create(
"python", "-m", "http.server", "8080",
app=app,
timeout=60,
)
# Sandbox runs until command completes or timeout
for line in sb.stdout:
print(line, end="")
File System Access
Filesystem API (Alpha)
# Write file
with sb.open("output.txt", "w") as f:
f.write("Hello, World!")
# Read file
with sb.open("output.txt", "r") as f:
content = f.read()
# Binary mode
with sb.open("data.bin", "wb") as f:
f.write(b"\x00\x01\x02")
# Directory operations
sb.mkdir("/app/data")
files = sb.ls("/app")
sb.rm("/app/data/temp.txt")
Using Volumes
# Ephemeral volume (auto-cleanup)
with modal.Volume.ephemeral() as vol:
# Upload files
with vol.batch_upload() as batch:
batch.put_file("local.txt", "/remote.txt")
batch.put_directory("./local_dir", "/remote_dir")
sb = modal.Sandbox.create(
volumes={"/data": vol},
app=app,
)
# Work with files
sb.exec("cat", "/data/remote.txt").wait()
sb.terminate()
sb.wait(raise_on_termination=False)
# Read files after sandbox terminates
for chunk in vol.read_file("output.txt"):
print(chunk)
Syncing Volume Changes
For Volumes v2, explicitly sync changes:
sb.exec("bash", "-c", "echo 'data' > /data/file.txt").wait()
sb.exec("sync", "/data").wait() # Persist changes immediately
Networking
Port Forwarding with Tunnels
sb = modal.Sandbox.create(
"python", "-m", "http.server", "8080",
app=app,
)
tunnel = sb.tunnels()[8080]
print(f"Access at: {tunnel.url}")
Network Isolation
# Block all network access
sb = modal.Sandbox.create(
block_network=True,
app=app,
)
Snapshots
Filesystem Snapshots
Save sandbox state as a new image:
sb = modal.Sandbox.create(app=app)
# Set up environment
sb.exec("pip", "install", "pandas").wait()
sb.exec("mkdir", "/app/data").wait()
# Create snapshot
image = sb.snapshot_filesystem()
sb.terminate()
# Use snapshot for new sandbox
sb2 = modal.Sandbox.create(image=image, app=app)
sb2.exec("python", "-c", "import pandas; print(pandas.__version__)").wait()
Security Best Practices
For Untrusted Code
sb = modal.Sandbox.create(
# Restrict Modal API access
restrict_modal_access=True,
# Block network
block_network=True,
# Set timeout
timeout=30,
# Minimal image
image=modal.Image.debian_slim(),
app=app,
)
LLM Code Execution
def execute_llm_code(code: str) -> dict:
app = modal.App.lookup("code-executor", create_if_missing=True)
sb = modal.Sandbox.create(
image=modal.Image.debian_slim().pip_install("numpy", "pandas"),
timeout=30,
block_network=True,
app=app,
)
try:
# Write code to file
with sb.open("/tmp/code.py", "w") as f:
f.write(code)
# Execute
p = sb.exec("python", "/tmp/code.py", timeout=10)
p.wait()
return {
"stdout": p.stdout.read(),
"stderr": p.stderr.read(),
"returncode": p.returncode,
}
finally:
sb.terminate()
Lifecycle Management
Graceful Shutdown
sb.terminate() # Request termination
sb.wait(raise_on_termination=False) # Wait for cleanup
Check Status
if sb.poll() is None:
print("Still running")
else:
print(f"Terminated with code: {sb.poll()}")
Async Usage
import asyncio
async def run_async():
app = await modal.App.lookup.aio("sandbox-app", create_if_missing=True)
sb = await modal.Sandbox.create.aio(app=app)
p = await sb.exec.aio("python", "-c", "print('async!')")
output = await p.stdout.read.aio()
print(output)
await sb.terminate.aio()