Docker sandbox tools for Axio
Project description
axio-tools-docker
Docker sandbox tools for axio.
DockerSandbox is an async context manager that spins up an isolated Docker
container on entry and removes it on exit. Inside the context it exposes six
axio tools - the same shell, write_file, read_file, list_files,
run_python, and patch_file as axio-tools-local, but every operation runs
inside the container, never on the host.
Requirements
Docker must be installed and running:
docker info # should succeed
The package talks to the Docker Engine API directly via
aiodocker - the docker CLI is not
required.
Installation
pip install axio-tools-docker
Quick start
import asyncio
from axio.agent import Agent
from axio.context import MemoryContextStore
from axio.testing import StubTransport, make_text_response
from axio_tools_docker import DockerSandbox
async def main() -> None:
transport = StubTransport([make_text_response("Done.")])
async with DockerSandbox(image="python:3.12-alpine") as sandbox:
agent = Agent(
system="You are a coding assistant. Use the sandbox tools to run code safely.",
tools=sandbox.tools,
transport=transport,
)
ctx = MemoryContextStore()
result = await agent.run("Print hello from Python.", ctx)
print(result)
asyncio.run(main())
Sandbox tools
These mirror axio-tools-local exactly - same names and field schemas:
| Tool | Description |
|---|---|
shell |
Run a shell command; returns stdout + stderr. Supports timeout, cwd, stdin. |
write_file |
Create or overwrite a file. Parent directories are created automatically. |
read_file |
Read a file with optional start_line/end_line, line_numbers, max_chars. |
list_files |
List a directory; directories first with a trailing /. |
run_python |
Execute a Python snippet in a subprocess. Supports timeout, cwd, stdin. |
patch_file |
Replace lines from_line..to_line (1-indexed, inclusive). to_line = from_line - 1 inserts. |
Container lifecycle
The container is created on __aenter__ and removed on __aexit__ (docker rm -f).
Cleanup runs even when the body raises an exception:
from axio_tools_docker import DockerSandbox
from axio import Agent
async def run(ctx):
agent = Agent(
system="You are a coding assistant. Use the sandbox tools to run code safely.",
tools=ctx.sandbox.tools,
)
async with DockerSandbox(image="alpine:latest") as sandbox:
await agent.run("...", ctx)
# container removed here (unless remove=False)
The image is pulled automatically if not present locally. If the Docker daemon
is unreachable, __aenter__ raises immediately:
RuntimeError: Docker daemon not available at 'unix:///var/run/docker.sock': ...
The running container's ID is available as sandbox.container_id inside the
async with block.
Named containers and reuse
Pass name= to give the container a fixed name. If a container with that name
already exists, the sandbox starts it if needed and attaches instead of creating
a new one. Attached containers are never removed on exit - regardless of
remove:
import asyncio
from axio_tools_docker import DockerSandbox
async def first_session() -> None:
async with DockerSandbox(image="python:3.12-slim", name="my-sandbox", remove=False) as sb:
await sb.exec("pip install requests")
async def second_session() -> None:
async with DockerSandbox(name="my-sandbox") as sb:
result = await sb.exec("python3 -c 'import requests; print(requests.__version__)'")
asyncio.run(first_session())
asyncio.run(second_session())
Named volumes
Named volumes are managed by the Docker daemon and persist across container restarts. Use them to share state between sandbox sessions:
import asyncio
from axio_tools_docker import DockerSandbox
async def main() -> None:
async with DockerSandbox(
image="python:3.12-alpine",
named_volumes={"/data": "my-project-data"},
) as sb:
await sb.write_file("/data/state.json", '{"count": 1}')
# Container removed, volume survives.
async with DockerSandbox(
image="python:3.12-alpine",
named_volumes={"/data": "my-project-data"},
volumes_remove=True, # delete the volume on exit
) as sb:
raw = await sb.read_file_bytes("/data/state.json")
assert raw.decode() == '{"count": 1}'
asyncio.run(main())
Docker creates the volume automatically if it does not exist yet.
Configuration
import os
from axio_tools_docker import DockerSandbox
sandbox = DockerSandbox(
os.getenv("DOCKER_HOST", "unix:///var/run/docker.sock"), # Docker daemon URL, optional
image="python:3.12-slim",
memory="512m", # memory limit: "256m", "1g", …
cpus="2.0", # CPU limit
network=False, # False=none, True=default, str=explicit mode
workdir="/workspace",
volumes={"/workspace": "/tmp/host-dir"}, # {container_path: host_path}
named_volumes={"/data": "my-project-data"}, # named Docker volumes
volumes_remove=False, # remove named volumes on exit
env={"PYTHONPATH": "/app"},
user="nobody",
name="my-agent-sandbox",
remove=False,
read_only=True, # read-only root filesystem
shm_size="64m", # /dev/shm size
cap_add=["NET_ADMIN"], # add Linux capabilities
cap_drop=["ALL"], # drop Linux capabilities
privileged=False,
ulimits={"nofile": (1024, 65536), "nproc": 512},
tmpfs={"/tmp": "size=128m,mode=1777"},
ports={8080: 8080}, # {container_port: host_port}
platform="linux/amd64",
extra_hosts={"host.docker.internal": "host-gateway"},
devices=["/dev/net/tun", "/dev/sda:/dev/xvda:r"],
dns=["8.8.8.8", "1.1.1.1"],
)
assert sandbox.image == "python:3.12-slim"
assert sandbox.memory == "512m"
assert sandbox.cpus == "2.0"
assert sandbox.network == False
| Parameter | Type | Default | Description |
|---|---|---|---|
url |
str |
"unix:///var/run/docker.sock" |
Docker daemon URL (unix socket or TCP). Positional. |
image |
str |
"python:latest" |
Container image. Pulled automatically if not present. |
memory |
str |
"256m" |
Memory limit. Accepts k/m/g suffixes. |
cpus |
str |
"1.0" |
CPU limit as a decimal string. |
network |
bool | str |
False |
Network mode. False → none. True → Docker default. String → explicit NetworkMode (e.g. "host", "bridge", "my-net"). |
workdir |
str |
"/workspace" |
Working directory inside the container. |
volumes |
dict[str, str] |
{} |
Bind mounts as {container_path: host_path}. |
named_volumes |
dict[str, str] |
{} |
Named Docker volumes as {container_path: volume_name}. Created automatically if absent. |
volumes_remove |
bool |
False |
Remove named volumes on exit. No effect when attached to an existing container. |
env |
dict[str, str] |
{} |
Environment variables passed to all commands. |
user |
str |
"" |
User to run as (e.g. "nobody", "1000"). |
name |
str |
"" |
Container name. Attaches to existing container if found; creates new one otherwise. |
remove |
bool |
True |
Remove container on exit. No effect when attached to an existing container. |
read_only |
bool |
False |
Read-only root filesystem. Combine with tmpfs for writable scratch paths. |
shm_size |
str |
"" |
/dev/shm size (e.g. "64m"). Useful for PyTorch / shared-memory IPC. |
cap_add |
list[str] |
[] |
Linux capabilities to add (e.g. ["NET_ADMIN", "SYS_PTRACE"]). |
cap_drop |
list[str] |
[] |
Linux capabilities to drop (e.g. ["ALL"]). |
privileged |
bool |
False |
Extended privileges - full capability set and device access. Use with care. |
ulimits |
dict[str, int | tuple[int, int]] |
{} |
Resource limits. {"nofile": 1024} → soft=hard=1024. {"nofile": (1024, 65536)} → soft/hard split. |
tmpfs |
dict[str, str] |
{} |
Tmpfs mounts as {path: options} (e.g. {"/tmp": "size=128m,mode=1777"}). |
ports |
dict[int, int] |
{} |
Port bindings as {container_port: host_port}. Only meaningful when network != False. |
platform |
str |
"" |
Platform override (e.g. "linux/amd64", "linux/arm64"). |
extra_hosts |
dict[str, str] |
{} |
Extra /etc/hosts entries as {hostname: ip}. |
devices |
list[str] |
[] |
Host devices to expose. Format: "/dev/sda", "/dev/sda:/dev/xvda", "/dev/sda:/dev/xvda:r". |
dns |
list[str] |
[] |
DNS servers (e.g. ["8.8.8.8"]). Only meaningful when network != False. |
Part of the axio ecosystem
axio · axio-tools-local · axio-tools-mcp · axio-tui
License
MIT
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file axio_tools_docker-0.9.4.tar.gz.
File metadata
- Download URL: axio_tools_docker-0.9.4.tar.gz
- Upload date:
- Size: 49.7 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
47b34fc892b6632e34412419872d2cd9035aea9e305e57c7c61bb575e194ffeb
|
|
| MD5 |
ab8bec7d2d301a10fd1c08fd8285d37f
|
|
| BLAKE2b-256 |
6bbbd9628654d71326f29d760421800584fd0c4007ebad9b4593c17b04e6f25a
|
Provenance
The following attestation bundles were made for axio_tools_docker-0.9.4.tar.gz:
Publisher:
publish.yml on mosquito/axio-agent
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
axio_tools_docker-0.9.4.tar.gz -
Subject digest:
47b34fc892b6632e34412419872d2cd9035aea9e305e57c7c61bb575e194ffeb - Sigstore transparency entry: 1508372536
- Sigstore integration time:
-
Permalink:
mosquito/axio-agent@7e241c87e64230bbb58e6df8cbb2ed72347f0aaf -
Branch / Tag:
refs/tags/0.9.4 - Owner: https://github.com/mosquito
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@7e241c87e64230bbb58e6df8cbb2ed72347f0aaf -
Trigger Event:
release
-
Statement type:
File details
Details for the file axio_tools_docker-0.9.4-py3-none-any.whl.
File metadata
- Download URL: axio_tools_docker-0.9.4-py3-none-any.whl
- Upload date:
- Size: 13.0 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
1c4fe7a9b1da26d917a6b9aa9744052c2e1387900132f69a481b665defed747e
|
|
| MD5 |
f78a949550ef9a12d7dccb4cd549911f
|
|
| BLAKE2b-256 |
27c858df96e1530661582bc9ccff7cc8d001bfb6ff92de26a30a7fbbe5ec1065
|
Provenance
The following attestation bundles were made for axio_tools_docker-0.9.4-py3-none-any.whl:
Publisher:
publish.yml on mosquito/axio-agent
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
axio_tools_docker-0.9.4-py3-none-any.whl -
Subject digest:
1c4fe7a9b1da26d917a6b9aa9744052c2e1387900132f69a481b665defed747e - Sigstore transparency entry: 1508372596
- Sigstore integration time:
-
Permalink:
mosquito/axio-agent@7e241c87e64230bbb58e6df8cbb2ed72347f0aaf -
Branch / Tag:
refs/tags/0.9.4 - Owner: https://github.com/mosquito
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@7e241c87e64230bbb58e6df8cbb2ed72347f0aaf -
Trigger Event:
release
-
Statement type: