Docker sandboxes
Build the agent images, understand how each agent container is locked down, and manage SI Fabrik's containers.
With the Docker provider, each agent runs in its own container from harness-agent:latest, with only its task's workspace mounted. SI Fabrik builds the image for you, starts and stops containers per attempt, and cleans up after itself.
Build the images#
- Start Docker
On Sandboxes, the Docker card shows the engine version and CPUs once it's running. Open Docker Desktop if it isn't.
- Build the agent image
On the Agent Image card, press Build Image (or Rebuild). The build runs
docker build -t harness-agent:latest .with live logs. View Dockerfile shows exactly what it builds. - Build the browser image (optional)
For projects with
browser: enabled, press Build next toharness-agent-browser:latest. It adds Chromium, the Playwright MCP server and CLI. If the agent image is missing, it's built first.
The agent image:
FROM node:22-bookworm-slim
RUN apt-get update && apt-get install -y --no-install-recommends \
git ca-certificates curl wget jq ripgrep fd-find python3 python3-pip python3-venv \
build-essential openssh-client less procps unzip gh \
&& rm -rf /var/lib/apt/lists/*
RUN npm install -g @anthropic-ai/claude-code @openai/codex && npm cache clean --force
ENV CLAUDE_CODE_DISABLE_AUTOUPDATER=1 \
DISABLE_AUTOUPDATER=1 \
IS_SANDBOX=1 \
HOME=/home/node
RUN mkdir -p /workspace /home/node/.claude && chown -R node:node /workspace /home/node
USER node
RUN git config --global --add safe.directory '*' && git config --global init.defaultBranch main
WORKDIR /workspace
CMD ["bash"]It runs as the non-root node user, which is what allows bypassPermissions inside the container. Rebuild it to pick up new versions of Claude Code and Codex.
Use your own image#
Set docker.image to an image built on top of harness-agent:latest with your toolchain (a database client, a specific JDK, Playwright browsers…). It must keep the node user and /workspace, and its tools must trust the egress proxy's certificate through the usual variables (SSL_CERT_FILE, NODE_EXTRA_CA_CERTS and the like). See The proxy's certificate.
docker:
enabled: true
image: your-org/agent-java:latestHow a container is locked down#
Every agent container gets:
| Protection | How |
|---|---|
| No Linux capabilities | --cap-drop ALL |
| No privilege escalation | --security-opt no-new-privileges |
| Process limit | --pids-limit 4096 |
| Memory limit | --memory from docker.memory, default 8g |
| CPU limit | --cpus from docker.cpus (optional) |
| Read-only root | --read-only, with tmpfs /tmp (2 GB) and $HOME (4 GB); /workspace is the mounted workspace. Turn off with sandbox.read_only_root: false, only where the sandbox floor is off. |
| Ownership (Linux) | The host user's UID and GID, so the server owns workspace files |
| Network | The task's own --internal network, with no route out and no address for the host; the egress proxy is the only way out. See Network policy. |
| Model credentials | Never in the container: it gets a placeholder, and the egress proxy's relay adds the real key |
| Other secrets | Passed by name (-e NAME), never on the command line |
Claude Code's non-essential traffic is turned off (CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC=1). Browser containers get a 1 GB /dev/shm.
Containers#
The Containers list shows the containers SI Fabrik started, with CPU and memory use, Logs, and a button to stop and remove each one. Turn on Show all to see every container on the engine. SI Fabrik labels its containers com.harness.managed=true, plus a per-instance label, by role:
| Role | Lifetime |
|---|---|
Agent (harness-<project>-<task>-<hash>) | One attempt |
hook | One hook run |
git | One branch save or import (offline) |
service | A linked project's app, for one attempt |
terminal | One terminal session |
Egress proxy (harness-egress-*) | While SI Fabrik runs |
The instance label is derived from SI Fabrik's data folder, so the Mac app, a test run and a harnessd on the same machine never touch each other's containers. The short hash in a container's name comes from the instance, project and task, so projects such as a.b and a-b never share a name, and a launch removes a stale container of the same name only if this SI Fabrik started it. Leftover terminal, service, hook and git containers and task networks from a crash are removed when SI Fabrik starts.
Settings#
| Where | What |
|---|---|
docker.image | The agent image |
docker.memory, docker.cpus | Limits |
docker.env | Host variables passed in by name. Model credentials are never passed, even if listed. |
docker.extra_args | Extra docker run arguments (only where the sandbox floor is off) |
docker.network | A Docker network to use instead of the egress proxy (Mac only, with the sandbox floor off). See A custom Docker network. |
| Settings → Credentials | The model credential the relay adds for containers |