sandboxhillclimb

Sandbox

What agents and solutions can write, read and reach on your machine, and how to see it for yourself.

hillclimb starts two kinds of process that run code nobody has read. The agents work with their permission prompts off, and the verifier runs the solution.py an agent wrote. Both run on your machine, as you.

So both run inside a sandbox. It is on by default, it is the operating system's own, and it needs no container.

See it for yourself

hillclimb sandbox check runs a script that behaves like a hostile solution, inside the same sandbox a search uses, and lists what happened to every attempt:

hillclimb sandbox check
$ hillclimb sandbox check A hostile script, run inside the sandbox (sandbox-exec)     files✓   write to its own candidate folder                     allowed✓   write to your home folder                             blocked✓   write to the hillclimb dir                            blocked    secrets✓   read the search's journal (it holds holdout scores)   blocked✓   read ~/.ssh                                           blocked✓   read Claude Code's login and history (~/.claude)      blocked    network✓   connect to the internet (1.1.1.1:443)                 blocked✓   look up a name (example.com)                          blocked    processes✓   signal a process outside the sandbox                  blocked    agent without internet✓   reach a host that is not allowed (example.org)        blocked✓   connect past the proxy                                blocked✓   reach an allowed host (example.com)                   allowed   The sandbox holds: 10 attempts blocked, and its own folder stays writable.

It exits with code 1 if one attempt got through. Whatever the script managed to write outside its folder is removed again. hillclimb connect shows in one line whether the sandbox starts on your machine.

What a sandboxed process can do

allowedblocked
writeits candidate's folder, the temp dirs, the caches of huggingface, torch and matplotlibeverything else: your home folder, your repositories, the search's journal and best/, the Python environments solutions run in
readmost of the disk~/.ssh, ~/.aws, ~/.gnupg, cloud and GitHub logins, browser profiles, shell history, .env files, the other agents' logins, the search's journal and its holdout runs, the sockets of Docker and other container runtimes
network, agentseverything; with allow_internet_for_agents: false only their model providerthe rest
network, verifiernothing; with the problem's allow_internet_during_solution: true everythingthe rest, name lookups included
processesits own childrensignalling anything outside

An agent also writes to its own state: ~/.claude and ~/.claude.json for Claude Code, an isolated home and its session folder for pi.

How it is enforced

The engine stays outside. It is the only process that writes the journal and best/. Every agent call and every verifier run is started inside a sandbox of its own, and everything that process starts stays inside with it:

your machine
│
├── engine (hillclimb run)                 outside: writes the journal and best/
│   └── proxy                              the one way out for agents without internet
│
├── sandbox ── agent (claude-code, pi)     writes its candidate's folder
│               └── every tool and script it starts
│
└── sandbox ── verifier.sh                 writes its candidate's folder, no network
                └── solution.py

hillclimb does not implement the confinement. It writes down the rules and hands them to the mechanism the operating system already has:

OSwhat enforces itinstall
macOSsandbox-exec (Seatbelt), the mechanism Chrome and Claude Code usenothing, it is part of macOS
Linuxbubblewrap, the mechanism Flatpak usessudo apt install bubblewrap (dnf, pacman alike)
Windowsnone existshillclimb runs unsandboxed and says so at every start

The rules are readable. On macOS they are one Seatbelt profile per process, on Linux one list of bubblewrap arguments, both written by harness/sandbox.py.

Per agent

agenthow it is confined
claude-codethe whole process runs inside the sandbox
pithe whole process runs inside the sandbox
codexby its own sandbox (--sandbox workspace-write): writes stay in the candidate's folder and its commands have no network. macOS allows no sandbox inside a sandbox, so hillclimb does not put a second one round it, and codex can still read files the table above lists as blocked
dummyruns no model and no tools

Agents without internet

By default an agent may use the internet while it works. To take it away:

hillclimb.yaml
allow_internet_for_agents: false

The agents then reach their model provider and nothing else. Everything they and their tools send goes through a small proxy inside the engine, which lets HTTPS through to the provider's hosts and refuses the rest. The engine's log names every host it refused. Claude Code's web search, web fetch and MCP servers are off, codex's web search is off, and the draft prompt no longer asks for research on the web.

This needs the sandbox. With sandbox: off, or on Windows, a search with claude-code or pi does not start.

When it does not start

A search does not start when the sandbox is on and cannot be started. The message says why:

what it sayswhat to do
bubblewrap is not installedinstall it with your package manager
it does not start, on Ubuntu 24.04 or laterUbuntu keeps the kernel feature bubblewrap uses behind AppArmor: sudo sysctl -w kernel.apparmor_restrict_unprivileged_userns=0
it does not start, inside a containerthe container has to allow user namespaces. If it does not, the container is the sandbox: set sandbox: off
it does not start, on macOShillclimb was started inside another sandbox, a coding agent's for example. Run it from a plain terminal

Settings

hillclimb.yaml
sandbox: off              # run everything unsandboxed
hillclimb.yaml
sandbox:                  # or adjust it
  write: [scratch]        # more writable paths, relative to the hillclimb dir
  deny_read: [~/private]  # more unreadable paths
  allow_hosts: [bedrock-runtime.eu-north-1.amazonaws.com]   # more hosts for agents without internet
  local_ports: [8000]     # localhost ports left open when the network is off

HILLCLIMB_SANDBOX=off in the environment switches it off for one command.

What it does not protect

It is a sandbox, not a virtual machine

It stops writes outside the candidate's folder, reads of your keys and traffic to hosts you did not allow. It does not protect against a flaw in the operating system's kernel.

These stay open:

  • An agent can read its own login, because it needs it.
  • A sandboxed process can still read most of your files. Add what is private to sandbox.deny_read.
  • An agent without internet still talks to its model provider, so what it can read can reach that provider.
  • codex is confined by its own sandbox, which does not hide your keys from it.
  • On Windows nothing is confined.