Skip to main content
A coding agent that writes and executes code inside an isolated Docker container. The agent gets six built-in tools (exec, read, write, edit, glob, grep) that all operate inside the container, with the workspace directory bind-mounted from the host.

Create sandbox tools

import os
from polos import (
    Agent, max_steps, MaxStepsConfig,
    sandbox_tools, SandboxToolsConfig, DockerEnvironmentConfig,
)

# Workspace directory on the host -- gets mounted into the container at /workspace
workspace_dir = os.path.join(os.path.dirname(os.path.abspath(__file__)), "workspace")

# Create sandbox tools that run inside a Docker container
tools = sandbox_tools(
    SandboxToolsConfig(
        env="docker",
        docker=DockerEnvironmentConfig(
            image="node:20-slim",
            workspace_dir=workspace_dir,
            # setup_command="npm install",  # optional: run after container creation
            # memory="512m",               # optional: limit container memory
            # network="none",              # default: no network access
        ),
    )
)

Define the agent

coding_agent = Agent(
    id="coding_agent",
    provider="anthropic",
    model="claude-sonnet-4-5",
    system_prompt=(
        "You are a coding agent with access to a sandbox environment. "
        "You can create files, edit code, run shell commands, and search the codebase. "
        "The workspace is at /workspace inside the container. "
        "Use the tools to complete the task, then summarize what you did and show the output. "
        "Always verify your work by running the code after writing it. "
        "In your final response, include the actual output from running the code."
    ),
    tools=tools,
    stop_conditions=[max_steps(MaxStepsConfig(count=50))],
)

Stream activity

The client invokes the agent and streams text deltas and tool calls in real time.
from polos import PolosClient
from polos.features import events

handle = await client.invoke(
    coding_agent.id, {"input": task, "conversationId": conversation_id, "streaming": True}
)

async for event in events.stream_workflow(client, handle.root_workflow_id, handle.id):
    if event.event_type == "text_delta":
        content = event.data.get("content") if isinstance(event.data, dict) else None
        if isinstance(content, str):
            print(content, end="", flush=True)
    elif event.event_type == "tool_call":
        tool_call = event.data.get("tool_call", {}) if isinstance(event.data, dict) else {}
        tool_name = tool_call.get("function", {}).get("name", "unknown")
        print(f"\n  [Using {tool_name}...]")

How it works

  1. sandboxTools() creates six tools that operate inside a Docker container
  2. The container is created lazily on first use and reused across tool calls
  3. The host workspace directory is bind-mounted into the container at /workspace
  4. The agent can write files, run commands, and search the codebase — all isolated from your host system
  5. On shutdown, tools.cleanup() removes the container

Run it

git clone https://github.com/polos-dev/polos.git
cd polos/python-examples/18-sandbox-tools
cp .env.example .env
uv sync
python worker.py      # Terminal 1
python main.py        # Terminal 2
Docker must be installed and running. The container image (node:20-slim) will be pulled automatically on first run.
Open http://localhost:5173 to view your agents and workflows, run them from the UI, and see execution traces. Python example on GitHub | TypeScript example on GitHub