Everything you need to install, configure, deploy, and troubleshoot ringfence.
60-second install on macOS or Linux:
curl -sSL https://ringfence.dev/install.sh | bash
The default install is zero-prompt and sets up the always-on configuration:
fence + fence-proxy to /usr/local/bin (sudo) or ~/.local/bin (no-sudo fallback)~/.config/ringfence/env.sh and adds a marker-bracketed source line to your shell rc (zsh/bash)Because shells inherit env vars at launch time, the terminal you ran the installer from doesn't yet see the new variables. Open a new tab — or paste:
source ~/.config/ringfence/env.sh
fence doctor
Every line should be ✓. If any line is ⚠ or ✗, the message tells you the exact fix.
Then just use claude / codex / aider as you normally would — they're now proxied through fence with budget enforcement.
ringfence is an HTTP proxy that intercepts API-key-authenticated calls to known LLM endpoints (Anthropic, OpenAI, Google Gemini). It cannot intercept OAuth-flow tools or proprietary backends — the auth tokens for those flows are scoped to the provider's own audience and don't accept a base URL override. Pick the right auth mode for the tools you care about and ringfence captures the spend; mismatched mode and your traffic bypasses the proxy silently.
ANTHROPIC_API_KEY by default. Honours ANTHROPIC_BASE_URL. Works out of the box after fence enable-system-wide.OPENAI_API_KEY=sk-… from platform.openai.com. Honours OPENAI_BASE_URL.http://localhost:9000. Cursor's default routing (its own backend) is not captured.GEMINI_API_KEY from Google AI Studio (paid tier). The base-URL env var name varies by gemini-cli version; fence doctor surfaces the right one.chatgpt.com/backend-api/… (not api.openai.com). Symptom if you leave OPENAI_BASE_URL pointed at fence: stream disconnected before completion errors. Either get an OpenAI API key, or unset OPENAI_BASE_URL for that shell.GEMINI_API_KEY mode if you need budget enforcement.*-aiplatform.googleapis.com) — different URL family + gcloud token auth. Not on fence-proxy's route table today; raise an issue if you need it.If your tool reads ANTHROPIC_API_KEY or OPENAI_API_KEY or GEMINI_API_KEY from your shell, fence captures it. If it logs you in via a browser, it doesn't.
Run fence doctor to see which AI tools are detected on your machine and which auth mode each is in — it flags the unsupported combinations explicitly.
fence-proxy is a streaming HTTP proxy on localhost:9000. It accepts requests for Anthropic, OpenAI, and Google Gemini on a single port, dispatches by URL path, forwards to the real upstream, and records token-count metadata on the response.
Each request is checked against your daily and monthly budget before forwarding. When a budget is breached, the proxy returns 429 Too Many Requests with a clear Retry-After header — your AI tool stops mid-conversation, you don't get a surprise bill.
Prompts and completions never leave your machine. Only metadata (timestamp, model, token counts, cost in USD, tags) is sent to the cloud control plane — and only if you've enrolled (run fence login). Solo mode is fully local; no phone-home of any kind.
Set these four environment variables (the install script does this for you via ~/.config/ringfence/env.sh):
export ANTHROPIC_BASE_URL=http://localhost:9000 export OPENAI_BASE_URL=http://localhost:9000 export OPENAI_API_BASE=http://localhost:9000 export GENAI_API_BASE=http://localhost:9000
Tools that read these env vars route through fence; tools that authenticate via OAuth or proprietary backends bypass it. See Coverage for the per-tool matrix and the auth-mode caveats.
ringfence is your AI cost firewall. When fence is running, AI tools route through it. When fence is not running, AI tools refuse to connect — by design. A budget firewall whose failure mode is silent direct-to-API is worse than no firewall at all (no enforcement + the user thinks it's enforcing). Loud failure is the right signal: fence up is right there.
The full command list. Run fence with no arguments for the same list inline.
fence init [--cloud-url URL]Write ~/.ringfence/config.toml. Idempotent.fence up [-d|--detach]Start proxy + dashboard. -d for background.fence downStop proxy + dashboard.fence restartStop, then start detached.fence psShow running components, ports, status, version.fence logs [-f] [proxy|dashboard|all]Show logs. -f to follow.fence daemonForeground supervisor (used by systemd / launchd).fence statusPrint current budget + recent activity.fence doctorSelf-check: ports, env vars, shell init, cloud reachability.fence version [--json]Print version. --json for machine-readable.fence budget set --daily $ --monthly $Set local budget caps.fence tag [<name>|clear]Per-project tag stamped on every event.fence providersList providers + their base URLs.fence enable-system-wide / disable-system-wideToggle launchctl/environment.d env vars.fence login [--token <...>]Enrol this machine with a cloud team.fence logoutRemove the agent token; back to solo mode.fence service installRegister launchd / systemd unit. Auto-starts on login.fence service uninstallRemove the unit.fence reset [--yes] [--keep-config]Wipe local data. Stops fence first.fence uninstall [--purge]Undo install.sh. --purge also wipes ~/.ringfence/.Located at ~/.ringfence/config.toml, written by fence init. Idempotent — re-running won't clobber an edited file.
mode = "solo" # "solo" (offline) or "team" (cloud) proxy_port = 9000 dashboard_port = 9001 cloud_url = "https://ringfence.dev" # upstream = "https://api.anthropic.com" # optional Anthropic-only egress override
Read by both fence binaries at runtime. The install script writes these into ~/.config/ringfence/env.sh automatically.
ANTHROPIC_BASE_URLWhere Claude Code / Aider / Cursor send requests. Set to http://localhost:9000.OPENAI_BASE_URLWhere Codex CLI / OpenAI SDKs send requests. Same value.OPENAI_API_BASELegacy alias for OPENAI_BASE_URL. Set both for max compatibility.GENAI_API_BASEWhere @google/genai SDK sends requests.FENCE_LIVE_PORTOverride the dashboard port (default 9001).RINGFENCE_HOMEOverride the data dir (default ~/.ringfence).For CI runners, Docker images, remote servers, and agentic-system runtimes — the install path that doesn't touch shell rc, doesn't register a service unit, and doesn't auto-start fence.
RINGFENCE_NO_SHELL_INIT=1 \
RINGFENCE_NO_SERVICE=1 \
RINGFENCE_NO_START=1 \
curl -sSL https://ringfence.dev/install.sh | bashThen in your service unit or Dockerfile, set the four base URLs explicitly and start fence-proxy directly:
[Service] Environment="ANTHROPIC_BASE_URL=http://localhost:9000" Environment="OPENAI_BASE_URL=http://localhost:9000" Environment="OPENAI_API_BASE=http://localhost:9000" Environment="GENAI_API_BASE=http://localhost:9000" ExecStart=/usr/local/bin/fence-proxy Restart=on-failure User=ringfence
FROM debian:trixie-slim
RUN curl -fsSL https://ringfence.dev/install.sh \
| RINGFENCE_NO_SHELL_INIT=1 RINGFENCE_NO_SERVICE=1 RINGFENCE_NO_START=1 \
bash
ENV ANTHROPIC_BASE_URL=http://localhost:9000 \
OPENAI_BASE_URL=http://localhost:9000 \
OPENAI_API_BASE=http://localhost:9000 \
GENAI_API_BASE=http://localhost:9000
EXPOSE 9000 9001
CMD ["fence", "daemon"]Each environment variable above has a CLI flag equivalent on install.sh:
--no-shell-init — skip shell rc append--no-service — skip service unit registration--no-start — skip the post-install fence up -d--prefix=DIR — override the install location--version=X.Y.Z — pin to a specific versionFirst step in every case: fence doctor. It surfaces the half-dozen things that go wrong in practice, with the fix on the same line.
Almost always: the shell you ran claude from doesn't have ANTHROPIC_BASE_URL set. Check with:
echo $ANTHROPIC_BASE_URL # expected: http://localhost:9000
Empty? Source the env file in this shell:
source ~/.config/ringfence/env.sh
Or open a new terminal tab — the source line in your shell rc fires automatically on shell startup.
Run fence login --token <token> again. The diagnostic line right above the failure message tells you why:
<id>.<secret>::<hmac> string.cloud_url in ~/.ringfence/config.toml resolves.Identify the offender:
lsof -i :9000 lsof -i :9001
If it's a stale fence from a previous run, fence down cleans up. If a service unit is bound, fence service uninstall.
Apple's TCC silently kills binaries with quarantine xattrs and broken codesignatures. The install script should handle this automatically (see adhoc_sign_macos). If it persisted:
xattr -dr com.apple.quarantine /usr/local/bin/fence codesign -s - /usr/local/bin/fence
If codesign or xattr is missing, install Xcode Command Line Tools: xcode-select --install.
One command undoes everything install.sh added:
fence uninstall
It stops fence, removes the launchd / systemd service unit, removes the marker-bracketed source line from your shell rc (with a .ringfence.bak backup), and removes ~/.config/ringfence/env.sh.
What it doesn't remove (preserves your data + the binaries):
rm--purge to also wipe theseFull clean revert:
fence uninstall --purge sudo rm /usr/local/bin/fence /usr/local/bin/fence-proxy # or ~/.local/bin if user-installed
Got stuck? Email us at hello@ringfence.dev.
These docs cover ringfence v1. The CLI's --help stays in sync with each release; if you find a discrepancy, the CLI is the source of truth.