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.
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
sandboxTools() creates six tools that operate inside a Docker container
- The container is created lazily on first use and reused across tool calls
- The host
workspace directory is bind-mounted into the container at /workspace
- The agent can write files, run commands, and search the codebase — all isolated from your host system
- 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