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.
⚠️ Honest expectations. FreeBuff's servers are strict, and this proxy reduces ban risk; it does not eliminate it. Nothing here can guarantee your account is never flagged or banned. Upstream detection is documented in the open-source FreeBuff client: per-request IP scoring (VPN/proxy/Tor/hosting egress → limited tier or terminalcountry_blocked), per-account trust levels with sticky caps (third-party-client flag, shared signup network, shared mailbox), daily spend ceilings ($0.50/day for restricted cohorts), and mass sweeps against known farm shapes (6,699 of 7,129 disposable-email accounts were already banned when the blocklist was compiled). This project is a local adapter that exposes FreeBuff's models as an OpenAI-compatible API for other coding agents (OpenCode, pi, hermes, openclaw, or any client that supports a custom endpoint). Your auth tokens are handled automatically by the gateway, which reimplements the official CLI's wire protocol (~99% parity); it is not the official client, and upstream changes can break it until adapted. Keep usage modest and follow the hygiene rules below; further improvements to session handling and ban avoidance are planned.
- 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 (Cursor, VS Code Continue/Cline, OpenCode, pi, 9router, Chatbox, LibreChat).
If you are a beginner, you don't need to write code or compile anything:
- Download the pre-built Release: Go to Releases and download the ZIP for your OS (e.g.
freebuff-proxy_..._windows_amd64.zip). (Do not use the green "Code -> Download ZIP" button, which is raw source code). - Extract & Double-Click: Unzip the folder.
- Windows: Double-click
start-proxy.cmd. - Linux / macOS: Open terminal in the extracted folder and run
./start-proxy.sh.
- Windows: Double-click
- Log in: When prompted, press Enter to open your browser and sign in with your FreeBuff/GitHub account. Your token is saved automatically!
- Open Web Dashboard: Open http://localhost:3457/admin in your browser to view your live status, test chat, and manage tokens visually.
- Connect your tool: In Cursor, VS Code Continue/Cline, Chatbox, or OpenCode, set:
- Base URL:
http://localhost:3457/v1 - API Key:
not-needed - Model:
deepseek/deepseek-v4-flash(full-tier only; limited-tier accounts are coerced tomimo/mimo-v2.5) (See Client Integration Guide for 1-click config snippets).
- Base URL:
Before you start, the rules (what you should / shouldn't do):
| ✅ Do | ❌ Don't |
|---|---|
| Use one key until it is rate-limited; the pool drains it naturally | Don't rotate many healthy keys; it looks like account farming |
| Use a normal residential connection | Don't use a VPN / proxy / Tor (Cloudflare TCP-layer GeoIP + MaxMind/Spur ASN detection → restricted cohort or country_blocked) |
| Register with a real email (e.g. Gmail) | Don't use temp-mail (documented ban cohort: 6,699 of 7,129 accounts already banned) |
| Request only models your tier/region offers (default Flash) | Don't request out-of-region models: refused/downgraded and correlated with your IP's geo |
Read a 429 as quota, resets Pacific midnight |
Don't confuse it with a ban; only 403 banned/country_blocked is terminal |
| Expect reduced risk, not immunity | Don't run unattended 24/7 or expect zero ban risk |
| Keep the pool draining one key at a time | Don't hammer many tokens from one public IP (ip_capped) |
Access Tiers & Upstream Models. FreeBuff determines your access tier via Cloudflare TCP-layer GeoIP (not HTTP headers — spoofing is impossible). A residential IP in a Tier-1 country (US, UK, DE, JP, CA, etc.) gets accessTier: "full" with all premium models available (5 premium sessions/day base — 4 at the floor when trust levels are enforced). Non-Tier-1 country IPs get accessTier: "limited" where mimo/mimo-v2.5 (MiMo 2.5) is the sole active model.
📢 Official Freebuff Upstream Notice (vendor snapshot
89ce3f5· npm0.0.1612026-08-30): "Every model runs on your normal daily sessions — no per-model caps; your shared premium allowance still charges partial time, rounded up to a tenth. MiMo, DeepSeek V4 Flash and GLM 5.3 Flash are unmetered. —❤️ Freebuff Team" (Premium pool5/daypacific_dayAmerica/Los_Angeles; shared byGPT-5.6 LunaandSolar Pro 4.GLM 5.3 Flashis unmetered — no per-model cap.)
| Category | Model Name | Wire Model ID | Specs & Upstream Quota Policy |
|---|---|---|---|
| Premium | GPT-5.6 Luna | openai/gpt-5.6-luna |
Strong all-around, Reasoning: high, Images. Shares 5/day premium pool (PREMIUM 0/5). |
| Premium | Solar Pro 4 NEW |
upstage/solar-pro4 |
Limited-time trial, experimental, OpenRouter BYOK (Upstage), text-only, context 500_000. Shares 5/day premium pool. |
| Unlimited | GLM 5.3 Flash NEW |
z-ai/glm-5.3-flash |
Deep reasoning, Images. Unmetered — always available, no per-model cap (left the premium pool 2026-08-28; now the default pick, per vendor 0.0.161). |
| Unlimited | DeepSeek V4 Flash | deepseek/deepseek-v4-flash |
Smart & Fast, Reasoning: high. Unmetered — always available (peak pricing applies; off-peak-only serving window removed 2026-08-28). |
| Unlimited | MiMo 2.5 | mimo/mimo-v2.5 |
Balanced, Images. Unlimited across all tiers. |
| Referral | GLM 5.2 | z-ai/glm-5.2 |
Top open-source agentic model. Referral-gated (+1/day per referral), 1-hour sessions. |
| Disabled | MiniMax M3 | minimax/minimax-m3 |
Withdrawn upstream (2026-08-20). |
| Disabled | DeepSeek V4 Pro | deepseek/deepseek-v4-pro |
Withdrawn upstream (2026-08-26, cost). |
| Disabled | Ox Alpha | stealth/ox-alpha |
Withdrawn upstream (2026-08-27, free promotion ended). |
Full detail in Key Hygiene & Ban Avoidance.
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),POST /v1/responses,POST /v1/messages(Anthropic shape) +/v1/messages/count_tokens,POST /v1/embeddings(unsupported →400 unsupported_endpoint),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: a modern Svelte 5 + Tailwind CSS v4 single-page application built with self-hosted IBM Plex Sans & IBM Plex Mono typography and an "instrument panel" operational design. Features a live overview with 6 KPIs and token risk cards, runtime token pool & quota management with in-browser OAuth device login, served models catalog, hot-reloading.envConfiguration Studio, in-memory structured log viewer with level filtering, and universal 1-click client setup snippets. Zero external CDN or runtime Node.js dependency. - Dynamic Reasoning Effort: OpenAI
reasoning_effort(low/medium/high/max) and Codex/Anthropicreasoning.effortare normalized and mapped to upstream reasoning engines. - Honest Feature Translation: Every request param of the three surfaces is mapped to what the upstream chat endpoint accepts, or answered with an explicit
400when it cannot be honored (OpenAIn > 1,audio,web_search_options,moderation; Responsesprevious_response_id,conversation,background, built-inweb_search/file_search/code_interpreter/computer_usetools — only function tools translate; Anthropictop_kand Responsesinclude/truncation/service_tierare documented-ignored)./v1/messagesrequests that omitmax_tokens(spec-required) default to 8192. - Session & Run Lifecycle: Upstream session handshakes, model-lock recovery (
DELETE→ re-POST), grace draining, and idle-run finishing, all automatic. - Token Pooling & Hybrid/Bridge Mode: Hot-session-first pooling with round-robin start and failover across
AUTH_TOKENS, zero-storage relay when clients bring their own token, or both at once —AUTH_TOKENSplusBRIDGE_ENABLED(default) serves API-key clients from the pool and other credentials as bridge tokens on one instance. 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: browser TLS fingerprinting via uTLS (Chrome, Firefox, Safari, Edge) plus sanitized request headers so upstream traffic reads as a browser client.
- CLI Impersonation: egress presents as the official FreeBuff CLI —
Freebuff-CLI/1.0.0ads-API User-Agent with a Chrome/124 body UA,ai-sdk/openai-compatible/1.0.0/codebuffchat UA, Bun/1.3.14 on session/auth endpoints, and your real device timezone/locale. - 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 (config, port, DNS/TLS, registry; zero-cost per-token validity probes run by default),-test-token(zero-cost probe on the first token, prints live quota, 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 (or hybrid, for a credential that does not match
API_KEYS) it uses the token your client sent in itsAuthorizationheader. - 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.
- 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 backend/internal/convert, backend/internal/upstream, backend/internal/stealth, and backend/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, 72h idle eviction). Best for a shared router (e.g. 9router) serving many users who each bring their own account. |
| Hybrid mode | The default when AUTH_TOKENS is set. The pool and the bridge run side by side: a request whose credential matches an API_KEYS entry is served from the pool, any other credential is relayed upstream as the client's own bridge token, and a missing credential is rejected 401 when API_KEYS are configured (open pooled otherwise). Set BRIDGE_ENABLED=0 for a locked-down pooled-only instance. |
| 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. |
freebuff-proxy follows platform-standard paths, and it finds its configuration automatically — you never need to cd into a specific folder for the .env to resolve.
| Linux | macOS | Windows | |
|---|---|---|---|
| Binary | ~/.local/bin/freebuff-proxy |
/usr/local/bin/freebuff-proxy |
%LOCALAPPDATA%\Programs\freebuff-proxy\freebuff-proxy.exe |
Config (.env, mode 0600) |
~/.config/freebuff-proxy/.env |
~/Library/Application Support/freebuff-proxy/.env |
%APPDATA%\freebuff-proxy\.env |
Template (.env.example) |
~/.local/share/freebuff-proxy/.env.example |
/usr/local/share/freebuff-proxy/.env.example |
%LOCALAPPDATA%\Programs\freebuff-proxy\.env.example |
- The
.envfile holds your secrets (AUTH_TOKENS,ADMIN_TOKEN, …). It lives only in the platform config directory above (the installer creates it there,chmod 600on Linux/macOS) and is resolved automatically by the runtime. As a legacy convenience for power users and dev clones, a./.envin the working directory still wins when present. - The
.env.exampleis a template — a secrets-free starter shipped next to the install root. It seeds the real.envduring setup; it is never read as live config. - Overrides:
--prefix <dir>/--dir <dir>(bash) and-Dir <dir>(PowerShell) relocate the install root;--env-file <path>(bash) and-EnvFile <path>(PowerShell) point.envat a specific file.--dir <dir>(kept for backward compatibility) and a dev-clone checkout preserve the legacy ".envin the current directory" behavior — the platform directories above are the default.
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 in your platform config directory.
Alternatively, run with Docker Compose (a dev clone — the installers place .env for you):
cp .env.example .env # dev clone: seed the template next to the compose file, then set AUTH_TOKENS
git fetch --tags 2>/dev/null || true
VERSION=$(git describe --tags 2>/dev/null || echo dev) docker compose up -d --buildOr download a release binary from Releases (Linux/macOS/Windows × amd64/arm64), unzip it, right-click the extracted folder → Open in Terminal, and run ./start-proxy.sh (Windows: .\start-proxy.cmd; the .cmd wrappers bypass the PowerShell execution policy). start-proxy.* resolves .env from your platform config directory, so it works no matter which directory you launch it from. The bundled scripts also include a headless token generator (gen-token.sh / gen-token.cmd).
Generate one headlessly (opens a browser OAuth login). Run with no flags for an interactive menu; the recommended default (Enter) appends the token to .env, auto-creating it from .env.example if missing:
Windows (PowerShell / CMD):
.\scripts\gen-token.cmd # menu; Enter = append to .env (auto-create)Linux / macOS (bash):
./scripts/gen-token.sh # menu; Enter = append to .env (auto-create)gen-token.* also supports explicit modes that skip the menu: --clipboard / -ToClipboard, --save / -Save (store in the CLI credentials file), --append / -Append (add to .env AUTH_TOKENS), and --env <path> / -EnvFile <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.
The installers already wrote .env for you (in your platform config directory — see Where the files are installed). For a manual or dev-clone run, seed the template and set your token:
# defaults to the platform config dir; pass --env-file <path> to target a specific file
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). Set AUTH_TOKENS for pooled mode — and because bridge relay is on by default (BRIDGE_ENABLED), a token pool also accepts clients who bring their own tokens (hybrid mode); set BRIDGE_ENABLED=0 for pooled-only. Not sure which to pick? One user with a few accounts → pooled/hybrid; a shared router serving many users → bridge mode. See Key Concepts. config.example.json shows the common keys in JSON form, loaded with -config; the Configuration Reference below documents every key. Its cb_xxx/cb_yyy auth placeholders are deliberately rejected by validation — edit the file with real token values before passing -config.
./freebuff-proxy # or: docker compose up -dThe binary reads .env from your platform config directory automatically — run it from anywhere.
Check health and run diagnostics:
curl http://127.0.0.1:3457/healthz
./freebuff-proxy -doctor # config, port, DNS/TLS, registry, plus zero-cost per-token validity probes
./freebuff-proxy -test-token # zero-cost probe on the first token (no session claimed); prints live quota, 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, plus a zero-cost validity probe per token |
-test-token |
Probe the first configured token with a zero-cost upstream GET probe (no session claimed); prints token OK and live quota, 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 |
-refresh-token N |
Re-authenticate token #N in .env via the headless GitHub login flow and exit. Interactive: prints a login URL and polls. With -yes and GITHUB_USER / GITHUB_PASSWORD / GITHUB_TOTP set: protocol login |
-install-service |
Register the current binary as a background service and start it: Task Scheduler on Windows (per-user, no admin), systemd --user unit on Linux, launchd LaunchAgent on macOS. Resolves .env from your platform config directory (a ./.env in the working directory still wins), and auto-starts on logon/boot |
-uninstall-service |
Stop and unregister the background service (idempotent) |
-service-status |
Check whether the service is registered and running; exits 0 when registered, 1 when not (scriptable) |
All keys can be set via environment variables or the JSON config file passed to -config (AUTO_DISCOVER_TOKEN is environment-only); a .env file (resolved automatically from your platform config directory, or ./.env in the working directory when 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, MODELS_ALLOW) are comma-separated in env and arrays in JSON (MODELS_ALLOW also accepts a plain comma-separated JSON string).
| 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; set = pooled or hybrid) |
BRIDGE_ENABLED |
true |
With AUTH_TOKENS set, accept bridge-mode clients (their own token relayed) alongside the pool — hybrid mode. 0 = locked-down pooled-only instance (the pre-hybrid behavior) |
BRIDGE_IDLE_EVICT |
72h |
How long a bridge entry may sit unused before its runs are FINISHed and it is evicted from the cache (sliding TTL; zero or invalid → 72h) |
MODELS_HIDE_UNAVAILABLE |
false |
/v1/models prunes models marked unavailable (region/tier demotion, quota exhaustion) so picker clients cannot select them; off by default so a stale signal never hides a working model |
MODELS_ALLOW |
"" |
Comma-separated model allowlist (JSON array or string). When set, only these model ids are served — /v1/models lists only them, and chat/messages/responses requests whose resolved model (after alias resolution) is not listed are rejected with 404 model_not_found ("model not allowed by MODELS_ALLOW"). Empty = all models allowed |
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). In hybrid mode API_KEYS is the discriminator: a credential matching an entry uses the pool, any other is relayed as a bridge token |
ADMIN_TOKEN |
123456 |
Login password for the admin dashboard and the bearer token POST /admin/reload requires. Defaults to the factory password 123456 (a startup warning is logged and the dashboard shows a change banner until you rotate it): change it before exposing the port — while the factory default is active, sensitive dashboard routes (config editor, logs, token management, reload) additionally require a loopback client |
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 |
ACTING_USER_ID |
"" |
Optional FreeBuff account id; sent on every chat call as x-freebuff-acting-user-id. BAN RISK: only the token's own account id is safe (the CLI derives it from GET /api/v1/me; the server honors the header only for the FreeBuff Web service account) — any other value impersonates another user. Pre-rename name USER_ID still works. Empty = header omitted |
TLS_FINGERPRINT |
auto |
auto, chrome120, chrome126, safari17, safari18, firefox120, firefox128, edge126, random |
DEBUG_DUMP |
false |
Persist redacted traffic dumps to ./dump/ (mode 0600) |
DEVTOOLS_ENABLED |
false |
Show the Dev Tools page (batch chat, session spawner) in the admin dashboard. Default off — it is a manual testing surface that hammers /v1/* and is not for public dashboards. |
LOG_FILE |
"" |
Append log lines to a file (e.g. ./logs/proxy.log) |
LOG_LEVEL |
info |
debug, info, warn, error, trace (trace = wire-level bodies) |
LOG_FORMAT |
text |
text (key=value, colored) or json (one JSON object per line) |
LOG_ACCESS |
true |
Log one access line per HTTP request (false disables; /healthz, /metrics, OPTIONS are rate-limited to 1/min regardless) |
LOG_RING_SIZE |
500 |
In-memory log ring for /admin/logs (50–5000) |
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) |
SESSION_IDLE_END |
0 |
End upstream sessions after this idle period, releasing the token's daily admission slot while the proxy sits unused; the next request re-admits and consumes a fresh slot (0 = disabled, opt-in) |
QUOTA_FALLBACK_MODELS |
flash→mimo, glm→flash, luna→flash |
Map model → fallback when its session quota is exhausted/unentitled. Defaults: deepseek/deepseek-v4-flash=mimo/mimo-v2.5, z-ai/glm-5.2=deepseek/deepseek-v4-flash, openai/gpt-5.6-luna=deepseek/deepseek-v4-flash (luna degrades the scarce premium session locally instead of hammering quota 429s; #203) |
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 |
Informational only: parsed and shown on the admin dashboard (Configuration Studio). No wire impact — the chat UA is pinned to ai-sdk/openai-compatible/1.0.0/codebuff, the ads UA to Freebuff-CLI/1.0.0, and session/auth endpoints default to Bun/1.3.14 |
MODEL_ALIASES |
"" |
Map aliases to real model IDs, e.g. gpt-4o:openai/gpt-5.6-luna. There are no built-in aliases (the old deepseek-chat/gpt-4o/claude-3-5-sonnet map was removed when deepseek-v4-pro was paused); clients must map aliases explicitly. |
TRANSIENT_RETRIES |
1 |
Max additional attempts after a transient transport failure; 0 disables |
SESSION_PERSIST |
false |
Persist session state AND active agent runs to disk so a restart resumes them instead of re-creating (new daily slot / re-START) |
SESSION_STATE_FILE |
.freebuff-session-state.json |
Path of the session state file (used when SESSION_PERSIST=true; token-keyed, 0600) |
SESSION_RE_ADMIT_LEAD |
60s |
Re-admit a session pre-emptively when less than this remains: the request rides the old session while the refresh runs in the background |
SESSION_PROBE_CACHE_TTL |
15s |
Reuse the last successful session state (skip redundant session poll GETs) within this window |
SESSION_CREATE_MAX_PARALLEL_GLOBAL |
128 |
Cap on concurrent in-flight session admissions (wait-or-503) |
SESSION_CREATE_MAX_PARALLEL_PER_MODEL |
32 |
Per-model cap on concurrent in-flight session admissions |
RUN_FINISH_QUEUE_SIZE |
64 |
Bounded deferred-FINISH worker queue for rotated/drained runs |
RUN_FINISH_INLINE_TIMEOUT |
250ms |
Synchronous inline FINISH fallback bound when the finish queue is full |
RUNS_DRAIN_QUEUE_CAP |
64 |
Draining-runs list cap; older entries are force-dropped (FINISH is best-effort) |
RUNS_DRAIN_TTL |
10m |
Draining-runs TTL eviction window |
HTTP2_UPSTREAM |
true |
Negotiate HTTP/2 with the upstream so the ALPN matches real browsers; false forces HTTP/1.1 |
FALLBACK_MODEL |
"" |
Map model1=fallback1,model2=fallback2 to re-route a request to the fallback model when its queue wait passes FALLBACK_AFTER_MS (queue-wait only — never on 429 quota exhaustion). When unset, the built-in default applies: openai/gpt-5.6-luna → deepseek/deepseek-v4-flash |
FALLBACK_AFTER_MS |
10000 |
Queue-wait threshold (ms) before falling back to FALLBACK_MODEL |
CORS_ALLOWED_ORIGIN |
* |
Access-Control-Allow-Origin for /v1/* responses |
ADOPT_CLI_SESSION |
false |
Adopt the upstream CLI's active session instead of creating a new one |
WAITING_ROOM_CHAIN |
false |
After an upstream 428 waiting_room_required, fire the reference ad-chain (POST /api/v1/ads per provider) + GET /api/v1/freebuff/streak before the next session create — on both the pooled and bridge paths (issue #94(b), gated stub — best-effort, never blocks the request; not a queue-across-tokens mechanism) |
WEBHOOK_URL |
"" |
Best-effort alert POSTs for three events: pool_exhausted (all tokens rate-limited), token_banned (from chat or admission — including bridge tokens, sent with token_index 0), and agent_model_mismatch_escalation (3+ allowlist refusals in 60s on one token — issue #140; empty = disabled; at most one POST per event type per 5m, never blocks the request path) |
RATE_LIMIT_PER_IP |
0 |
Requests/second allowed per client IP (0 = disabled; e.g. 20) |
RATE_LIMIT_BURST |
0 |
Burst request capacity per client IP (0 = default 2 * RATE_LIMIT_PER_IP) |
When SESSION_PERSIST=true, the state file stores a SHA-256 hash of each
active token plus its session metadata (instance id, expiry, tier/country)
and its active agent runs (run id, agent, trace session id), including
bridge-mode client tokens, since every session manager shares the one store.
A restart adopts the persisted session and runs without re-creating them.
The raw token is never written, and the file is created with mode
0600. Leave SESSION_PERSIST unset (or false) to opt out entirely.
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.
- Do not route through a VPN. FreeBuff resolves access tier via Cloudflare TCP-layer GeoIP
(not HTTP headers —
X-Forwarded-For/CF-Connecting-IPspoofing is impossible at L4). VPN/datacenter IPs are detected via MaxMind/Spur Intelligence ASN databases (ipPrivacySignals: ["vpn"]) and placed in a restricted cohort with a $0.50/day spend ceiling. Commercial VPNs (NordVPN, ExpressVPN), datacenter VPS (AWS, DO, Hetzner), and Tor all trigger this detection. The proxy's stealth settings mask TLS fingerprints and proxy headers; they do not change your public IP. Use a normal residential connection. - Do not hammer many tokens at once from the same public IP. Upstream caps how many
distinct users can hold an active free session on one egress IP (
ip_capped, 429), and accounts created from the same signup network (≥8 per /24) or mailbox (≥3) are permanently capped at lower trust levels. Documented ban cohorts include single-IP rings and same-day account mints. The pool already drains keys one at a time; do not add aggressive rotation on top. - Only request models your account's tier and region actually offers. Out-of-tier picks
are refused or downgraded (
model_unavailable,session_model_mismatch). The requested model id is correlated with the egress IP's resolved geo, so a premium model request from a VPN/hosting IP is a suspicious, ToS-prohibited combination. On limited-tier accounts,mimo/mimo-v2.5is the supported active model (deepseek/deepseek-v4-flashis restricted on limited tier). - Know the difference between a quota and a ban.
429(quota, resets at Pacific midnight) is the normal end-of-day signal; the proxy locks the token locally and answers in<1ms, and routers fail over.503withwaiting_roomis the queued-waiting-room signal (also transient). Only403withbanned/country_blockedmeans the account itself is gone: stop using it and move to a fresh established account. - For ~24h of continuous coding, budget 4-5 keys. Each FreeBuff account has a daily session
quota (premium 5/day, limited 3/day, trust-level ladder up to 7) and the CLI holds one session
at a time (concurrent sessions are a Desktop multi-tab feature, not CLI).
One key ≈ one day of moderate use. Configure
AUTH_TOKENSwith multiple tokens to pool session headroom across tokens and let the proxy drain them one at a time. - Register accounts with real email addresses (e.g. Gmail). Disposable / temp-mail registrations are a documented ban cohort: 6,699 of 7,129 accounts on flagged domains were already banned when the blocklist was compiled. Accounts sharing one mailbox are capped at lower trust levels.
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). Each row carries available/status/current_access_tier: models outside the limited-tier allowlist (mimo-v2.5) are marked available:false, status:"region_limited" when the token's egress region demotes it to the limited tier; MODELS_HIDE_UNAVAILABLE=true prunes them from the list; MODELS_ALLOW prunes every id not in the allowlist |
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; zero-cost per-token validity probes run on every request |
POST /admin/mode |
session cookie (loopback when ADMIN_TOKEN unset) |
Runtime mode switch: {"mode":"hybrid"} (pooled + bridge), {"mode":"pooled"} (bridge relay disabled, BRIDGE_ENABLED=0), {"mode":"bridge"} (empties AUTH_TOKENS). All changes persisted to .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 a built-in modern SPA web dashboard: single binary, no external dependencies, and zero runtime Node.js requirement (the Svelte 5 production build is compiled and embedded into the binary at build time). 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. It defaults to the factory password123456— until you change it, sensitive routes (config editor, logs, token management, reload) require a loopback client even when logged in (a startup warning and a persistent dashboard banner prompt the rotation;/admin/api/change-passwordworks from anywhere since it requires the current password). Failed logins are rate-limited per IP (5 fails → 1 minute lockout), and the session cookie isHttpOnly+SameSite=Strict(+Securewhen TLS orX-Forwarded-Proto: httpsis present). - Overview: live relay state (pooled/bridge/hybrid mode, model count, uptime, safe mode) with per-token cards: session status, risk score, usage vs
MAX_MESSAGES_PER_DAY, transient-retry counters, a bridge relay summary (active client count), plus a smoke test that sends one real chat through the pool (status, latency, preview). - Tokens & Quotas: two sections side by side in hybrid mode — the pooled token table and live bridge-client cards (masked key, status, model, requests, spend, premium/GLM quota, ban state) so both surfaces are trackable from one page. Per-token Unlock, Finish runs, and Test; runtime Add Token to Pool; a 3-mode switcher (
Pooled,Hybrid,Bridge) — changes automatically persisted to.env. - Models: live catalog with upstream agent mappings, default model badges, and
MODEL_ALIASES. - Traces: recent chat requests and their routing outcome (token, model, status, duration, error class), the observability view for ban-avoidance debugging.
- Playground: interactive prompt console with real-time SSE chat streaming, model selector, and collapsible thinking/reasoning blocks.
- Configuration Studio: hot-reloading
.enveditor equipped with 3 One-Click Presets (Stealth Anti-Ban, Maximum Speed, Deep Debugging), interactive quick knobs (boolean switches, enum pills, duration sliders) with real-time bidirectional sync, and hover quick info cards explaining every setting and default. - Setup & Tool Integration: universal 1-click copy cards (Base URL, API Key, Default Model), copy-paste snippets for 5 major AI coding tools (OpenCode, Continue/Cline, aider, 9router, cURL), headless OAuth login wizard, and diagnostic suite.
- Logs: real-time in-memory log stream with level filtering (
INFO,DEBUG,WARN,ERROR), search filtering, and structured field tags. - Metrics: tabular stat cards with SVG sparklines and direct link to the raw
/metricsPrometheus feed.
See Dashboard Guide for access, Docker caveats, and hardening.
Develop the SPA with the Vite dev server: run task frontend:dev (Vite on http://127.0.0.1:5173/admin/)
alongside a local gateway (task dev, 127.0.0.1:3457). The dev server proxies /admin/* to that
gateway and redirects a GET /admin/login to the SPA hash route /admin/#login. For the embedded
production build (single binary), run task frontend:build.
- 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
- Manual Testing: verify the proxy on Linux or Windows by hand, step by step
- User Lifecycle: install → first run → tokens → use → monitor → edit → rotate → quota → update
- Version Stability & Ban Findings: read before upgrading — why v0.11.2 bridge is the proven-stable deployment
| Compatibility | Details |
|---|---|
| Coding-agent harnesses | 11/12 first-party surfaces supported: opencode, codex, cline, roo-code, goose, aider, continue, qwen-code, pi, oh-my-pi, kilocode. gemini-cli is not supported (native Gemini only — point it at Vertex AI / AI Studio, or use opencode-go). Full per-harness matrix, config snippets, and known limits: docs/harness-compatibility.md; ready-to-edit templates in examples/harnesses/. |
- Contributing: filing issues, opening PRs, what to expect
- Security: supported versions and how to report a vulnerability
The offline model registry pins five upstream constant files in backend/internal/registry/testdata/upstream/.
To automatically fetch upstream changes from CodebuffAI/freebuff, update the pinned definitions, verify hash parity, and run the test suite:
# Linux / macOS / Git Bash
bash scripts/sync-upstream.sh
# Windows (PowerShell / CMD)
.\scripts\sync-upstream.cmdTo check drift without writing files, pass --check / -CheckOnly. To run the full test suite after syncing, pass --test-all / -TestAll.
To run only the read-only hash parity check:
bash scripts/check-upstream.shCI runs the same check weekly (upstream-drift workflow) and goes red on drift. A live registry refresh self-heals at runtime; sync-upstream keeps the offline fallback in lockstep.
- Questions, bugs, feature requests: GitHub Issues
- Security reports: SECURITY.md
- Contributing: CONTRIBUTING.md