# DockerSandbox runs harness agents in a locked-down container

> Agno's DockerSandbox gives each sandboxed ClaudeAgent or CodexAgent session its own container, running as UID 1000 on a read-only image with every capability dropped and no network unless you ask for one.

- Published: 2026-10-16
- Author: Ashpreet Bedi
- Categories: Changelog
- Canonical: https://www.agno.com/blog/dockersandbox-runs-harness-agents-in-a-locked-down-container
- Markdown: https://www.agno.com/blog/dockersandbox-runs-harness-agents-in-a-locked-down-container.md

Agno's `DockerSandbox` names every container after a hash of the namespace, agent, session and generation, so two replicas racing to create the same computer, or a create whose response got lost, both land on one container. Commands never retry on their own: a timeout, a cancel or an uncertain transport result stops the container, and recovery goes through the checkpoint.

```python
from agno.agents.claude import ClaudeAgent
from agno.db.postgres import PostgresDb
from agno.sandbox.docker import DockerSandbox

agent = ClaudeAgent(
    id="coder",
    db=PostgresDb(db_url="postgresql+psycopg://ai:ai@localhost:5532/ai"),
    sandbox=DockerSandbox(
        "agno-sandbox:local",
        cpus=2.0,
        memory_mb=2048,
        pids_limit=256,
        workspace_mb=512,
        network="isolated",
    ),
)
```

We created a real `DockerSandbox` computer with the default settings from the runtime image this release builds, then read back what Docker recorded and what a process inside could do. The agent's files live on bounded tmpfs volumes (512 MB at `/workspace`, 256 MB at `/runtime`), and nothing from the host is mounted, the Docker socket included.

![A DockerSandbox container created with the default settings, real output. Left, docker inspect shows User 1000:1000, ReadonlyRootfs True, CapDrop ALL, SecurityOpt no-new-privileges, NetworkMode none, Memory 2147483648, NanoCpus 2000000000, PidsLimit 256, Binds None and Privileged False. Right, inside the sandbox: id prints uid=1000(sandbox), touching /usr/local/probe fails with Read-only file system, CapEff is all zeros and NoNewPrivs is 1, a connection to 1.1.1.1 port 443 fails with OSError Errno 101 Network is unreachable, and /var/run/docker.sock does not exist.](https://www.agno.com/images/v3-1-4-docker-sandbox-security.png)

The container sees `HOME`, the `env=` you pass, and the agent's model credential (`ANTHROPIC_API_KEY` or `CLAUDE_CODE_OAUTH_TOKEN` for Claude, `OPENAI_API_KEY` for Codex), which Agno forwards from the host when `env=` leaves it out. The values travel through a private env file, so they never appear in the host's process list.

Networking starts at `none`. With `network="isolated"`, Agno creates one bridge per host called `agno-sandbox`, with inter-container traffic switched off, on `172.30.0.0/22` unless `subnet=` picks another range. Sandboxes on it reach the internet and the host's published ports, while traffic between them stays blocked. `docker network inspect` on that bridge showed `com.docker.network.bridge.enable_icc: false`, and `remove_network()` deleted the bridge once nothing was attached. `DockerSandbox` refuses `network="host"` and `container:` networking at construction.

`pause()` freezes a container through the kernel's cgroup freezer, with memory, processes and files kept as they were, and `resume()` thaws it. `DockerCheckpointTransfer` copies a frozen container's files in and out through the Docker daemon, with no host bind mounts. To build the runtime image, run `python cookbook/frameworks/sandbox/build_image.py`. It sends Docker only the public package sources, tags the image `agno-sandbox:local` and confirms the tag is in the image store.

See the [cookbook](https://github.com/agno-agi/agno/blob/main/cookbook/frameworks/sandbox/docker/docker_execution.py), and learn more about [running Claude and Codex as harness agents](https://docs.agno.com/agent-os/multi-framework/overview) in the documentation.
