Sandboxes

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#

  1. Start Docker

    On Sandboxes, the Docker card shows the engine version and CPUs once it's running. Open Docker Desktop if it isn't.

  2. 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.

  3. Build the browser image (optional)

    For projects with browser: enabled, press Build next to harness-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:

Dockerfile (generated by SI Fabrik)
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.

YAML
docker:
  enabled: true
  image: your-org/agent-java:latest

How a container is locked down#

Every agent container gets:

ProtectionHow
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
NetworkThe 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 credentialsNever in the container: it gets a placeholder, and the egress proxy's relay adds the real key
Other secretsPassed 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:

RoleLifetime
Agent (harness-<project>-<task>-<hash>)One attempt
hookOne hook run
gitOne branch save or import (offline)
serviceA linked project's app, for one attempt
terminalOne 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#

WhereWhat
docker.imageThe agent image
docker.memory, docker.cpusLimits
docker.envHost variables passed in by name. Model credentials are never passed, even if listed.
docker.extra_argsExtra docker run arguments (only where the sandbox floor is off)
docker.networkA Docker network to use instead of the egress proxy (Mac only, with the sandbox floor off). See A custom Docker network.
Settings → CredentialsThe model credential the relay adds for containers

See also#