# opencode-provider-switch (`ocswitch`) A tiny local proxy for [OpenCode](https://opencode.ai) that gives you **one stable model alias** routed to **multiple upstream providers** with **deterministic failover**. - Expose one custom provider `ocswitch` to OpenCode. - Configure logical aliases (`ocswitch/gpt-5.4`, etc.). - Each alias has an ordered list of upstream `provider/model` targets. - Providers can be disabled without mutating alias target state. - When the primary upstream returns `5xx`/`429`/connect error *before* any stream bytes are flushed, `ocswitch` transparently retries the next target. - Once a stream has started, the upstream is locked for the rest of that request — no mid-stream splicing. Protocol: OpenAI Responses (`POST /v1/responses`) only. Streaming supported. ## Install ```bash go build -o ocswitch ./cmd/ocswitch ``` ## Desktop GUI The repository also ships a Wails-based desktop control panel for managing providers, aliases, sync flows, and desktop preferences on Windows. Current desktop capabilities: - Sidebar tabs: `Overview` / `Providers` / `Aliases` / `Sync` / `Settings` - UI language preference: `en-US` / `zh-CN` / `system` - Theme preference: `light` / `dark` / `system` - Shared frontend between the desktop shell and the browser fallback shell ### Build the desktop executable Install frontend dependencies and verify the frontend build first: ```bash cd frontend npm install npm run build ``` Then build the desktop app from the repository root: ```bash wails build -tags desktop_wails ``` On Windows, the default output path is: ```text build/bin/ocswitch-desktop.exe ``` Note: - Windows 11 generally includes the WebView2 Runtime, and most mainstream Windows 10 devices already have it installed. - `ocswitch-desktop.exe` is distributed as a single-file artifact and does not require extra sidecar files in the same directory. - If the desktop app fails to start on Windows, one common cause is a missing WebView2 Runtime. Install the Microsoft Edge WebView2 Runtime and try again: https://developer.microsoft.com/microsoft-edge/webview2/ ### Development mode To run the desktop GUI in local development mode: ```bash wails dev -tags desktop_wails ``` ### Usage After launching the desktop app, you can: - inspect proxy state, config path, and doctor summary - manage providers with search, filtering, editing, and OpenCode import - manage aliases and target bindings - preview and apply `ocswitch opencode sync` - save desktop preferences including launch-at-login, tray behavior, notifications, theme, and language If you already built the executable, you can run it directly: ```bash ./build/bin/ocswitch-desktop.exe ``` ## Quick start ```bash # 1. add upstream providers (models are discovered from /v1/models by default; warnings do not block saving) ocswitch provider add --id su8 --base-url https://cn2.su8.codes/v1 --api-key sk-... ocswitch provider add --id codex --base-url https://api-vip.codex-for.me/v1 --api-key sk-... # 2. create alias and bind targets in priority order (preferred Provider/Model form) ocswitch alias add --name gpt-5.4 ocswitch alias bind --alias gpt-5.4 --model su8/gpt-5.4 ocswitch alias bind --alias gpt-5.4 --model codex/GPT-5.4 # 3. push alias exposure into OpenCode global config ocswitch opencode sync # optional: temporarily disable one provider without editing alias targets ocswitch provider disable su8 # 4. run the proxy ocswitch serve ``` Inside OpenCode you can now pick `ocswitch/gpt-5.4`. ### Import providers from an existing OpenCode config ```bash ocswitch provider import-opencode # reads global OpenCode config ocswitch provider import-opencode --from ./examples/opencode.jsonc ``` The default import/sync target is the global user config only. It does not follow `OPENCODE_CONFIG_DIR`; use `--from` or `--target` when you want a different file. Only `@ai-sdk/openai` custom providers with a `baseURL` are imported. An empty `apiKey` is allowed and kept as-is so you can complete credentials later. Imported provider model lists are preserved when the source config already declares `models`, and `provider add` will otherwise refresh them from `/v1/models` by default. Imported lists are kept for migration context, while hard typo validation only uses catalogs actively discovered from `/v1/models`. If connection details change but discovery is skipped, fails, or returns an empty list, any old catalog is retained only as untrusted metadata and no longer used for strict validation. ### Validate before serving ```bash ocswitch doctor ``` Runs structural checks only — never issues real upstream requests. Enabled aliases must have at least one **routable** target. A target is considered routable only when: - the alias itself is enabled - the target itself is enabled - the referenced provider exists - the referenced provider is not disabled `ocswitch opencode sync` and `/v1/models` use the same routable-alias view, so OpenCode does not see aliases that the proxy would immediately reject. ### Provider state ```bash ocswitch provider disable ocswitch provider enable ``` Disabling a provider only removes it from routing/failover consideration. It does **not** rewrite alias target `enabled` flags in config, which avoids odd interactions when the same provider is shared across multiple aliases. ## CLI reference For exact command behavior, defaults, write scope, and side effects, prefer the matching `--help` page. This README is the quick-start narrative, while CLI help is the authoritative local execution contract. - `ocswitch serve` — run the proxy - `ocswitch doctor` — validate config - `ocswitch provider {add,list,enable,disable,remove,import-opencode}` - `ocswitch alias {add,list,bind,unbind,remove}` - `ocswitch opencode sync [--target FILE] [--set-model ALIAS] [--set-small-model ALIAS] [--dry-run]` Preferred bind form: `ocswitch alias bind --alias --model /` when `--provider` is omitted. The legacy `--provider --model ` form is still accepted as a fallback, including models whose names already contain `/`. The same combined form also works for `alias unbind`. To clear a previously saved upstream API key, pass `--api-key ""` explicitly on `provider add`. To clear previously saved extra provider headers, pass `--clear-headers` on `provider add`. Global flag: `--config PATH` (default `$OCSWITCH_CONFIG`, else `$XDG_CONFIG_HOME/ocswitch/config.json`, else `~/.config/ocswitch/config.json`). ## Debug headers Responses include these debug headers once a concrete upstream attempt is being returned to the client: - `X-OCSWITCH-Alias` - `X-OCSWITCH-Provider` - `X-OCSWITCH-Remote-Model` - `X-OCSWITCH-Attempt` - `X-OCSWITCH-Failover-Count` ## Scope Out of MVP: Anthropic native, multi-protocol routing, dashboard, billing, latency-based routing, and full OpenCode config takeover. See `.trellis/tasks/archive/2026-04/04-17-04-17-ops-mvp-design-review/prd.md` for the authoritative design notes.