freebuff-proxy is a local gateway that makes the AI coding models behind Codebuff/FreeBuff available to any tool that speaks the OpenAI API: OpenCode, pi, 9router, LiteLLM, or your own scripts.
Your coding tools expect an OpenAI-style endpoint (/v1/chat/completions). The upstream service is not OpenAI-shaped: it is a CLI coding agent with its own session protocol, and its free-tier access is tied to per-account tokens that carry individual daily quotas and can be rate-limited or banned. freebuff-proxy sits between the two and absorbs that friction:
- Translates: rewrites standard OpenAI requests into the upstream session protocol (CLI request envelope, model-bound agent runs, tool-schema normalization) and streams the SSE response back as OpenAI
chat.completion.chunkevents. - Pools: routes requests across multiple tokens (hot-session-first with round-robin start and failover), so a busy client or router rides out per-account quotas instead of failing.
- Stealths: makes egress look like a real browser (TLS fingerprints, header sanitization, request jitter) so upstream abuse detection is less likely to flag your account (see the ToS warning below).
⚠️ Terms-of-service risk. Using your FreeBuff token through this proxy conflicts with FreeBuff/Codebuff terms of service; upstream abuse detection can suspend or permanently ban accounts. UseSAFE_MODE=true, keep usage modest, and do not run unattended 24/7. See Getting Started.
- New here? Start here
- Requirements
- Features
- How It Works
- Key Concepts
- Quick Start
- Command-Line Interface
- Configuration Reference
- Deployment
- Guides
- Contributing & Security
- Contact & Support
- License
Freebuff-proxy makes the free AI models behind the FreeBuff/Codebuff CLI available to any OpenAI-compatible tool (OpenCode, pi, 9router, LiteLLM). If you are new:
- Get a FreeBuff account + token. You need a Codebuff/FreeBuff account; the token (
cb_...) is what the proxy uses upstream. Get one with the official CLI orscripts/gen-token.*. See Obtain an Auth Token. - Install the proxy. One command, no Go or Docker required. See Quick Start.
- Connect your AI tool. Point OpenCode, pi, 9router, or LiteLLM at
http://127.0.0.1:3457/v1. See Client Integration.
For a guided walkthrough, read Getting Started (5 minutes).
| Requirement | Details |
|---|---|
| A FreeBuff/Codebuff account | Free account at codebuff.com / freebuff.com. The proxy relays your account's token; each account has its own daily session quota. |
A token (cb_...) |
From the official CLI login or scripts/gen-token.*. See Obtain an Auth Token. |
| OS | Linux, macOS, or Windows (amd64/arm64). Prebuilt release binaries; no Go toolchain needed. |
| Docker | Optional: only for the container deployment path (docker compose up -d --build). |
| Network | Outbound HTTPS to codebuff.com (configurable via UPSTREAM_BASE_URL); the proxy listens on loopback 127.0.0.1:3457 by default. |
| Go 1.26+ | Only if building from source. |
- OpenAI-Compatible API:
POST /v1/chat/completions(stream + non-stream),GET /v1/models,GET /healthz, PrometheusGET /metrics, and hot config reload viaPOST /admin/reload. - Admin Dashboard: embedded single-binary web UI at
http://<host>:3457/admin: live overview with a one-click smoke test (a real chat through the pool), runtime token management (add/remove/test on the live pool, persisted to.env, no restart), a pooled↔bridge mode switch, a three-step setup wizard with full diagnostics, a.envconfig editor with validation and hot-reload, a log viewer, and metrics sparklines. Login viaADMIN_TOKEN; htmx-driven, zero build step. - Dynamic Reasoning Effort: OpenAI
reasoning_effort(low/medium/high/max) and Codex/Anthropicreasoning.effortare normalized and mapped to upstream reasoning engines. - Session & Run Lifecycle: Upstream session handshakes, model-lock recovery (
DELETE→ re-POST), grace draining, and idle-run finishing, all automatic. - Token Pooling & Bridge Mode: Hot-session-first pooling with round-robin start and failover across
AUTH_TOKENS, or zero-storage relay when clients bring their own token. See Key Concepts. - Token Auto-Discovery: With empty
AUTH_TOKENS, credentials are read from the official CLI login files (~/.config/manicode/credentials.json,~/.config/codebuff/credentials.json). Disable withAUTO_DISCOVER_TOKEN=false. - TLS Stealth & Egress Proxies:
HTTP_PROXY/SOCKS5_PROXY, per-token SOCKS5 routing (SOCKS5_PROXIES, bound by token index), and browser TLS fingerprinting via uTLS (Chrome, Firefox, Safari, Edge). - Subagent-Ready Concurrency: Single-flight session refresh prevents race conditions during high-volume tool-calling loops.
- Safe Mode: On by default: anti-ban presets (TLS stealth, header sanitization, jitter, idle rotation).
- Operational Tooling:
-doctordiagnostics with a real session-handshake validity probe per token,-test-token(exit 0/1 for installers and scripts),-setupinteractive client configuration, and a SHA-256-verified-updateself-updater. - Quota Transparency: Live per-model quota (from the upstream
rateLimitsByModeladmission payload) is surfaced inGET /healthz(per-tokenquotamap) andGET /metrics(freebuff_proxy_quota_recent/freebuff_proxy_quota_limitgauges).
One chat request, end to end:
- Your tool calls the proxy. It POSTs a standard OpenAI request to
http://127.0.0.1:3457/v1/chat/completions, same shape it would send to any OpenAI-compatible endpoint. - A token is chosen. The proxy prefers the token that already holds a live session (hot-session-first), starting from a round-robin index and skipping tokens in cooldown or locked by a rate limit; in bridge mode it uses the token your client sent in its
Authorizationheader. - The request is translated. The model id is resolved through the catalog to the upstream agent that runs it, the message list is sanitized and re-wrapped in the CLI request envelope, and OpenAI extras (
reasoning_effort, tool schemas, etc.) are mapped to what upstream expects. - It goes out stealthily. The upstream call uses a browser-like TLS handshake and sanitized headers, through
HTTP_PROXY/SOCKS5_PROXYif configured. - The stream comes back translated. The upstream SSE stream is converted into OpenAI
chat.completion.chunkevents and relayed to your client in real time. - State is cleaned up. When the request finishes, the run is drained; once a run or token ages out (rotation interval, idle timeout), it is rotated or finished so the next request starts clean. A token that hit a quota limit (
429) is locked locally until its reset time. The proxy answers429+Retry-Afteritself, with no traffic sent upstream.
The translation layer reimplements the official CLI's wire protocol and session lifecycle, sourced from the open-source Freebuff client (Apache-2.0). It changes when the upstream changes. The translation lives in internal/convert, internal/upstream, internal/stealth, and internal/registry.
graph TD
Client[AI Client / Router<br/>OpenCode · pi · 9router · LiteLLM] -->|POST /v1/chat/completions| Proxy[freebuff-proxy<br/>localhost:3457]
Proxy -->|1. Session & Run Lifecycle| Pool[Token Pool & Session Cache]
Proxy -->|2. Inject Envelope + Stealth| Upstream[Upstream Backend API]
Upstream -->|3. SSE Stream| Proxy
Proxy -->|4. OpenAI SSE Chunks| Client
Client -.->|GET /metrics · GET /healthz · POST /admin/reload| Proxy
| Concept | What it means |
|---|---|
| Token | One FreeBuff/Codebuff account credential (cb_...). Each token has its own daily quota and can be rate-limited or banned independently. |
| Session | Per-token upstream admission state (handshake, model locks). The proxy maintains and reuses it so every request does not pay the handshake cost. |
| Run | One upstream agent execution for a model, shared across many requests. Runs start on first use, live for ROTATION_INTERVAL (default 6h), then are rotated (fresh start, old one drained/finished) so no run accumulates suspiciously long-lived activity. Idle tokens get their runs finished too. |
| Model | A catalog entry addressed as provider/model (e.g. deepseek/deepseek-v4-flash). The registry serves /v1/models and maps each model to the upstream agent that runs it. |
| Pooled mode | You configure several tokens in AUTH_TOKENS. Requests stick to the token with a live session and fail over only when it is rate-limited or errors: a reactive drain, not aggressive rotation. Best for one user with several accounts who wants maximum uptime and quota headroom. |
| Bridge mode | You configure no tokens. Each client sends its own token as Authorization: Bearer <token>, and the proxy relays with it, caching per-client state (LRU, max 32). Best for a shared router (e.g. 9router) serving many users who each bring their own account. |
| Safe mode | Default-on anti-ban presets: TLS stealth, proxy-header sanitization, request jitter, and idle rotation. See Safe Mode. |
| Quota lock | When a token hits its daily limit, the proxy parses the upstream 429 reset timestamp and refuses local requests for that token until reset, fast (<1ms), silent, and spam-free. |
One-command installer (Linux/macOS):
curl -sSL https://raw.githubusercontent.com/trefeon/freebuff-proxy/main/scripts/install-freebuff-proxy.sh | bashWindows (PowerShell):
irm https://raw.githubusercontent.com/trefeon/freebuff-proxy/main/scripts/install-freebuff-proxy.ps1 | iexThe bash installer prompts for an install method (easy, manual binary, Docker Compose, bridge mode); both installers mint/read your token and write .env.
Alternatively, run with Docker Compose:
cp .env.example .env # then set AUTH_TOKENS
docker compose up -d --buildOr download a release binary from Releases (Linux/macOS/Windows × amd64/arm64) and run ./freebuff-proxy.
Generate one headlessly (opens a browser OAuth login, prints the token to the terminal without saving):
Windows (PowerShell):
.\scripts\gen-token.ps1 -ToClipboardLinux / macOS (bash):
./scripts/gen-token.sh --clipboardgen-token.* are aliases for gen-freebuff-token.*, which also supports --save (store in the CLI credentials file), --append (add to .env AUTH_TOKENS), and --env <path>.
Alternatively, log in with the official CLI (npm i -g freebuff && freebuff): the proxy auto-discovers the token from its credentials file on startup.
Copy the example and set your token:
cp .env.example .env
# AUTH_TOKENS=cb_xxx ← paste your token (comma-separate for pooling)
# SAFE_MODE=true ← default (set false to disable)Leave AUTH_TOKENS= empty for bridge mode (clients bring their own tokens). Not sure which to pick? One user with a few accounts → pooled mode; a shared router serving many users → bridge mode. See Key Concepts. config.example.json shows the equivalent JSON config file, loaded with -config; see the Configuration Reference for every key.
./freebuff-proxy # or: docker compose up -dCheck health and run diagnostics:
curl http://127.0.0.1:3457/healthz
./freebuff-proxy -doctor # config, port, DNS/TLS, registry + per-token session probes
./freebuff-proxy -test-token # real session handshake on the first token; exit 0/1| Flag | Description |
|---|---|
| (none) | Run the proxy |
-config <path> |
Load an optional JSON config file (keys mirror env names) |
-v |
Verbose (debug) logging |
-version |
Print version and exit |
-doctor |
Run configuration and environment diagnostics: config, port, DNS/TLS reachability, model registry, and a real session-handshake validity probe per token |
-test-token |
Probe the first configured token with a real upstream session handshake; prints token OK and exits 0, or exits 1 (for installers/scripts) |
-update |
Self-update from the latest GitHub release (SHA-256 verified against checksums.txt) |
-setup |
Interactive client setup (detects installed clients) |
-yes |
Auto-confirm -setup prompts |
All keys can be set via environment variables or the JSON config file passed to -config (AUTO_DISCOVER_TOKEN is environment-only); a local .env file (if present) is also read, and for the keys it covers it behaves like the environment. Precedence, lowest to highest: built-in defaults < JSON -config < ./.env < environment. List values (AUTH_TOKENS, API_KEYS, SOCKS5_PROXIES) are comma-separated in env and arrays in JSON.
| Environment Variable | Default | Description |
|---|---|---|
LISTEN_ADDR |
127.0.0.1:3457 |
Host and port to bind (loopback; containers set :3457) |
UPSTREAM_BASE_URL |
https://codebuff.com |
Upstream API endpoint (normalized to www.codebuff.com) |
AUTH_TOKENS |
"" |
Comma-separated upstream tokens (empty = bridge mode) |
AUTO_DISCOVER_TOKEN |
true |
When AUTH_TOKENS is empty, read credentials from the official CLI login files (false disables) |
API_KEYS |
"" |
Comma-separated client keys required for /v1/* (empty = open; ignored in bridge mode) |
ADMIN_TOKEN |
"" |
Bearer token that POST /admin/reload requires when set (empty = unauthenticated in default deployments; a startup warning is logged). Also the login password for the admin dashboard: the same value unlocks the login page |
ROTATION_INTERVAL |
6h |
Agent-run rotation interval |
REQUEST_TIMEOUT |
15m |
Upstream request timeout |
SESSION_CALL_TIMEOUT |
30s |
Session call timeout |
REGISTRY_REFRESH |
6h |
Model catalog refresh interval |
COST_MODE |
free |
free (free-tier) or paid billing mode |
TLS_FINGERPRINT |
auto |
auto, chrome120, chrome126, safari17, safari18, firefox120, firefox128, edge126, random |
HTTP_PROXY |
"" |
Outbound HTTP proxy for upstream requests |
SOCKS5_PROXY |
"" |
Outbound SOCKS5 proxy for upstream requests |
SOCKS5_PROXIES |
"" |
Per-token SOCKS5 proxies (comma-separated) |
PROXY_ROTATION |
per-token |
SOCKS5 binding mode: only per-token (bind by token index) is implemented; round-robin/random are accepted but currently inert |
DEBUG_DUMP |
false |
Persist redacted traffic dumps to ./dump/ (mode 0600) |
LOG_FILE |
"" |
Append log lines to a file (e.g. ./logs/proxy.log) |
LOG_LEVEL |
info |
debug, info, warn, error |
MAX_MESSAGES_PER_DAY |
0 |
Per-token daily cap on successful chats (0 = unlimited, default; the upstream 429 lock is the real enforcement) |
IDLE_ROTATION_TIMEOUT |
0 |
Finish runs after this idle period (0 = disabled; SAFE_MODE sets 30m when unset) |
SAFE_MODE |
true |
Apply anti-ban presets (see below; set false to disable) |
REQUEST_JITTER |
0s |
Random delay range [0, REQUEST_JITTER) before upstream calls (SAFE_MODE sets 2s when unset) |
CLI_VERSION |
0.10.7 |
Upstream CLI version string used in the request envelope |
MODEL_ALIASES |
"" |
Map aliases to real model IDs, e.g. gpt-4o:deepseek/deepseek-v4-flash |
TRANSIENT_RETRIES |
1 |
Max additional attempts after a transient transport failure; 0 disables |
SAFE_MODE=true is the default for all setups (set SAFE_MODE=false to
opt out). It enables essential anti-ban protections and presets:
- JA3 TLS Stealth: Mimics real browser handshakes (Chrome 120/126, Safari 17/18, Firefox 120/128, Edge 126) via
uTLSto prevent WAF / CDN bot detection. - Proxy Header Sanitization: Strips 25 proxy-identifying headers (
X-Forwarded-For,Via,CF-Connecting-IP, etc.). - Request Jitter: Injects randomized 0–2s delay jitter to break robotic, machine-like cadence.
- Idle Rotation: Finishes runs after 30 minutes of inactivity.
- Daily Cap (optional):
MAX_MESSAGES_PER_DAYdefaults to0(unlimited). The upstream429lock is the real enforcement; see below.
- Use one key until it is rate-limited. The pool prefers the token that already holds a live session (hot-session-first) and only fails over when a token hits its quota or errors. It does not aggressively round-robin healthy keys. Letting one account run until its daily quota is natural usage; rotating many healthy keys in rapid succession looks like account farming and can trigger upstream ban detection.
- For ~24h of continuous coding, budget 4–5 keys. Each FreeBuff account has a daily
session quota (≈6 sessions on the limited tier, ≈5 premium sessions/day). One key ≈ one
day of moderate use. Configure
AUTH_TOKENSwith as many keys as you need and let the pool drain them one at a time. - Register accounts with real email addresses (e.g. Gmail). Disposable / temp-mail registrations are flagged as not-legitimate users and are more likely to be banned.
Why MAX_MESSAGES_PER_DAY Defaults to 0 (Unlimited):
- Unlimited is the default: no local cap throttles your free-tier allowance.
The proxy never spams upstream: when an account reaches its daily quota, the
upstream
429lock kicks in (below), so an unlimited local cap is safe. - Zero-Spam Guarantee: When an account reaches its daily quota or upstream capacity limit, the upstream returns a
429with a Pacific midnight reset timestamp (resetAt: 07:00:00Z). - The proxy parses this timestamp and locks the token locally in memory.
- Any subsequent request for that token returns
429locally in<1mswithout sending any network traffic upstream. - Upstream routers (e.g. 9router) receive standard
429+Retry-Afterheaders and automatically rotate to your next available account without failing user prompts.
| Endpoint | Auth | Description |
|---|---|---|
POST /v1/chat/completions |
API_KEYS (when set) |
OpenAI-compatible chat, streaming and non-streaming |
GET /v1/models |
API_KEYS (when set) |
Model catalog from the registry (fallback at boot + live refresh) |
GET /healthz |
none | JSON: status, uptime_seconds, models, per-token snapshot (incl. per-model quota map when the last admission carried it), bridge_tokens |
GET /metrics |
none | Prometheus text format: uptime, model count, per-token 24h messages / requests / active runs / cooldown, per-model quota (freebuff_proxy_quota_recent / freebuff_proxy_quota_limit) |
POST /admin/reload |
ADMIN_TOKEN (when set) |
Hot-reload configuration from disk without restart |
GET /admin |
session cookie (login via ADMIN_TOKEN) |
Admin dashboard: overview, tokens, config, logs, metrics (see Admin Dashboard) |
GET/POST /admin/login |
none | Dashboard login: constant-time ADMIN_TOKEN check, per-IP rate limit, HttpOnly + SameSite=Strict session cookie |
POST /admin/config |
session cookie | Validate and persist the .env file, then hot-reload the config (rolls back on rejection) |
POST /admin/smoke |
session cookie (loopback when ADMIN_TOKEN unset) |
One real chat through the pool: reports model, token, latency, and a content preview (bridge mode needs a client token in the payload) |
POST /admin/diag |
session cookie (loopback when ADMIN_TOKEN unset) |
Dashboard diagnostics (same checks as -doctor): config state, DNS + TCP reachability, registry count, per-token validity probes |
POST /admin/mode |
session cookie (loopback when ADMIN_TOKEN unset) |
Runtime pooled↔bridge switch; {"mode":"bridge"} empties the pool and clears AUTH_TOKENS in .env |
POST /admin/tokens/... |
session cookie (loopback when ADMIN_TOKEN unset) |
Runtime pool management: /add, /remove (last token), /test-all, and per-token /test, /unlock, /finish, persisted to .env |
The proxy ships with an embedded web dashboard: same single binary, no extra process, no build step (htmx + Pico are vendored into the binary). Open http://127.0.0.1:3457/admin (or your LISTEN_ADDR).
- Login: enter your
ADMIN_TOKENon the login page. It is the same value as the bearer token forPOST /admin/reload. WithoutADMIN_TOKENthe dashboard is open (matching/admin/reload's legacy behavior; a startup warning is logged). But the sensitive routes require a loopback client in that mode: Config and Logs (secrets), the token actions, the smoke test, diagnostics, and the mode switch. So a remotely reachable proxy cannot leak or rewrite its.env, mutate the pool, or switch modes. Failed logins are rate-limited per IP (5 fails → 1 minute lockout), and the session cookie isHttpOnly+SameSite=Strict(+Securewhen the proxy listens beyond loopback). - Overview: live relay state (pooled/bridge mode, model count, uptime, safe mode) with per-token cards: session status, ban/429 risk level, usage vs
MAX_MESSAGES_PER_DAY, transient-retry counters, plus a smoke test that sends one real chat through the pool (status, latency, preview). Polls every 5s. - Tokens: per-token session detail + the live per-model session quota table (limit/recent/period/reset/entitlement) with usage bars and reset countdowns; per-token Unlock (clears cooldown/ban), Finish runs, and Test (real upstream session probe). The pool is runtime-mutable: an Add-token form, Remove last, Test all, and Switch to bridge mode take effect immediately and are persisted to
AUTH_TOKENSin.env, no restart. Polls every 30s. - Models: the live catalog with upstream agent mappings and
MODEL_ALIASES. - Traces: recent chat requests and their routing outcome (token, model, status, duration, error class), the observability view for ban-avoidance debugging. Polls every 3s.
- Setup: a three-step wizard: (1) add/remove/test tokens, (2) verify with a smoke test and Full diagnostics (
-doctor-style checks: config state, DNS + TCP reachability, registry count, per-token validity), (3) copy-paste client snippets generated from the effective config. - Config: edit the proxy's
.envfile in place. Save runs the same validation as startup (durations, URLs,Validate) and hot-reloads; invalid input is rejected with the file rolled back. The effective-value table shows secrets redacted to set/unset + counts. - Logs: the last 200 records from an in-memory ring (no log file or docker needed), level-colored, polling every 3s.
- Metrics: sampled counter trends as server-rendered sparklines; the full Prometheus exposition stays at
/metrics.
See Dashboard Guide for access, Docker caveats, and hardening.
- Docker:
docker-compose.yml+Dockerfile, runs as an unprivileged user, healthchecked on/healthz,LISTEN_ADDR=:3457inside the container. - Systemd:
scripts/freebuff-proxy.service(Linux). - macOS launchd:
scripts/com.freebuff-proxy.plist(macOS). - Docker + 9router helper:
scripts/setup-proxy-docker.sh.
- Getting Started: 5-minute setup walkthrough
- Client Integration: OpenCode, pi, 9router, LiteLLM, OpenAI SDKs
- 9router Integration: router dashboard setup in bridge mode
- Dashboard Guide: the admin web UI: access, pages, Docker caveats, hardening
- Contributing: filing issues, opening PRs, what to expect
- Security: supported versions and how to report a vulnerability
- Questions, bugs, feature requests: GitHub Issues
- Security reports: SECURITY.md
- Contributing: CONTRIBUTING.md