Skip to content

FR: add OpenCode Go provider #46

Description

@wtfsayo

Summary

Add an OpenCode Go upstream so Claude Code can use an OpenCode Go subscription ($5 first month, then $10/mo) through this proxy’s existing Anthropic-compatible surface.

Unlike Codex/Kimi/Grok/Cursor, OpenCode Go is API-key auth only — there is no OAuth login flow. The value CCP adds is per-model wire routing + translation, not credential management UX.

How this fits the project

claude-code-proxy already does:

credentials → local Anthropic Messages API → provider-specific upstream

Claude Code talks Anthropic; the proxy authenticates upstream and translates. OpenCode Go should be another provider on that path.

The main reason it belongs in CCP (vs. asking users to run a second proxy) is that OpenCode Go splits models across two wire protocols on one subscription. Claude Code only has one ANTHROPIC_BASE_URL and cannot pick the upstream API per model itself.

Motivation

OpenCode Go docs expose 14 curated open coding models via API, but they are not all on the same endpoint:

Models Upstream endpoint Wire format
GLM-5.2, GLM-5.1, Kimi K2.7 Code, Kimi K2.6, DeepSeek V4 Pro/Flash, MiMo-V2.5, MiMo-V2.5-Pro https://opencode.ai/zen/go/v1/chat/completions OpenAI-compatible
MiniMax M3/M2.7/M2.5, Qwen3.7 Max, Qwen3.7 Plus, Qwen3.6 Plus https://opencode.ai/zen/go/v1/messages Anthropic-compatible

Claude Code always sends Anthropic POST /v1/messages. Without a smart proxy:

  • Pointing at …/messages breaks half the catalog (GLM, Kimi, DeepSeek, MiMo).
  • Pointing at …/chat/completions breaks the other half (MiniMax, Qwen).
  • Community proxies (ocgo, oc-go-cc, opencode-proxy-for-claude-code, etc.) each re-implement routing + translation.

CCP already solves this class of problem for Codex (Responses), Kimi (OpenAI chat), Grok (Responses), and Cursor (Connect). OpenCode Go is the same pattern with a per-model endpoint split.

Note: Go endpoint assignments differ from OpenCode Zen for some models (e.g. MiniMax is chat/completions on Zen but messages on Go). Routing must follow the Go table, not Zen’s.

Authentication (API key — not OAuth)

Per OpenCode Go docs:

  1. Sign in to OpenCode Zen, subscribe to Go, copy your workspace API key from opencode.ai/auth
  2. In OpenCode itself: /connect → OpenCode Go → paste key (stored in ~/.local/share/opencode/auth.json via opencode auth login)

There is no browser/device OAuth for Go. The key is a static bearer token until rotated in the Zen console.

What CCP should do (and not do)

Do not mirror codex auth login / grok auth device for OpenCode Go — that implies an OAuth flow that does not exist.

Do follow the same pattern community proxies use:

Source Variable / config Notes
Env (preferred) OPENCODE_API_KEY or CCP_OPENCODE_API_KEY Same key OpenCode integrations expect (ACP docs)
config.json opencode.apiKey Env wins over file (CCP precedence)
Optional convenience Read OpenCode’s ~/.local/share/opencode/auth.json Only if user already connected via OpenCode TUI; don’t require OpenCode install

Inbound vs outbound credentials (important):

  • Claude Code → CCP: ANTHROPIC_AUTH_TOKEN / ANTHROPIC_API_KEY can be dummy (unused, sk-test) — CCP does not validate these for upstream
  • CCP → OpenCode: real Authorization: Bearer <OPENCODE_API_KEY>

Proxy should fail fast when an OpenCode Go model is requested but no API key is configured (clear error: set OPENCODE_API_KEY or opencode.apiKey in config).

Optional CLI (not auth login):

claude-code-proxy opencode status   # key present? source (env/config/opencode-auth.json)?

No logout needed — unset env or remove config key.

Go vs Zen billing on one key

The same Zen workspace API key can access pay-as-you-go Zen models (zen/v1/*) and Go subscription models (zen/go/v1/*). They are different upstream bases and billing pools. v1 scope: Go endpoint only (zen/go/v1); Zen PAYG is a separate follow-up.

Proposed routing UX

Route via ANTHROPIC_MODEL with explicit Go model IDs, e.g.:

  • kimi-k2.7-code, kimi-k2.6
  • glm-5.2, glm-5.1
  • deepseek-v4-pro, deepseek-v4-flash
  • mimo-v2.5, mimo-v2.5-pro
  • minimax-m3, minimax-m2.7, minimax-m2.5
  • qwen3.7-max, qwen3.7-plus, qwen3.6-plus

Proxy behavior:

  1. Accept Anthropic Messages / streaming (+ count_tokens) from Claude Code
  2. Resolve model → chat/completions or messages upstream path under zen/go/v1
  3. Translate Anthropic ↔ OpenAI where needed; passthrough or light adapt for messages models
  4. Inject Authorization: Bearer <api_key> on upstream calls
  5. Reject unknown model IDs with HTTP 400 listing supported Go models

Catalog metadata: GET https://opencode.ai/zen/go/v1/models

Claude Code env example

OPENCODE_API_KEY=sk-... \
ANTHROPIC_BASE_URL=http://localhost:18765 \
ANTHROPIC_AUTH_TOKEN=unused \
ANTHROPIC_MODEL=kimi-k2.7-code \
ANTHROPIC_SMALL_FAST_MODEL=mimo-v2.5 \
CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC=1 \
CLAUDE_CODE_DISABLE_NONSTREAMING_FALLBACK=1 \
  claude

Or persist the key in ~/.config/claude-code-proxy/config.json:

{
  "opencode": {
    "apiKey": "sk-...",
    "baseUrl": "https://opencode.ai/zen/go/v1"
  }
}

ANTHROPIC_SMALL_FAST_MODEL should map to a cheap Go model — Claude Code emits background haiku-style requests that would 400 without it.

Optional follow-ups (out of scope for v1?)

Implementation sketch

src/providers/opencode/
  credentials.rs    # env > config.json > optional opencode auth.json
  client.rs         # HTTP to zen/go/v1/* with Bearer
  model.rs          # allowlist + EndpointKind { Messages, ChatCompletions }
  translate/        # reuse Kimi OpenAI path; thinner path for messages models

Registry: opencode provider; provider_for_model("kimi-k2.7-code") → opencode (distinct from existing kimi.com Kimi Code OAuth provider).

Config/env:

  • CCP_OPENCODE_API_KEY / OPENCODE_API_KEY
  • CCP_OPENCODE_BASE_URL default https://opencode.ai/zen/go/v1

No ProviderGroup auth subcommands unless we add a minimal opencode status later.

Prior art / references

Notes / caveats

  • Usage limits: dollar-based ($12 / 5h, $30 / week, $60 / month); surface upstream 429/limit errors clearly
  • One Go subscriber per workspace (OpenCode billing)
  • Model catalog may change
  • Skills / rules: Claude Code vs OpenCode harness mismatch — this FR is wire routing only
  • Reasoning / tool round-trips: per-model validation (Kimi/DeepSeek reasoning replay, strip thinking for non-reasoning models)
  • ocgo limitation: some community proxies only hit chat/completions — CCP should implement both Go endpoint families

Related issues

Happy to help test or send a PR.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions