Skip to content
aNother1332Public

About

Tiny local gateway that makes OpenCode Zen's free models (glm-5.3-flash-free, deepseek-v4.1-flash-free, ...) usable from any OpenAI Chat Completions compatible client. Zero dependencies.

Topics

Resources

Stars

1 star

Watchers

0 watching

Forks

Latest commit

 

History

1 Commit

Folders and files

Repository files navigation

zen-pool

A tiny local gateway that makes OpenCode Zen's free models (glm-5.3-flash-free, deepseek-v4.1-flash-free, …) usable from any OpenAI Chat Completions–compatible client.

No dependencies. Just Node.js ≥ 18.

中文说明见 README.zh-CN.md


The problem

OpenCode Zen serves its free models only to requests that look like the real OpenCode client — anything else gets:

403 FreeTierError: OpenCode's free tier can only be used from within OpenCode.

A static API key, an OAuth login, or a different User-Agent alone does not help. Reverse-engineering the gate (by capturing the real opencode CLI and reading magpie's source) shows a free-tier request must satisfy all of the following:

# Requirement Detail
1 OpenCode client headers User-Agent: opencode/<version> ai-sdk/… runtime/bun/…, x-opencode-session, x-opencode-session-id, x-opencode-request, x-opencode-client: cli, x-opencode-project: global — and no x-session-affinity
2 Well-formed IDs Session/message IDs must follow opencode's descending() layout: 26 chars = 12 hex chars of ~(ms<<12) + 14 random chars
3 Streaming + bash/read tools stream: true is mandatory; the tools array must offer lowercase bash and read with non-empty parameter schemas
4 The right URL Free models must be called at https://opencode.ai/inference/v1/... (since mid-October 2026, /zen/v1 returns 403 for free models)

zen-pool does all of this transparently, so your client doesn't have to.

What it does

  • Accepts OpenAI Chat Completions requests on http://127.0.0.1:3425/v1.
  • Injects the OpenCode identity headers and generates valid IDs per request.
  • Offers the client's Bash/Read tools to Zen under lowercase bash/read (or adds harmless stubs when absent) and maps tool-call names back in the reply.
  • Streams through to /inference/v1 for free models (*-free, plus big-pickle and grok-code), and to /zen/v1 for everything else.
  • Aggregates the upstream stream into a single JSON reply for non-streaming clients.
  • Multi-account rotation: on 401/402/quota-style errors it moves to the next API key / OAuth account automatically.

Quick start

git clone https://github.com/<you>/zen-pool.git
cd zen-pool
node zen-pool.mjs serve           # listens on 127.0.0.1:3425

Then point any OpenAI-compatible client at it:

  • Base URL: http://127.0.0.1:3425/v1
  • API key: anything (e.g. local) — the gateway supplies the real credential
  • Model: glm-5.3-flash-free, deepseek-v4.1-flash-free, cat-jam-free, …

No account or API key is required for free models — zen-pool asks Zen anonymously (Bearer public) in OpenCode's shape.

Example: curl

curl http://127.0.0.1:3425/v1/chat/completions \
  -H "content-type: application/json" \
  -d '{
    "model": "glm-5.3-flash-free",
    "messages": [
      {"role": "system", "content": "You are a helpful coding agent."},
      {"role": "user", "content": "Say hello in one sentence."}
    ]
  }'

Tip: a system message is not required by the gateway, but agents normally send one — keep it, it makes the request look natural.

Example: ZCode (desktop client)

  1. Start the gateway: node zen-pool.mjs serve
  2. In ZCode: Settings → Model Providers → add a custom provider
    • API type: OpenAI Chat Completions
    • Base URL: http://127.0.0.1:3425/v1
    • API key: anything (e.g. local)
    • Add the model IDs you want (glm-5.3-flash-free, …)
  3. Restart ZCode and pick the model.

(The equivalent for ZCode's config file lives at <zcode-data-dir>/v2/provider_config.json — an opencode-zen-chat provider entry with api.baseUrl set to the gateway.)

Example: Codex CLI

In ~/.codex/config.toml:

[model_providers.zen-pool]
name = "zen-pool"
base_url = "http://127.0.0.1:3425/v1"
wire_api = "chat"

[profiles.free]
model = "glm-5.3-flash-free"
model_provider = "zen-pool"

Then codex --profile free.

Accounts & rotation (optional)

Free models need no account. If you also want paid models through the gateway, or want multiple free accounts pooled, provide credentials:

# Option A — API keys (paid models). Copy the example and fill in your keys:
cp keys.example.json keys.json
# Get keys at https://opencode.ai/auth

# Option B — OAuth device login (repeat per account):
node zen-pool.mjs login --name work
node zen-pool.mjs login --name personal

# Inspect state:
node zen-pool.mjs status
curl http://127.0.0.1:3425/zen-pool/status

Rotation rules: free models try anonymous first, then fall back to every configured account/key; paid models rotate through keys and accounts on 401/402/quota errors. Every response carries an x-zen-pool-account header saying which account served it. OAuth tokens are refreshed automatically and persisted in accounts.json.

Run on startup (optional)

  • Windows: Win+R → shell:startup → put a shortcut to node <path>\zen-pool\zen-pool.mjs serve there.
  • macOS/Linux: a systemd --user unit or a launchd plist running node /path/to/zen-pool/zen-pool.mjs serve.

Caveats

  • The upstream free pool occasionally answers 429 Endpoint is unavailable (capacity, not your account) — just retry.
  • Free-tier data policy is permissive (prompts may be retained / used for training). Don't send sensitive code to free models.
  • keys.json and accounts.json contain plaintext credentials — they are gitignored; keep it that way.
  • The gateway binds 127.0.0.1 only.
  • The free-tier gate is a server-side rule and can change any time. If you see FreeTierError again, check the constants at the top of zen-pool.mjs against magpie's internal/provider/opencode_client.go.

How it was figured out

  1. Captured the real opencode CLI with a local HTTP recorder (it sends Bearer public when nobody is signed in).
  2. Compared every captured header/body field against a minimal working request to isolate the required set (headers → ID layout → stream → bash/read tools → /inference/v1 URL).
  3. Cross-checked with magpie's MIT-licensed source, which documents the same rules in internal/gateway/zenfree.go.

Credits

  • opencode — the CLI whose request shape is emulated.
  • magpie by yetone (MIT) — prior art for this exact integration; several constants and the tool-renaming strategy follow it.

License

MIT — see LICENSE.

About

Tiny local gateway that makes OpenCode Zen's free models (glm-5.3-flash-free, deepseek-v4.1-flash-free, ...) usable from any OpenAI Chat Completions compatible client. Zero dependencies.

Topics

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages