The OpenCode proxy layer on top of the generic core-proxy engine.
It provides opencodeProfile (the config filename, tier order/fallback,
tier regex, env-var prefix, default context/output limits, and the native
Anthropic-shaped 429 response that the engine needs) to route requests for
OpenCode. OpenCode consumes it by pointing an @ai-sdk/anthropic custom
provider's baseURL at the proxy, so it talks the Anthropic /v1/messages
format and expects the Anthropic-shaped error body on rate limit, the same
contract claude-code-proxy already serves for Claude Code.
This is a library repo consumed as a git submodule and bundled from
source (the same treatment as core / core-auth / core-loader /
core-proxy / claude-code-proxy), it is not published to npm.
This project carries no generic engine code; the routing engine
(:34567 daemon, tier→provider chains, rate-limit fallback, model rewrite,
the node↔web request adapter) lives entirely in core-proxy, nested here as
a submodule. opencode-proxy only supplies the OpenCode-specific profile
that parameterizes that engine.
core-proxy/: the generic routing engine, nested as a git submodule (compiled separately intocore-proxy/dist, excluded from this project's owntsconfig.json).src/profiles/opencode.ts:opencodeProfile(), the OpenCodeRoutingProfile(config file, tier order/fallback, tier regex, env prefix, default context/output,nativeRateLimit).src/index.ts: the public barrel, re-exports the entirecore-proxyAPI plusopencodeProfile, so consumers import everything from one place.dist/: compiled output (gitignored, never committed).
import { createProxyServer, makeDynamicResolver, opencodeProfile } from "./opencode-proxy/dist/index.js";
const profile = opencodeProfile();
const resolveHandler = makeDynamicResolver(() =>
listProviders().map((p) => ({ provider: p.provider, handlerPath: p.handlerPath }))
);
const server = createProxyServer({ configDir, profile, port: 34567, resolveHandler });
await server.listen();Once the proxy is running (dashboard-installed sidecar, listening on
:34567), OpenCode points a custom provider at it via an @ai-sdk/anthropic
baseURL override in its config, the same pattern already used by any
provider driver that sets opencodeNpm: "@ai-sdk/anthropic":
{
"provider": {
"opencode-proxy": {
"npm": "@ai-sdk/anthropic",
"options": { "baseURL": "http://127.0.0.1:34567" },
"models": {
"claude-opus-4": {},
"claude-sonnet-4": {},
"claude-haiku-4": {}
}
}
}
}Requests then flow: OpenCode → @ai-sdk/anthropic (Anthropic /v1/messages
wire format) → this proxy on :34567 → core-proxy's tier engine (tier
detection via tierRegex/tierOrder, rate-limit fallback across the tier's
provider chain, and, once every model in the chain is exhausted, the
Anthropic-shaped native 429 from opencodeProfile's nativeRateLimit) → the
underlying provider(s).
npm run build && npx vitest run builds the nested core-proxy engine
first, then this project's own src, then runs the opencodeProfile tests
plus a barrel smoke test asserting the re-exported surface.
MIT