MySandbox
A pure-Python sandbox for Agent services, inspired by OpenSandbox.
MySandbox provides an isolated execution environment for running untrusted shell commands and Python code on behalf of LLM agents. Unlike OpenSandbox, which relies on Docker/Kubernetes for isolation, MySandbox is implemented entirely in Python with zero external runtime dependencies, making it ideal for local development, testing, and lightweight production deployments.
Key Features
-
Process-level isolation — each sandbox owns a private workspace directory and runs commands in confined subprocesses.
-
Stateful code execution — Python code runs in a persistent namespace (like a Jupyter kernel) so variables and imports survive across multiple calls.
-
Streaming output — receive stdout/stderr chunks in real time via async handlers.
-
Background commands — start long-running commands without blocking, then poll for logs and status.
-
Bash sessions — persistent shell state (cwd, env vars, functions) across multiple commands.
-
Comprehensive filesystem API — read, write, move, delete, search, list, and set permissions on files within the confined workspace.
-
Resource limits — CPU time, memory, process count, file size, and disk quotas.
-
Security policy — command denylist, environment variable filtering, and path-escape prevention.
-
Agent toolkit — 12 OpenAI function-calling tools ready to plug into any LLM agent loop.
-
Zero dependencies — pure Python standard library only.
Architecture
┌─────────────────────────────────────────────────────────┐ │ Agent / LLM │ │ (OpenAI function calling) │ └────────────────────────┬────────────────────────────────┘ │ ┌──────────▼──────────┐ │ SandboxToolkit │ ← agent/tools.py │ (12 tool schemas) │ └──────────┬──────────┘ │ ┌────────────────────────▼────────────────────────────────┐ │ MySandbox │ ← sandbox.py │ (lifecycle: create → run → pause → resume → kill) │ ├────────────┬───────────────┬──────────────┬─────────────┤ │ Commands │ Filesystem │ Code │ Metrics │ │ Service │ Service │ Service │ Service │ ├────────────┴───────────────┴──────────────┴─────────────┤ │ Isolation Layer │ │ ┌────────────┐ ┌──────────────┐ ┌────────────────┐ │ │ │ Workspace │ │ ProcessRunner│ │ SecurityPolicy │ │ │ │ (path conf)│ │ (async sub) │ │ (cmd filter) │ │ │ └────────────┘ └──────────────┘ └────────────────┘ │ └─────────────────────────────────────────────────────────┘
Quick Start
Installation
# From the source tree:
cd mysandbox
pip install -e .
# Or simply add the directory to PYTHONPATH:
export PYTHONPATH=/path/to/mysandbox:$PYTHONPATH
Basic Usage
import asyncio
from mysandbox import MySandbox, SandboxConfig
async def main():
# Create a sandbox with default configuration.
sb = await MySandbox.create(config=SandboxConfig.default())
# Run a shell command.
result = await sb.commands.run("echo hello world")
print(result.text) # "hello world\n"
# Write and read a file.
await sb.files.write_file("greet.py", 'print("hi from file")')
content = await sb.files.read_file("greet.py")
# Execute Python code with persistent state.
ctx = await sb.code.create_context()
await sb.code.run("x = 10", context=ctx)
result = await sb.code.run("print(x * 2)", context=ctx)
print(result.logs.stdout_text()) # "20\n"
# Clean up.
await sb.kill()
asyncio.run(main())
Using as a Context Manager
async with await MySandbox.create() as sb:
await sb.commands.run("echo context manager works")
# Sandbox is automatically killed when the block exits.
Agent Integration
import asyncio, json
from mysandbox import MySandbox, SandboxConfig
from mysandbox.agent import SandboxToolkit, TOOL_SCHEMAS
async def main():
sb = await MySandbox.create()
toolkit = SandboxToolkit(sb)
# TOOL_SCHEMAS is a list of OpenAI function-calling schemas.
# Pass them to your LLM, then dispatch tool calls:
result = await toolkit.call("run_command", {"command": "echo hi"})
print(result.output)
result = await toolkit.call("run_python", {"code": "print(2**10)"})
print(result.output)
await sb.kill()
asyncio.run(main())
API Reference
MySandbox
The main entry point. Manages the sandbox lifecycle and provides access to services.
| Property | Description |
|---|---|
id |
Unique sandbox identifier. |
state |
Current SandboxState (RUNNING, PAUSED, TERMINATED, etc.). |
workspace_path |
Path to the confined workspace directory. |
config |
The SandboxConfig used to create the sandbox. |
commands |
CommandService for shell command execution. |
files |
FilesystemService for file operations. |
code |
CodeService for stateful Python execution. |
| Method | Description |
|---|---|
MySandbox.create(config=...) |
Create and start a new sandbox. |
sb.pause() |
Pause all processes (best-effort). |
sb.resume() |
Resume paused processes. |
sb.kill() |
Terminate the sandbox and clean up. |
sb.get_metrics() |
Get CPU/memory/disk usage. |
sb.info() |
Get a SandboxInfo snapshot. |
CommandService
| Method | Description |
|---|---|
run(command, *, env=, timeout=, background=, ...) |
Execute a shell command. |
interrupt(execution_id) |
Interrupt a running command. |
get_status(execution_id) |
Get the status of a command. |
get_logs(execution_id, cursor=0) |
Get accumulated logs for a background command. |
create_session() |
Create a persistent bash session. |
run_in_session(session_id, command) |
Run a command in a session. |
delete_session(session_id) |
Terminate a session. |
FilesystemService
| Method | Description |
|---|---|
read_file(path) / read_bytes(path) |
Read file contents. |
write_file(path, data) / write_files(entries) |
Write files. |
create_directories(entries) |
Create directories (mkdir -p). |
delete_files(paths) / delete_directories(paths) |
Delete files/directories. |
move_files(entries) |
Move/rename files. |
set_permissions(entries) |
Change mode/owner/group. |
search(entry) |
Glob search for files. |
list_directory(entry) |
List directory contents. |
get_file_info(paths) |
Get file metadata. |
CodeService
| Method | Description |
|---|---|
create_context(language="python") |
Create a stateful execution context. |
run(code, context=, timeout=) |
Execute Python code in a context. |
get_context(id) |
Retrieve a context by ID. |
list_contexts() |
List all contexts. |
delete_context(id) |
Delete a context. |
Agent Toolkit
The SandboxToolkit exposes 12 tools in OpenAI function-calling format:
| Tool | Description |
|---|---|
run_command |
Execute a shell command. |
run_python |
Execute Python code (stateful). |
read_file |
Read a file's contents. |
write_file |
Write content to a file. |
list_directory |
List directory contents. |
create_directory |
Create a directory. |
delete_file |
Delete a file. |
delete_directory |
Delete a directory. |
move_file |
Move/rename a file. |
get_file_info |
Get file metadata. |
search_files |
Search for files by glob pattern. |
get_metrics |
Get resource usage. |
list_sessions |
List active bash sessions. |
delete_session |
Delete a bash session. |
sandbox_info |
Get sandbox metadata. |
Configuration
from mysandbox import SandboxConfig, ResourceLimits
config = SandboxConfig(
image="python:3.11", # Informational only
timeout=3600, # Sandbox TTL in seconds
resource_limits=ResourceLimits(
cpu_quota_seconds=30, # Max CPU time per execution
memory_mb=512, # Soft memory limit
max_processes=64, # Max concurrent processes
max_file_size_mb=50, # Max single file size
disk_quota_mb=500, # Total disk quota
timeout_seconds=60, # Default execution timeout
),
blocked_commands={"rm", "sudo", "shutdown"}, # Command denylist
blocked_env={"HOME", "USER", "PATH"}, # Env vars to strip
allow_network=False, # Block network commands
auto_reap=True, # Enable TTL reaper
python_executable="python3", # Python for code exec
)
Security Model
MySandbox uses multiple layers of defense:
-
Workspace confinement — all file operations are resolved through
Workspace.resolve(), which canonicalizes paths and rejects any that escape the workspace root. Symlinks are not followed during resolution. -
Command filtering — the
SecurityPolicyinspects the first token of each command and rejects any in theblocked_commandsdenylist. Network-related commands (curl,wget,ssh, etc.) are blocked whenallow_network=False. -
Environment sanitization — blocked environment variables (like
HOME,USER,PATH) are stripped from the inherited host environment before a command runs. -
Resource limits — CPU time, memory, process count, file size, and disk quotas are enforced (best-effort on platforms without cgroup support).
-
No elevated privileges — MySandbox runs as the current user; it does not use
chroot, namespaces, or any privileged operation.
Warning: MySandbox provides process-level isolation suitable for trusted-to-moderately-untrusted code. For fully untrusted code, use a container-based solution like OpenSandbox with Docker/K8s.
Comparison with OpenSandbox
| Feature | OpenSandbox | MySandbox |
|---|---|---|
| Isolation | Docker/K8s containers | Process + workspace confinement |
| Dependencies | Docker or K8s | None (pure Python) |
| Deployment | Server + controller | In-process library |
| Scalability | Multi-node clusters | Single process |
| Security | Strong (container boundary) | Moderate (process boundary) |
| Use case | Production multi-tenant | Local dev, testing, agents |
| API parity | — | Mirrors SDK API surface |
Examples
See the examples/ directory:
-
01_basic_usage.py— lifecycle, commands, files, code execution. -
02_agent_integration.py— OpenAI function-calling agent loop. -
03_streaming_and_background.py— streaming output, background commands, bash sessions.
Testing
cd mysandbox
pip install pytest pytest-asyncio
pytest tests/ -v
License
Apache License 2.0, inspired by the OpenSandbox project.
https://cdn.neusncp.com/public/file/20260729160352_lXdDu5Hj.md