Fence
Fence wraps agents in Seatbelt (macOS) or bubblewrap (Linux), with filesystem rules, command denies, and a domain allowlist proxy. It does not inject credentials; that stays varlock’s job.
Install
Section titled “Install”brew tap fencesandbox/tapbrew install fencesandbox/tap/fenceOn Linux, also install bubblewrap and socat (for example sudo apt install bubblewrap socat).
Wire Fence through varlock
Section titled “Wire Fence through varlock”Fence’s own proxy enforces domain policy. Important detail from Fence’s upstream proxy docs: traffic that matches allowedDomains goes direct to the origin and bypasses upstreamProxy. Hosts that need varlock injection must therefore sit in the grey zone (not listed in allowedDomains), with defaultAction: "proxy" and upstreamProxy pointed at varlock.
- Start varlock on a fixed port, so
fence.jsoncan name the proxy address without per-session editing:
varlock proxy start --port 54321- Project
fence.json(extends thecodetemplate; keep package registries on the allowlist so they stay direct; leave model API hosts for varlock):
{ "$schema": "https://raw.githubusercontent.com/fencesandbox/fence/main/docs/schema/fence.schema.json", "extends": "code", "network": { "allowedDomains": [ "github.com", "*.npmjs.org", "registry.yarnpkg.com", "registry.npmjs.org" ], "deniedDomains": ["169.254.169.254"], "defaultAction": "proxy", "upstreamProxy": "http://127.0.0.1:54321" }}--port keeps that address stable across sessions, so fence.json can be committed as-is (match upstreamProxy to the port you chose). Only http:// upstream URLs are supported by Fence today.
- Export placeholders + CA trust, then launch:
eval "$(varlock proxy env)"fence --settings ./fence.json -- claudeThe agent talks to Fence’s local proxy first. Grey-zone hosts (including api.anthropic.com when it is not in allowedDomains) forward to varlock, which injects secrets under your @proxy rules. Keep @proxyConfig={egress="strict"} so unmatched grey-zone destinations die at varlock instead of leaking outbound.