npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

opencode-devin

v0.2.0

Published

OpenCode v2 plugin: connect your Devin subscription to opencode with native /connect login and devin/* models

Readme

opencode-devin

OpenCode v2 plugin that connects your Devin subscription to OpenCode:

  • Native /connect integration — log in with Devin straight from the OpenCode TUI using the same browser PKCE flow as the Devin CLI. The credential is stored in OpenCode's own auth store; no config files or API keys to copy.
  • devin/* models in /models — the live, per-account catalog (SWE, Claude Opus, GPT, Gemini, Grok, Kimi and more, with reasoning-effort and speed variants), streamed from Cognition's Cascade inference API.

Requires OpenCode v2. This plugin targets the v2 plugin API (Plugin.define). The official @cognitionai/opencode-devin plugin is v1-only at the time of writing and does not load on v2.

Install

Add the plugin to opencode.json (project or ~/.config/opencode/opencode.json):

{
  "$schema": "https://opencode.ai/config.json",
  "plugins": ["opencode-devin"]
}

OpenCode installs it automatically on the next start.

Connect

Start OpenCode, run /connect, pick Devin, then choose a method:

| Method | How it works | Best for | | --- | --- | --- | | Log in with Devin (browser) | Opens the Devin sign-in page (PKCE + S256) and captures the authorization code through a local loopback callback. | Interactive terminals | | Paste code (headless) | Opens the same login page without a redirect; the page shows a code to copy and paste back into the TUI. | Headless machines, SSH | | DEVIN_LLM_API_KEY | Reads a devin-session-token$... token from the environment. | CI, scripting |

After connecting, the model list refreshes automatically and devin/<model> entries appear in /models.

Environment variable alternative

Skip /connect entirely:

export DEVIN_LLM_API_KEY=devin-session-token$your_token_here

Use

Pick any devin/ model in the /models picker, or set a default:

// opencode.json
{
  "model": "devin/swe-2-max"
}

From the CLI:

opencode run --model devin/swe-2-max "Refactor the auth module"

How it works

flowchart TD
    subgraph Login["Login — /connect"]
        A["/connect → Log in with Devin"] --> B["app.devin.ai/auth/cli/continue<br/>PKCE + S256, loopback callback on 127.0.0.1"]
        B --> C["api.devin.ai/auth/cli/token"]
        C --> D[("devin-session-token$JWT<br/>stored as an OpenCode credential")]
    end

    subgraph Catalog["Catalog — /models"]
        D --> E["GetCascadeModelConfigs (gRPC)<br/>live per-account model list"]
        E --> F["devin/* models"]
    end

    subgraph Chat["Chat — agent loop"]
        D --> G["GetUserJwt → short-lived user_jwt"]
        G --> H["GetChatMessage<br/>Cascade gRPC streaming"]
    end

    D -. "credential events → re-publish" .-> Catalog
  1. Integration — the plugin registers a devin integration with the Devin CLI login flow: PKCE (S256) against app.devin.ai/auth/cli/continue, a loopback callback on 127.0.0.1 (or manual code paste), and a token exchange at api.devin.ai/auth/cli/token.
  2. Catalog — model families come from Cognition's Cascade API for the logged-in account (the same source the Devin CLI uses). The OpenAI-compatible REST gateway (/api/v1) is not provisioned for most accounts, so chat streams through Cascade gRPC instead.
  3. Provider — the plugin publishes a devin provider whose package specifier self-references the plugin's own installed location (aisdk:<this-package>), so OpenCode's dynamic AI-SDK loader imports it directly with no registry round-trip — both from a repo checkout during development and from the npm cache once installed. Its LanguageModelV3 implementation lives in src/protocol/: a short-lived user_jwt is minted per session (GetUserJwt) and chat streams through GetChatMessage.
  4. Reactivity — the inventory re-publishes whenever a credential is connected, switched, or removed, so connecting mid-session updates /models without a restart.

Troubleshooting

  • No devin/ models: run /connect again. Failures are logged as [opencode-devin] ...; the log is at ~/.local/share/opencode/log/opencode.log.
  • A model is rejected even though /models lists it: the account can see a uid it is not entitled to. The error names the tier.
  • Costs look wrong or absent: OpenCode reads cost from the pricing published to /models, not from the stream. Check the model has a non-zero price there.
  • A 401 during chat: the short-lived token is refreshed automatically. Reconnect only if the session token itself was revoked.
  • Plugin failed to load: rebuild and opencode reload. See the FAQ on atomic builds.
  • A path in plugins is ignored: only name@file:<absolute-path> links a local build.

Development

bun install
npm run typecheck
bun test
npm run build

build is atomic, so the plugin can be reloaded while it runs. Publishing uses build:clean, which wipes dist/ first.

Developing against a local build

Edit plugins in ~/.config/opencode/opencode.json to one of these, then run npm run build && opencode reload:

// this repository
{ "plugins": ["opencode-devin@file:C:/path/to/opencode-devin"] }

// the published package
{ "plugins": ["opencode-devin"] }

The path must be absolute, and the name@file: form is required: a bare path or a file:// URL is ignored without an error.

To confirm which copy the server loaded:

opencode api provider.list   # the devin provider's "package" field

Testing against the real API

bun test runs everything except the live suite, which skips itself without a credential:

DEVIN_LLM_API_KEY='devin-session-token$...' bun test test/live.test.ts

FAQ

Why is build atomic? OpenCode reloads a linked plugin the moment its entrypoint changes, and a failed load is not retried. Writing dist/ in place lets a reload land mid-write and fail, which shows up as ENOENT reading dist/index.js or Cannot find module '.../constants.js'. build compiles to a staging directory and swaps it in.

Why a second protobuf implementation in the tests? The suite encodes and decodes with the same module, which only proves the two halves agree — they could both be wrong. wire-conformance.test.ts checks the framing against protobufjs, which shares no code with this repository. It is a dev-only dependency.

What the tests cannot check. The Cascade field numbers were recovered by reverse-engineering the Devin CLI. Only test/live.test.ts, which talks to Cognition, can notice them changing. All three RPCs have been exercised against the live API, but nothing guards a future upstream change; a committed capture of real responses would, and there is not one yet.

Why doesn't a missing model fail immediately? Because the catalog is not guaranteed to list every uid Cascade accepts, and refusing one that works would be worse than a vague error. Disabled models are refused outright; unknown ones are warned about, and the likely reason is appended if the request fails.

Why is the session token in the provider registry? It is passed as settings.apiKey, which is how the provider receives it. opencode api provider.list therefore returns it in clear text. Treat that output as a secret.

Credits

  • The Cascade protocol client is a typed TypeScript port, owned in src/protocol/ (see ATTRIBUTION.md) — originally from ai-sdk-devin by karthiknish and pi-devin-auth by nmzpy, both MIT. Owning the port keeps the credential path free of third-party runtime dependencies.
  • @cognitionai/opencode-devin — reference for the Devin CLI PKCE login flow.

License

MIT