Skip to main content
Sandbox tools give agents the ability to write code, run shell commands, and explore a codebase - all inside a controlled environment. A single call to sandbox_tools() creates six tools (exec, read, write, edit, glob, grep) that share an execution environment.
from polos import Agent, sandbox_tools, SandboxToolsConfig, DockerEnvironmentConfig

tools = sandbox_tools(SandboxToolsConfig(
    env="docker",
    docker=DockerEnvironmentConfig(
        image="node:20-slim",
        workspace_dir="./workspace",
    ),
))

coding_agent = Agent(
    id="coding_agent",
    provider="anthropic",
    model="claude-sonnet-4-5",
    system_prompt="You are a coding assistant. The repo is at /workspace.",
    tools=tools,
)

Environments

Polos supports three execution environments. The environment determines where tools execute and what isolation guarantees you get.
EnvironmentIsolationRequiresBest for
docker (default)ContainerDockerProduction, untrusted code
localNone (host machine)NothingDevelopment, trusted agents
e2b (coming soon)Cloud sandboxE2B accountCloud-native deployments

Docker

Commands run inside an isolated Docker container. Your host workspace directory is bind-mounted into the container.
from polos import sandbox_tools, SandboxToolsConfig, DockerEnvironmentConfig

tools = sandbox_tools(SandboxToolsConfig(
    env="docker",
    docker=DockerEnvironmentConfig(
        image="node:20-slim",
        workspace_dir="./workspace",
        # container_workdir="/workspace",  # default
        # memory="512m",                   # memory limit
        # cpus="1",                        # CPU limit
        # network="none",                  # default: no network
        # setup_command="npm install",     # run after container creation
        # env={"NODE_ENV": "production"},  # environment variables
    ),
))

Docker configuration

OptionDefaultDescription
imagerequiredDocker image (e.g., "node:20-slim", "python:3.12-slim")
workspace_dir / workspaceDirrequiredHost directory mounted into the container
container_workdir / containerWorkdir"/workspace"Working directory inside the container
memoryNo limitMemory limit (e.g., "512m", "2g")
cpusNo limitCPU limit (e.g., "1", "0.5")
network"none"Network mode. Use "bridge" to allow network access
setup_command / setupCommandNoneCommand to run after container creation
envNoneEnvironment variables set inside the container
The container is created lazily on the first tool call and reused for subsequent calls. Call tools.cleanup() to destroy it when done.

Local

Commands run directly on your host machine. Since there’s no container isolation, exec security defaults to approval-always and file operations default to requiring approval.
from polos import sandbox_tools, SandboxToolsConfig, LocalEnvironmentConfig

tools = sandbox_tools(SandboxToolsConfig(
    env="local",
    local=LocalEnvironmentConfig(
        cwd="./workspace",
        path_restriction="./workspace",  # confine file access
    ),
))

Local configuration

OptionDefaultDescription
cwdCurrent working directoryWorking directory for commands
path_restriction / pathRestrictionNoneRestrict file operations to this directory. Symlink traversal is blocked.

Local mode defaults

In local mode, Polos applies stricter defaults since there’s no container boundary:
SettingLocal defaultDocker default
Exec securityapproval-alwaysNo check
File approval (write/edit)alwaysNone
Path restriction (read/glob/grep)Approval required outside workspaceNo restriction

E2B

E2B support is coming soon. The configuration is defined but not yet implemented.
from polos import sandbox_tools, SandboxToolsConfig, E2BEnvironmentConfig

tools = sandbox_tools(SandboxToolsConfig(
    env="e2b",
    e2b=E2BEnvironmentConfig(
        template="base",
        # api_key="...",          # defaults to E2B_API_KEY env var
        # timeout=3600,           # sandbox timeout in seconds
        # cwd="/workspace",       # working directory
        # setup_command="...",    # setup command
    ),
))

Built-in tools

sandbox_tools() creates six tools that all operate within the shared environment:
ToolDescription
execRun shell commands
readRead file contents
writeWrite/create files
editFind-and-replace in files
globFind files by pattern
grepSearch file contents
To include only a subset of tools:
tools = sandbox_tools(SandboxToolsConfig(
    env="docker",
    docker=DockerEnvironmentConfig(image="node:20-slim", workspace_dir="./workspace"),
    tools=["exec", "read", "write"],  # only these three
))

Exec security

The exec tool supports three security modes that control which shell commands can run without user approval.
from polos import sandbox_tools, SandboxToolsConfig, DockerEnvironmentConfig, ExecToolConfig

tools = sandbox_tools(SandboxToolsConfig(
    env="docker",
    docker=DockerEnvironmentConfig(image="node:20-slim", workspace_dir="./workspace"),
    exec=ExecToolConfig(
        security="allowlist",
        allowlist=["node *", "cat *", "ls *", "ls", "echo *"],
        # timeout=300,            # command timeout in seconds (default: 300)
        # max_output_chars=100000, # truncate output after this many chars
    ),
))

Security modes

ModeBehavior
allow-alwaysAll commands run without approval. Default for Docker and E2B.
allowlistCommands matching patterns run automatically. Non-matching commands suspend for approval.
approval-alwaysEvery command suspends for user approval. Default for local mode.
Allowlist patterns use glob-style matching. "node *" matches node hello.js but not npm install. When a command is rejected, the agent receives the rejection along with any feedback the user provided, and can adjust its approach.

Exec configuration

OptionDefaultDescription
securityallow-always (Docker), approval-always (local)Security mode
allowlistNoneCommand patterns for allowlist mode
timeout300Command timeout in seconds
max_output_chars / maxOutputChars100000Truncate output after this many characters

File approval

Write and edit operations can require user approval before modifying files.
tools = sandbox_tools(SandboxToolsConfig(
    env="docker",
    docker=DockerEnvironmentConfig(image="node:20-slim", workspace_dir="./workspace"),
    file_approval="always",  # require approval for write and edit
))
ValueBehavior
"always"Write and edit suspend for approval. Default for local mode.
"none"No approval required. Default for Docker and E2B.

Path restriction

When path_restriction / pathRestriction is set (local mode), read-only tools (read, glob, grep) run freely within the restricted directory but suspend for approval when accessing paths outside it. Symlink traversal outside the restriction is blocked.
tools = sandbox_tools(SandboxToolsConfig(
    env="local",
    local=LocalEnvironmentConfig(
        cwd="./workspace",
        path_restriction="./workspace",
    ),
))
# read("./workspace/file.txt")  → runs immediately
# read("/etc/hosts")            → suspends for approval

Cleanup

The execution environment (Docker container, E2B sandbox) is created lazily on the first tool call. Call cleanup() to destroy it when you’re done.
import signal, asyncio

loop = asyncio.get_event_loop()
loop.add_signal_handler(signal.SIGINT, lambda: asyncio.ensure_future(tools.cleanup()))

# Or in a try/finally
try:
    await worker.run()
finally:
    await tools.cleanup()

Examples