Documentation
Sandbox
Running shell commands in a resource-capped container.
By default, a command the agent runs is a command on your machine, with your user and your environment. The sandbox changes that: shell calls execute inside a disposable container with capped resources and no network.
$ forge --sandbox docker "run the test suite and fix what fails"Two modes
- none
- The default. Commands run directly in the workspace, with your toolchain and your credentials.
- docker
- Each shell call runs in a container. Requires a working Docker daemon; Forge exits with code 2 if it cannot reach one.
Set it per run with --sandbox, per repository in forge.toml, or per shell with FORGE_SANDBOX. Only the shell tool is affected - file edits are governed by the workspace root, and reads never leave it.
Container defaults
- image
- python:3.12-slim - Override for a prepared toolchain.
- cpus
- 2.0 - CPU quota for the container.
- memory
- 2g - Hard memory cap.
- network
- disabled - --network=none unless enabled.
- pids
- 512 - Process-count ceiling.
- capabilities
- --cap-drop=ALL - Plus --security-opt=no-new-privileges.
The caps exist for a specific failure: a loop that runs a runaway build, exhausts memory, or forks until the machine stops responding. A container that hits a limit dies and returns an error the agent has to read, instead of taking your laptop with it.
Networking is off
Containers start with --network=none. Nothing the agent runs can reach the internet, your VPN, or a service on localhost.
This is the setting most likely to surprise you. A test suite that hits a live API fails in the sandbox, and dependency installs fail too - so prepare an image with your dependencies already in it, or enable networking and accept what that means.
Privileges are dropped
Containers run with --cap-drop=ALL and --security-opt=no-new-privileges, so a command cannot acquire capabilities it did not start with.
Choosing an image
The default image is python:3.12-slim, which is enough for a Python project and wrong for most others. Point it at an image that has your toolchain - ideally the one your CI already uses, so a passing run means the same thing in both places.
# forge.tomlsandbox = "docker" [sandbox_options]image = "node:22"memory = "4g"If the agent reports that a command is missing, the image is the first thing to check - the command exists on your machine and not in the container.
What the sandbox does not do
Worth being precise about, because a partial boundary described as a complete one is worse than no boundary at all.
- The workspace is still writable. That is the point - the agent has to be able to edit your code. The container bounds what a command can reach, not whether your files can change.
- It is Docker's isolation, not more. Forge inherits the container runtime's boundary and its weaknesses. A container escape is a container escape.
- Only shell calls are sandboxed. Filesystem and git tools run on the host, governed by the workspace root and the permission policy.
- The model call goes out regardless. Disabling container networking does not make the run offline; the agent still talks to your provider from the host.
When to turn it on
- Unattended runs, especially with
--yolo- this is the pairing that makes it sane. - Untrusted code: a dependency audit, a stranger's pull request, an unfamiliar repository.
- Any task where a wrong
rmwould ruin your afternoon. - CI, where the container is the environment anyway.
For everyday work in a repository you trust, none with the default approval mode is the pragmatic choice - you keep your toolchain, and destructive calls still stop for you.