Introducing opencode-aipass
A dynamic opencode plugin for aipass-proxy that discovers AIPass models from GET /v1/models at startup — no more hand-maintained models in opencode.json.
view .mdopen in claudeopen in chatgpt
I built aipass-proxy to expose AIPass through the OpenAI GET /v1/models and POST /v1/chat/completions endpoints. The first guide — Using aipass-proxy with opencode — showed how to wire it to opencode with a manual provider.aipass.models block in opencode.json.
That worked, but it had a flaw: you had to copy model IDs by hand, and they drifted. When AIPass added gpt-5.6-sol or renamed gemini-3.1-flash-lite, you had to edit the file again. opencode-aipass fixes that. It fetches the list from your local proxy and registers the provider for you.
Important Warning
Same warning as before. AIPass terms prohibit use of the platform API outside the official interface (section 3.4). This proxy — and the plugin that talks to it — uses the API outside that interface. AIPass can suspend your account. Not legal advice — read the terms before you use either project.
The problem with the old way
The original setup looked like this in opencode.json:
{
"$schema": "https://opencode.ai/config.json",
"provider": {
"aipass": {
"npm": "@ai-sdk/openai-compatible",
"name": "AIPass",
"options": {
"baseURL": "http://localhost:47871/v1",
"apiKey": "unused"
},
"models": {
"gemini-3.1-flash-lite": { "name": "Gemini 3.1 Flash Lite (Unlimited)" },
"claude-opus-5@azure": { "name": "Claude Opus 5" },
"gpt-5.6-terra": { "name": "GPT-5.6 Terra" }
}
}
}
}
Every key under models had to match an ID from GET /v1/models exactly. The proxy already knew the real list — you were just copying it. The plugin removes that duplication.
What the plugin does
opencode-aipass v0.1.1 is a provider plugin for opencode v2. On startup it calls GET /v1/models on your proxy, turns the response into Model.Info entries with tools: true (the proxy emulates tool calls via <tool_call>), and registers them with ctx.provider.transform. opencode then shows them in the picker as aipass/<model-id>.
It then keeps the list in sync:
- Polls
GET /v1/modelsevery 60 seconds. If the id set changed, it callsctx.provider.reload. - Persists the last good list in
ctx.storage. If the proxy is offline at next startup, it restores that cached list and logs a warning instead of showing nothing. - Exposes a manual refresh as command
aipass:refresh(TUI) and toolaipass_refresh(for agents).
You no longer edit opencode.json when AIPass ships a model.
Prerequisites
- aipass-proxy
v0.2.1installed and running athttp://localhost:47871(or your custom port). See the project page forcurl -sL https://fasu.dev/aipass-proxy | bash,aipass-proxy setup, andaipass-proxy start. - opencode v2 and
@opencode/plugin^2.0.8(peereffect^4.0.0-rc.112,zod^4.1.8).
Verify the proxy first:
curl http://localhost:47871/v1/models | head -c 500
If that returns {"data": [...]} you are ready for the plugin.
Install
Option A — Project-local (fastest, no publish)
This is how the aipass-proxy repo itself uses the plugin. Point opencode at the source file:
{
"$schema": "https://opencode.ai/config.json",
"plugins": ["./plugin/src/index.ts"],
"model": "aipass/gpt-5.6-sol"
}
Use this when you clone pyyupsk/aipass-proxy and want the plugin without publishing. The provider id is aipass and the model id is whatever the proxy returns — e.g. aipass/gpt-5.6-sol.
Option B — Published package
If you want the plugin in your own project without the proxy repo:
# one-time publish from the proxy repo
cd plugin && npm publish
# then in your project
opencode plugin add opencode-aipass
{
"$schema": "https://opencode.ai/config.json",
"plugins": ["opencode-aipass"],
"model": "aipass/gpt-5.6-sol"
}
Both options behave the same. Pick A for local dev, B for sharing across projects.
Options
You can override the defaults:
{
"plugins": [{
"package": "./plugin/src/index.ts",
"options": {
"baseURL": "http://localhost:47871/v1",
"name": "AIPass",
"refreshInterval": 60000,
"timeoutMs": 5000
}
}]
}
baseURL— proxy base URL. Defaulthttp://localhost:47871/v1.name— provider display name in opencode. DefaultAIPass.refreshInterval— ms betweenGET /v1/modelspolls. Default60000.timeoutMs— fetch timeout in ms. Default5000.
Change baseURL if you run the proxy on a different port or expose it on your LAN.
How it works (in 6 steps)
- Calls
GET {baseURL}/modelswithAbortSignal.timeout(timeoutMs). On failure, keeps the previous list and warns to console. - Builds a provider via
@opencode/ai/providers/openai-compatiblewithbaseURLandapiKey: "unused", advertisingcapabilities: { tools: true, input: ["text"], output: ["text"] }. - Registers with
ctx.provider.transform— this is what populates the model picker. - Persists
models.map(m => m.id)toctx.storage. On next cold start with proxy offline, restores from storage. - Every
refreshIntervalre-fetches and diffs id sets. Only callsctx.provider.reloadwhen the set actually changed (avoids noisy events). - Adds
aipass:refreshandaipass_refreshfor on-demand reloads (aipass: 23 models).
Source is ~130 lines in plugin/src/index.ts — easy to audit.
Try the refresh
In the opencode TUI, open the command palette and run aipass:refresh. From an agent, call the tool:
{ "tool": "aipass_refresh", "input": {} }
Response:
{ "content": "aipass: 23 models" }
Add a model in AIPass, run the command, and it appears without restarting opencode.
Migrate from the manual config
If you followed the first guide:
- Delete the entire
provider.aipassblock fromopencode.json(includingmodels). - Add the
pluginsentry from above. - Set
"model": "aipass/<id>"to any id fromcurl http://localhost:47871/v1/models. - Restart opencode. Run
aipass:refreshonce to prime the cache.
You can keep both configs side-by-side to compare, but the plugin will overwrite a manual aipass provider with the same id via editor.remove(providerID) before editor.add.
When not to use the plugin
- Proxy not at
http://localhost:47871and you do not want to setbaseURL. - You want a curated subset of models, not the full AIPass list. The plugin registers everything the proxy returns; manual
modelslets you hide entries. - Offline-first setups where
GET /v1/modelsis never reachable and you prefer an explicit list over a cached one.
Ideas once it is running
Same ideas from the first post, now with less friction:
- Pin
aipass/gemini-3.1-flash-liteas your default for quick edits; switch toaipass/claude-opus-5@azureoraipass/gpt-5.6-solfor planning. - Test Thai-specific models without editing config — they just appear when AIPass makes them available.
- Run
aipass-proxy install-serviceon a home server and point every machine’sbaseURLat that host. One plugin, one proxy, every device in sync.
Where to find it
- Proxy: pyyupsk/aipass-proxy — see also /projects/aipass-proxy
- Plugin: pyyupsk/aipass-proxy/tree/main/plugin (
opencode-aipassv0.1.1on npm aftercd plugin && npm publish) - Previous guide: Using aipass-proxy with opencode
- Plugin package:
plugin/package.json
OpenAI-compatible chat-completions proxy in front of AIPass (https://de.aipass.net)
★ 0 · ⑂ 0 · TypeScript