An OpenAI-compatible proxy bridge for the FreeBuff free tier. Point any OpenAI client at it and it talks to FreeBuff for you, with token pooling and session management built in.
FreeBuff (Codebuff's free coding agent) exposes its models only through the official CLI. The backend fingerprints CLI traffic and rejects direct API calls with 403 free_mode_cli_required. freebuff-proxy replicates the CLI request envelope, manages the free-session and agent-run lifecycle upstream, and pools multiple tokens. Clients see a plain OpenAI-compatible API.
Current upstream status (read before installing). Since roughly 2026-08-03, upstream rejects free-tier
POST /api/v1/chat/completionswith403 free_mode_cli_requiredeven for valid, non-banned tokens. Sessions and agent runs still succeed, so/healthzand/v1/modelswork normally and your install will look healthy while chat fails. The check is server-side and bound to the account, and it is not bypassable from this project: see the FAQ entry for the full list of what was tested against a live token. Install anyway to be ready for an upstream change, but do not expect working chat today.
What this is not: an official FreeBuff or Codebuff product. It is a community bridge for an unofficial service. See the FAQ and Terms of use at the bottom.
This project works by making FreeBuff believe it is talking to the official CLI. The upstream service detects this and does suspend and ban accounts.
- Suspended/banned accounts fail with
403 account_banned/{"status":"banned"}, and the web dashboard shows "suspended". Your FreeBuff/Codebuff account, tokens, and free-tier access are on the line.- The ban is per account and effectively terminal. The official source code flags the account as banned ("terminal", returned from every endpoint). Unbanning is an internal admin operation; there is no self-service path. Community proxies have seen
resumes_attimestamps in ban responses, which would mean temporary bans, but this is not confirmed in any official source and may just be the account being gone.- Bans are scored by a public abuse-detection pipeline: heavy continuous usage (hundreds of messages a day, many distinct active hours, long unattended sessions), automation patterns, fresh GitHub accounts (under a few weeks old), throwaway email addresses, and clusters of new accounts created close together all raise the score.
- Codebuff's terms allow one account per person and explicitly prohibit wrappers, proxies, and non-human sessions. Using this proxy already conflicts with them.
Use at your own risk, and assume a ban is permanent.
- Use one modest account; do not run 24/7, do not leave sessions running unattended, stop when you see
429 rate_limited.- If you are banned: the token is dead. Wait and re-probe once (cheap to try), then get a new account with an established GitHub login (months old, not fresh) and a clean IP, without a VPN. That is the only realistic recovery.
- Appeals go to support@codebuff.com and realistically only succeed for false positives, not for proxy use. The maintainers have had accounts suspended while building and testing this project. This is not a toy warning.
New here? Start with the Getting Started Guide for step-by-step setup, or see the Client Integration Guide for copy-paste config for Continue, Cursor, aider, opencode, and more.
graph TD
Client[AI Client / Tool<br/>Continue, Cursor, aider] -->|POST /v1/chat/completions| Proxy[freebuff-proxy<br/>localhost:3457]
Proxy -->|1. Session & Run Lifecycle| Pool[Token Pool & Session Manager]
Proxy -->|2. Inject Envelope + Stealth| Upstream[Codebuff Upstream API<br/>codebuff.com]
Upstream -->|3. SSE Stream| Proxy
Proxy -->|4. OpenAI SSE Chunks| Client
| Term | Meaning |
|---|---|
| Token | Your FreeBuff authentication credential (authToken). Obtained via official CLI login (freebuff). |
| Session | A "free session" created upstream by the proxy so FreeBuff treats requests as coming from the official CLI. |
| Run | An "agent run" inside a session required for model requests. Automatically rotated every 6h. |
| Rotation | Periodically finishing old agent runs and starting new ones upstream to prevent long-lived session detection. |
| Cooldown | When a token receives a 401 or 429 error, the proxy temporarily pauses it (30 min) and fails over to another token. |
| Bridge mode | Proxy runs without configured tokens (AUTH_TOKENS=); each client sends their own token via Authorization: Bearer <token>. |
| Safe mode | Preset (SAFE_MODE=true) applying conservative defaults for message caps, idle rotation, and request jitter. |
-
Serves
/v1/chat/completions,/v1/models, and/healthzon127.0.0.1:3457by default. -
Self-diagnostic tool:
./freebuff-proxy -doctortests config, network, tokens, and upstream reachability (#15). -
Pools tokens:
AUTH_TOKENSaccepts comma-separated values, round-robins across them, and cools a token down for 30 minutes after a 401. -
Keeps free sessions alive: single-flight session create/poll/end, runs prewarmed at boot, rotated every
ROTATION_INTERVAL(default 6h). -
Refreshes the model catalog every 6h from the Codebuff sources (15 models at boot, served by
/v1/models). -
Sends outbound traffic through
HTTP_PROXYorSOCKS5_PROXY, or impersonates a browser TLS fingerprint withTLS_FINGERPRINT(chrome126,firefox128,safari18,edge126,auto). -
Account-safety knobs:
SAFE_MODE=truepreset,MAX_MESSAGES_PER_DAY,IDLE_ROTATION_TIMEOUT, andREQUEST_JITTER. -
Zero or more FreeBuff auth tokens. With none, the proxy runs in bridge mode — each client sends their own token (see Bridge mode).
-
Release binaries run standalone. Building from source needs Go 1.26+ (see
go.mod).
Four ways to install. If you are new, pick Option 1.
| Option | Pick it when | Needs |
|---|---|---|
| 1. One-command installer | You just want it running (interactive menu picks the rest for you) | curl, a terminal |
| 2. Manual download | You want to see every step, or the installer is blocked | curl, tar/unzip |
| 3. Docker Compose | You run containers, or want it always-on with a healthcheck | Docker + Compose v2 |
| 4. Build from source | You want to audit or modify the code | Go 1.26+ |
All four end the same way: a proxy listening on 127.0.0.1:3457 (or :3457 in a container)
plus a .env. Then run the Quick start smoke test and compare against the
results table there before wiring any client.
Downloads the latest release binary for your platform, verifies its checksum, sets up
.env, asks for your token, and prints the next steps. No version to look up, no manual
downloads. Running it in a terminal shows an interactive menu: easy install, manual binary,
Docker Compose, or bridge mode (no proxy token — clients send their own). For scripted
runs add --no-prompt (safe defaults) or pick a method with --method=binary|docker|bridge.
Windows (PowerShell):
irm https://raw.githubusercontent.com/trefeon/freebuff-proxy/main/scripts/install-freebuff-proxy.ps1 | iexLinux / macOS (bash):
curl -sSL https://raw.githubusercontent.com/trefeon/freebuff-proxy/main/scripts/install-freebuff-proxy.sh | bashBoth scripts install into the current directory (--dir <path> to change it), extract
AUTH_TOKENS into .env from your official freebuff CLI login, and print the run and smoke-test commands.
Download the archive for your platform from the latest release. The commands below resolve the version automatically — no manual <version> replacement needed. Every release ships checksums.txt.
| Platform | Asset name |
|---|---|
| linux / amd64 | freebuff-proxy_<version>_linux_amd64.tar.gz |
| linux / arm64 | freebuff-proxy_<version>_linux_arm64.tar.gz |
| macOS / amd64 | freebuff-proxy_<version>_darwin_amd64.tar.gz |
| macOS / arm64 | freebuff-proxy_<version>_darwin_arm64.tar.gz |
| windows / amd64 | freebuff-proxy_<version>_windows_amd64.zip |
| windows / arm64 | freebuff-proxy_<version>_windows_arm64.zip |
Linux / macOS (one-liner, adjust the asset suffix for your platform):
VERSION="$(curl -fsSL https://api.github.com/repos/trefeon/freebuff-proxy/releases/latest | grep -oP '"tag_name":\s*"\K[^"]+' )"
curl -fsSL -o freebuff-proxy.tar.gz "https://github.com/trefeon/freebuff-proxy/releases/latest/download/freebuff-proxy_${VERSION}_linux_amd64.tar.gz"
curl -fsSL -o checksums.txt "https://github.com/trefeon/freebuff-proxy/releases/latest/download/checksums.txt"
tar xzf freebuff-proxy.tar.gz
sha256sum -c checksums.txt --ignore-missing 2>/dev/null || echo "checksum mismatch — verify manually"
./freebuff-proxyWindows (PowerShell):
$v = (Invoke-RestMethod https://api.github.com/repos/trefeon/freebuff-proxy/releases/latest).tag_name
Invoke-WebRequest -OutFile freebuff-proxy.zip "https://github.com/trefeon/freebuff-proxy/releases/latest/download/freebuff-proxy_${v}_windows_amd64.zip"
Expand-Archive freebuff-proxy.zip -DestinationPath . -Force
.\freebuff-proxy.exeFor the fully automatic path (download + checksum + .env + token + next steps), just use the one-command installer in Option 1.
Copy .env.example to .env and set AUTH_TOKENS first (or leave it empty for bridge
mode), then:
docker compose up -d --build
docker compose ps # wait for "healthy" before smoke testingThe compose file publishes port 3457, sets LISTEN_ADDR=:3457, and runs a healthcheck
against /healthz. For a one-shot setup on Linux, scripts/setup-proxy-docker.sh clones the
repo, grabs the token, starts the container, and prints the 9router config with the right
Docker gateway IP.
If you run the image without Compose, you must set LISTEN_ADDR yourself. The default
(127.0.0.1:3457) binds loopback inside the container, so a published port leads nowhere
and curl fails with "connection refused" while the container looks fine:
docker build -t freebuff-proxy .
docker run -d -p 3457:3457 --env-file .env -e LISTEN_ADDR=:3457 freebuff-proxyLeaving out -e LISTEN_ADDR=:3457 is the single most common "my setup does not work"
report. Compose sets it for you; plain docker run does not.
go build -o freebuff-proxy ./cmd/freebuff-proxyWindows builds: go build -o freebuff-proxy.exe ./cmd/freebuff-proxy.
The FreeBuff token (authToken) is issued when you log in through the official freebuff CLI:
- Official CLI: Run
npm i -g freebuffand runfreebuffonce to log in via your browser. - Token location: The CLI saves
authTokento~/.config/manicode/credentials.json(Windows:C:\Users\<you>\.config\manicode\credentials.json). - Scripts:
scripts/get-freebuff-token.sh(bash) orscripts/get-freebuff-token.ps1(PowerShell) automate installing the CLI, completing the login, and writingAUTH_TOKENSinto.envfor you.
Use the authToken value without any Bearer prefix; the proxy adds it upstream automatically. For higher throughput, log in with several accounts and comma-separate the tokens: AUTH_TOKENS=tok1,tok2.
-
Copy the example config:
cp .env.example .env
(Windows PowerShell:
Copy-Item .env.example .env) -
Edit
.envand setAUTH_TOKENS. Optional — empty starts the proxy in bridge mode (see Bridge mode). -
Run the proxy:
./freebuff-proxy
-
Smoke test:
curl http://localhost:3457/healthz curl http://localhost:3457/v1/models curl -N http://localhost:3457/v1/chat/completions \ -H "Content-Type: application/json" \ -d '{"model":"deepseek/deepseek-v4-flash","messages":[{"role":"user","content":"Say hello in one short sentence."}],"stream":true}'
Read this table before concluding your setup is broken. /healthz and /v1/models
returning 200 means your setup is correct — those two prove the binary, config, port, and
model registry all work. The chat call additionally depends on your account and on upstream,
so a failure there is usually not a setup problem.
| Call | Result | Meaning |
|---|---|---|
/healthz |
200 + JSON (uptime_seconds, models, tokens) |
Proxy is up. Setup OK. |
/healthz |
connection refused | Not running, or in a container without LISTEN_ADDR=:3457 (see Option 3). |
/v1/models |
200 + ~12 model ids |
Registry loaded. Setup OK. |
/v1/models |
401 invalid_api_key |
You set API_KEYS; send Authorization: Bearer <your-api-key>. |
| chat | SSE stream (data: {...}) |
Everything works end to end. |
| chat | 502 wrapping 403 free_mode_cli_required |
Upstream's CLI-only gate, not your setup. See the FAQ entry below. |
| chat | 502 wrapping 401/404 Invalid API key or user not found |
The token in .env is invalid, expired, or the account is gone. Get a fresh token. |
| chat | 403 account_banned |
Account suspended upstream. Token is dead, see the WARNING at the top. |
| chat | 429 rate_limited |
Daily session quota used up (6/day on limited tier). Wait for the Pacific-midnight reset or add a token. |
| chat | 503 waiting_room_queued |
Normal. Retry after Retry-After; 9router and opencode do this automatically. |
| chat | 401 missing_bearer_token |
Bridge mode with no client token. Send Authorization: Bearer <your-freebuff-token>. |
| chat | 400 invalid_json |
Shell quoting mangled the -d payload. On Windows use --data @file.json instead of inline quotes. |
If /healthz and /v1/models are 200 and only chat fails, your installation is fine: the
problem is the token or upstream, and no config change in this project will fix it.
Every key is read from the environment and overrides the JSON config file passed with -config (see config.example.json; keys mirror the env names). -v enables verbose logging.
| Key | Default | Description |
|---|---|---|
AUTH_TOKENS |
empty | FreeBuff token(s), comma-separated. Round-robin + failover across tokens. Empty = bridge mode: clients supply their own token per request. |
LISTEN_ADDR |
127.0.0.1:3457 |
Listen address. Loopback only by default; use :3457 in containers or behind a firewall. |
UPSTREAM_BASE_URL |
https://codebuff.com |
Upstream base URL (host normalized to www.codebuff.com). |
ROTATION_INTERVAL |
6h |
How long an agent run lives upstream before rotation (FINISH + restart). |
REQUEST_TIMEOUT |
15m |
Timeout for one chat-completions request, stream included. |
SESSION_CALL_TIMEOUT |
30s |
Timeout for individual session/run API calls. |
REGISTRY_REFRESH |
6h |
How often the model registry re-fetches the Codebuff sources. |
API_KEYS |
empty | Optional client auth. Comma-separated keys clients must present. Empty means no client auth. |
HTTP_PROXY |
empty | Outbound HTTP/HTTPS proxy (CONNECT tunneling). |
SOCKS5_PROXY |
empty | Outbound SOCKS5 proxy, e.g. socks5://127.0.0.1:1080. |
COST_MODE |
free |
Mode sent upstream with chat requests. Must be free: the upstream 402 balance check runs only when cost_mode != "free", so omitting it makes fresh free-tier accounts fail with 402 "Out of credits. Please add credits at codebuff.com/usage". |
DEBUG_DUMP |
false |
Dump raw upstream traffic into ./dump (sensitive headers redacted). |
LOG_FILE |
empty | Append logs to a file in addition to stderr. |
LOG_LEVEL |
info | debug, info, warn, or error. -v implies debug; LOG_LEVEL wins. |
TLS_FINGERPRINT |
empty | Outbound JA3 fingerprint: chrome120, safari17, firefox120, or random. |
MAX_MESSAGES_PER_DAY |
0 |
Per-token rolling 24h message cap. At the cap the proxy answers 429 rate_limited with Retry-After instead of hitting upstream, keeping the account far under FreeBuff's abuse thresholds (~500 msgs/24h). 0 = unlimited. |
IDLE_ROTATION_TIMEOUT |
0 |
Pause background work after this long without traffic (e.g. 30m): runs are FINISHed and maintenance stops until the next request, so the account is not kept artificially active 24/7. 0 = always maintain. |
Leave AUTH_TOKENS= empty and the proxy boots in bridge mode: it holds no token of its own and is a pure relay. Every client sends their own FreeBuff token with each request:
curl -N http://localhost:3457/v1/chat/completions \
-H "Authorization: Bearer <your-freebuff-token>" \
-H "Content-Type: application/json" \
-d '{"model":"deepseek/deepseek-v4-flash","messages":[{"role":"user","content":"hi"}],"stream":true}'- The token from
Authorization: Bearer <token>(orx-api-key: <token>) is used verbatim upstream — it is never written to.envor logged (only counts/hints are logged). /healthzand/v1/modelsneed no header.API_KEYSis ignored in bridge mode (the Authorization header is the upstream credential, not a proxy key).- Sessions and runs are created lazily per token on first use and reused across that client's later requests (least quota burn). The cache is bounded at 32 client tokens with LRU eviction; entries idle for ~2h are finished and dropped.
- All existing error mapping still applies per account:
403 account_banned,429 rate_limited+Retry-After,503 waiting_room_queued, etc. — each client's token is cooled down / banned independently. MAX_MESSAGES_PER_DAYapplies per client token (each cached entry has its own rolling 24h counter).
Readiness check: /healthz includes bridge_tokens — the number of cached client-token entries (0 until the first chat).
Add freebuff-proxy as an OpenAI-compatible custom provider in 9router. The step-by-step guide covers the dashboard form, model catalog, verification, and troubleshooting: docs/guides/9router-integration.md.
Quick version: Dashboard, Providers, Add OpenAI Compatible. Base URL http://localhost:3457/v1, API Type Chat Completions, any non-empty API key, and the model ids come from /v1/models. Model combos become freebuff/<model-id>.
Alternatively, bridge mode: leave AUTH_TOKENS empty on the proxy and use your FreeBuff token as the 9router API key — the proxy then relays with your token (one token = one session; quota/ban status is yours).
- 9router integration guide: full wiring, model catalog, troubleshooting.
- The other project docs (PRD, research notes, delivery tasks, security notes) are local-only dev docs, gitignored on purpose. They do not ship with the repo.
The smoke test chat returns 403 free_mode_cli_required (often wrapped in a 502).
The full message is "Free mode is only available through the freebuff CLI. Install it with
npm i -g freebuff, then run freebuff. Calling the API directly is not supported and may
get your account banned."
This is not a broken setup and not a bad token. Upstream added a CLI-only gate on the
free tier (first reported around 2026-08-03, see
Quorinex/Freebuff2API#18). If
/healthz and /v1/models return 200, your install is correct.
What was tested against a live, non-banned token, all still returning 403:
- the CLI/AI-SDK user agent (
ai-sdk/openai-compatible/<ver>/codebuff) - a stable
client_idreused across session, run, and chat x-freebuff-modelon session creation,x-freebuff-instance-idon chatCOST_MODE=free(verified in the startup log) and a valid 13-char base36client_idTLS_FINGERPRINT=chrome120(browser JA3 impersonation)- a hand-built request sent straight to upstream with no proxy involved
Session creation and agent-run START both succeed (200); only
POST /api/v1/chat/completions is rejected, and only once the run actually exists — so the
check is server-side and bound to the account/run, not to anything in the request. No setting
in this project bypasses it. Your options are to use the official CLI directly, or wait and
re-test after an upstream change. Open an issue if you see it start working again.
I get 402 / "Out of credits. Please add credits at codebuff.com/usage".
The request went down the paid path. Upstream runs its balance check only when cost_mode != "free", so a fresh free account (balance 0) always gets 402 unless COST_MODE=free is sent. Check your .env: COST_MODE must be free (the default and the value in .env.example). If it is empty, the proxy bills the request as paid. Old configs copied before v0.2.0 that set COST_MODE= empty need the value restored.
I get 429 with rate_limited in the body.
The token's daily session quota is exhausted (6 sessions per day on the limited tier, resets at Pacific midnight). The proxy returns 429 with the upstream resetAt so clients back off. Add another AUTH_TOKENS or wait for the reset.
I get 403 with account_banned / {"status":"banned"}.
Your FreeBuff account was banned or suspended upstream. See the WARNING at the top of
this file: the ban is per account and effectively permanent, the token is dead, and no
setting will revive it. The proxy stops using the token during the ban window (upstream
resumes-at, or 24h if none) and then re-probes once, which is cheap to try; if it still
fails, get a new account with an established GitHub login and a clean IP (no VPN). Appeals
go to support@codebuff.com but realistically only succeed for false positives.
I get 503 with waiting_room_queued.
Normal. The free session is queued in the waiting room. The Retry-After header tells the client when to retry; 9router and opencode retry automatically.
Windows Defender or Kaspersky flags the binary or test executables.
This is a heuristic false positive, not malware. The trigger is the optional TLS-fingerprint
module (internal/stealth): it links refraction-networking/utls, a library whose purpose
is impersonating a browser's TLS fingerprint (JA3). Malware uses the same technique to evade
network detection, so AV vendors heuristically flag any executable containing uTLS (that is
a static pattern match, not a behavior detection). The proxy is a plain HTTP server: no
persistence, no injection, no extra network traffic beyond the documented upstream relay,
and all token values are redacted from logs and dumps.
Verify it yourself in under a minute: build from source and compare with the release checksums:
go build -o freebuff-proxy.exe ./cmd/freebuff-proxy
sha256sum freebuff-proxy.exe # must match the value in the release's checksums.txtIf the hashes match, the flagged binary is exactly the public source. You can also submit the binary for re-analysis at opentip.kaspersky.com with the build-from-source repro. Practical workarounds:
- Add the binary and the Go build cache (
go-build*paths) to AV exclusions sogo testand normal use are not interrupted. TLS_FINGERPRINTis empty by default, so the uTLS path is only compiled in, not active, unless you set it. You lose nothing by leaving it unset.
Open an issue if you see a detection name (we have never seen a real signature match — only heuristics).
Is this against FreeBuff's terms?
FreeBuff is intended to be used through the official CLI only. This proxy uses undocumented endpoints and replicates CLI fingerprints, which conflicts with the letter of the service terms. Account bans are possible. Use it for personal and educational experimentation, keep usage modest, at your own risk.
How do I keep my account from getting banned?
Use less, use it like a human, and let the proxy do the same. Set
MAX_MESSAGES_PER_DAY (well under the ~500 msgs/24h threshold, e.g. 150) and
IDLE_ROTATION_TIMEOUT (e.g. 30m) so the proxy stops background work when you are not
using it; do not run it 24/7, stop when you see 429 rate_limited, and never share a
token between the proxy, the official CLI, and the web dashboard at the same time. See
the WARNING at the top of this file and the Terms of use.
I don't want to put my token in .env — can I send it per request?
Yes — run the proxy in bridge mode: leave AUTH_TOKENS= empty and send your FreeBuff
token as Authorization: Bearer <token> (or x-api-key: <token>) on every chat request.
The proxy relays with your token, never stores it in .env, and reuses one lazy session
per token. See Bridge mode.
Still stuck? Open an issue with the proxy version, your client, and LOG_LEVEL=debug output (redact tokens).
go build ./...
go vet ./...
go test ./... # runs against the mock upstream, no token needed
golangci-lint run ./... # lint config in .golangci.ymlCI runs go test -race ./... and go mod verify on Linux. Windows note: some AVs quarantine freshly linked test binaries out of the go-build cache (fork/exec ... Access is denied); that is the false positive above, use go test -c -o out\convert.test.exe ./internal/convert and run it directly as a workaround.
See CONTRIBUTING.md before opening a pull request.
This project is not affiliated with or endorsed by Codebuff. FreeBuff free tier is an unofficial, moving target: quota, models, and endpoints change without notice, and the proxy may break at any time. Use at your own risk.
MIT.