@cognitionai/opencode-devin
v0.3.0
Published
OpenCode plugin: log in with Devin and use Devin's AI Gateway
Downloads
601
Readme
opencode-devin
opencode plugin that adds Devin as a provider:
/connect→ Devin logs you in with the same browser PKCE flow as the Devin CLI (chisel) and stores the resulting session token as an opencode credential. No API key to copy.- Registers a
devinprovider backed by Devin's OpenAI-compatible gateway (server.codeium.com/api/v1, the same api-server chisel talks to). - Populates the model list from
GET /api/v1/modelsfor your account instead of a static catalog — nomodels.deventry required.
Works with opencode 2.x (the v2 plugin API) and opencode 1.3.4 or newer (the v1 hooks API) from one package: the
default export carries both setup() and server(), and opencode calls the one for its own version.
opencode 1.0 – 1.3.3 cannot load this version. Those releases call every export of a plugin module as a function, so the combined object export fails with
failed to load plugin … is not a functionand thedevinprovider never appears. Either upgrade opencode or pin the previous release:"plugin": ["@cognitionai/[email protected]"]. (The upstream migration guide documents this export shape for opencode ≥ 1.18.29; the loader support goes back to 1.3.4, verified live on 1.3.4, 1.4.14, 1.18.25 and 1.18.32.)
Install
opencode.json (project or ~/.config/opencode/opencode.json):
{
"$schema": "https://opencode.ai/config.json",
"plugins": ["@cognitionai/opencode-devin"], // opencode 2.x
}On opencode 1.x the key is plugin (singular) instead: "plugin": ["@cognitionai/opencode-devin"].
To run from a checkout instead, see DEVELOPMENT.md.

Then in opencode run /connect, pick Devin, and choose Log in with Devin (browser) (or paste code on a
headless machine). After login the model list refreshes and devin/<model> shows up in /models. Alternatively
pick API key and paste a Devin service key (cog_...) — that is what the gateway's own API consumers use.
Endpoints
Login and inference live on different hosts, mirroring chisel:
| Deployment | Webapp (login page) | Auth API (/auth/cli/token) | Inference gateway (/api/v1/*) |
| ---------- | ---------------------- | ---------------------------- | ------------------------------- |
| production | https://app.devin.ai | https://api.devin.ai | https://server.codeium.com |
| custom | prompted | derived (api.<domain>) | https://server.codeium.com |
The login prompt lets you pick the default (production) or a custom deployment, and only asks for the webapp URL;
the other two are derived like chisel does (dedicated tenants share the production gateway). For development, the
derived endpoints can be overridden via plugin options (webapp, api, inference) or env vars: DEVIN_WEBAPP_URL,
DEVIN_API_URL, and DEVIN_INFERENCE_URL (chisel's WINDSURF_API_SERVER_URL is honoured too).
{
"plugins": [
{ "package": "@cognitionai/opencode-devin", "options": { "webapp": "https://acme.devinenterprise.com" } },
],
}(opencode 1.x: "plugin": [["@cognitionai/opencode-devin", { "webapp": "..." }]].)
Browser and paste-code logins record their inference gateway on the credential (baseURL metadata); the plugin
reads it back and publishes it as the provider baseURL, so requests always go to the deployment you logged in to.
A pasted key uses the configured gateway.
How it works
The plugin registers everything through opencode's v2 plugin context at setup():
| Registration | What happens |
| ----------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| integration.transform | Adds the Devin integration with three methods. Browser: loopback server on 127.0.0.1:<random>/callback + {webapp}/auth/cli/continue?...code_challenge=S256, 10-minute timeout, state check. Paste-code: same URL without redirect_uri. Key: paste a session token or cog_... service key. |
| token exchange | POST {api_url}/auth/cli/token {code, code_verifier} → stored as an OAuth credential whose access token is devin-session-token$<jwt> (sent as the bearer key). Devin's session token has no refresh flow; a 401 means run /connect again. |
| provider.transform | Publishes provider.devin (@opencode/ai/providers/openai-compatible, baseURL: {inference_url}/api/v1) with the current model list, bound to the active Devin connection (sourceConnection) so a list fetched for one login is never shown for another. |
| model refresh | At startup and on every credential.switched / credential.updated event, resolves the active Devin credential, fetches GET {inference_url}/api/v1/models (cached for an hour in $XDG_CACHE_HOME/devin-opencode/models.json), converts max_input_tokens / max_output_tokens / available_variants (→ variants, each routing to its uid) / families, then calls provider.reload(). Fallback: cache → a single built-in claude-sonnet-4.5. |
On opencode 1.x the same flow runs through the v1 hooks (config, auth, provider.models, chat.params): the
provider is injected at startup from the model list fetched with the credential in auth.json, and the cache is
scoped to a fingerprint of that credential.
Seeing only devin/claude-sonnet-4.5 means the model fetch failed and nothing is cached: check
curl -H "Authorization: Bearer $KEY" https://server.codeium.com/api/v1/models with your key, then restart opencode.
Development
See DEVELOPMENT.md.
