VS Code BYOK: run Copilot Chat on any model (2026)

By Jose Sabater -

TL;DR: We published an Opper extension for VS Code. It adds Opper's 700+ models to the VS Code chat model picker, plus your pools and dynamic routes. Agent mode included. No Copilot subscription, no GitHub sign-in.

code --install-extension opperai.opper-vscode

Then run Opper: Manage API Key from the command palette and paste a key from platform.opper.ai.


What BYOK means in VS Code now

VS Code 1.104 stabilised the Language Model Chat Provider API, and it changed the bring-your-own-key story in two ways worth knowing before you pick an approach.

First, models contributed this way don't require a Copilot plan. Chat and agent mode run on the model you brought, without a subscription and without signing in to GitHub. (Inline completions still belong to Copilot; this is about chat.)

Second, there are now two ways to bring a model in:

  • Custom Endpoint. Built into VS Code. You paste a base URL and a key, then hand-type every model id you want to use. Fine for two or three models. Painful past that, and it can't know what your key is actually allowed to reach.
  • A provider extension. One that implements the API and discovers models at runtime. The picker fills itself, and the extension can show things a bare endpoint can't: where a model is hosted, whether it retains data, whether it's a single model or a load-balancing pool.

The Opper extension is the second kind.

Install the Opper extension for VS Code

  1. Install it from the Marketplace, or run code --install-extension opperai.opper-vscode. VS Code 1.104 or later.
  2. Run Opper: Manage API Key and paste a key from platform.opper.ai. It goes into VS Code's SecretStorage, never into settings.json, so it won't ride along into a synced or committed settings file.
  3. Open Chat, click the model picker, and pick an Opper model.

Nothing is listed until there's a key, because the list is scoped to it.

What lands in the model picker

Three kinds of entry, and the distinction matters more than it looks:

EntryWhat it is
ModelOne model on one provider, e.g. gcp/claude-sonnet-4-5-eu. You know exactly who serves it and from where.
PoolA bare name like claude-sonnet-4-5 that load-balances across every provider serving that model, and falls back when one of them rate-limits or goes down.
Dynamic routeOne of your own deployed routing graphs, as dynamic/<name>. The graph decides which model handles each request: cheap model for the easy turns, frontier model when it matters.

Pools and dynamic routes are the reason a provider extension beats a hand-typed endpoint: neither one is a model id you could have guessed, and both are specific to your project.

Each entry's detail line carries its region and whether it's zero-data-retention, so the choice is visible at the moment you make it rather than buried in a catalog somewhere. The full list of what's available is in the model directory.

Narrow the list to EU or ZDR models

700+ entries is a lot of scrolling. Everything below is a normal VS Code setting:

SettingDefaultWhat it does
opper.euOnlyfalseEU-hosted models only.
opper.zdrOnlyfalseZero-data-retention models only.
opper.modelFilter[]Substrings to narrow a long list.
opper.showModelstrueList concrete models.
opper.showPoolstrueList load-balancing names.
opper.showDynamicRoutestrueList your deployed routes.

For the kind toggles there's a faster path: the gear next to Opper in the model picker → Choose what to list…. Untick Models and you're left with just your pools and routes, which is how most people end up using it day to day.

Worth saying plainly: discovery is filtered server-side by your project's compliance rules. A model your policy denies is never offered in the picker in the first place. You can't accidentally pick it, and you don't have to trust the client to enforce anything.

Custom Endpoint vs. a provider extension

Custom EndpointOpper extension
Model idsTyped by hand, one at a timeDiscovered at runtime
Pools and dynamic routesNot reachableIn the picker
Region / ZDR visibleNoOn each entry
Scoped to your policyNoServer-side
Copilot plan requiredNoNo

If you're already on the Custom Endpoint route (see the GitHub Copilot setup page), it keeps working. The extension just removes the copy-pasting.

Troubleshooting

The picker is empty. No key is stored. Run Opper: Manage API Key.

I'm seeing models from the wrong project. Compliance rules are scoped to the key's project, so a key pointing somewhere unexpected looks like a filtering bug. The gear menu leads with Opper · <org> · project <name> · N models, and that line is the fastest way to spot it. If you have OPPER_API_KEY exported in your shell it's used only when no key is stored, and the line says so when it is.

Agent mode won't use my dynamic route. Opper can't know ahead of time whether a route supports tool calling, because the graph decides per request. opper.dynamicRouteToolCalling is a promise you make on the route's behalf; turn it off if a route can land on a model without tool support.

Discovery works but the first message fails. Check whether the project is blocked on spend. Listing models and spending on them are different permissions, so the picker looks healthy right up until you send something.

Get started

Grab a key at opper.ai, install the extension, and pick a model. The extension is MIT-licensed and the source is on GitHub.

Same idea, other tools: Claude Code, Codex CLI, and Claude Cowork all route through the same gateway. Questions? Find us on Discord or drop us a line at hello@opper.ai.