Summary
Custom (no-auth) providers declared in V2 config under providers.<id> — such as a local
LM Studio server — are silently dropped if they do not define env and are not otherwise
registered as integrations. The /connect flow then offers only the three built-in hardcoded
LM Studio models instead of the user's configured server/models.
Environment
- opencode version: v1.17.20+ded9f87 (V2, via
nix run .#opencode2 - custom nix flake to run v2 binary)
- OS: Linux 7.1.3 (NixOS, x86_64)
- Terminal: TERM_PROGRAM=kgx, TERM=xterm-256color, COLORTERM=truecolor
- Shell: /run/current-system/sw/bin/zsh
- Install/channel: nix (local dev build from
dev)
- Active plugins: None configured
Reproduction
-
Configure a local LM Studio provider in ~/.config/opencode/opencode.jsonc:
(No env key — LM Studio is a local server and needs no API key.)
-
Launch opencode2 and run /connect.
-
Select LM Studio from the list.
-
Observe it only offers the three built-in models (openai/gpt-oss-20b,
qwen/qwen3-30b-a3b-2507, qwen/qwen3-coder-30b) pulled from ModelsDev — NOT the
qwen/qwen3.6-27b and google/gemma-4-26b-a4b-qat models defined in the user config.
Expected Behavior
- The user's
providers.lmstudio config (base URL, custom model list) should be picked up and
the configured models should appear in the model picker.
/connect for a no-auth local provider should surface the configured server rather than
silently ignoring it.
Actual Behavior
The configured lmstudio provider is discarded. Root cause appears to be the integration/catalog
transform in packages/core/src/config/plugin/provider.ts:
const configuredIntegrations = new Set(
files.flatMap((file) =>
Object.entries(file.info.providers ?? {}).flatMap(([id, provider]) =>
provider.env === undefined ? [] : [id],
),
),
)
for (const file of files) {
for (const [id, item] of Object.entries(file.info.providers ?? {})) {
const integrationID = id
if (!configuredIntegrations.has(id) && !integrations.get(integrationID)) continue // <-- drops no-auth providers
integrations.update(integrationID, ...)
...
catalog.provider.update(providerID, ...) // this never runs for lmstudio
...
}
}
Because lmstudio has no env, it is never added to configuredIntegrations, and there is no
pre-existing integration with that id, so the entire loop iteration is skipped — including the
catalog.provider.update(...) that would apply the config. Local/open-weight providers that need
no credential therefore cannot be configured through providers.<id>.
Additionally, the /connect provider-selection list (packages/opencode/src/cli/cmd/providers.ts)
is built only from ModelsDev + plugin providers and has no entry for user-configured custom
providers, so there is no path to authenticate/discover a locally-defined provider either.
Additional Context
- The V1→V2 config migration (
packages/core/src/v1/config/migrate.ts) correctly maps
provider.lmstudio → V2 providers.lmstudio (with package from npm and settings.baseURL
from api/options). The migrated config is loaded; the drop happens later in the
integration/catalog transform.
- The catalog
available() logic in packages/core/src/catalog.ts does support no-auth providers
(provider.integrationID === undefined && !integration → available), so the only blocker is the
env-gated continue.
- Workaround attempted: none effective. Adding a dummy
env array to the provider config makes it
appear in the integration list, but LM Studio does not use an API key, so this is not a real fix.
Summary
Custom (no-auth) providers declared in V2 config under
providers.<id>— such as a localLM Studio server — are silently dropped if they do not define
envand are not otherwiseregistered as integrations. The
/connectflow then offers only the three built-in hardcodedLM Studio models instead of the user's configured server/models.
Environment
nix run .#opencode2- custom nix flake to run v2 binary)dev)Reproduction
Configure a local LM Studio provider in
~/.config/opencode/opencode.jsonc:{ "providers": { "lmstudio": { "npm": "@ai-sdk/openai-compatible", "name": "Lm-Studio", "settings": { "baseURL": "http://localhost:1234/v1" }, "models": { "qwen/qwen3.6-27b": { "name": "QWEN 3.6 27b", "modelID": "qwen3.6-27b" }, "google/gemma-4-26b-a4b-qat": { "name": "Gemma 4 26B-A4B", "modelID": "gemma4-26b-a4b-qat" } } } } }(No
envkey — LM Studio is a local server and needs no API key.)Launch opencode2 and run
/connect.Select LM Studio from the list.
Observe it only offers the three built-in models (
openai/gpt-oss-20b,qwen/qwen3-30b-a3b-2507,qwen/qwen3-coder-30b) pulled from ModelsDev — NOT theqwen/qwen3.6-27bandgoogle/gemma-4-26b-a4b-qatmodels defined in the user config.Expected Behavior
providers.lmstudioconfig (base URL, custom model list) should be picked up andthe configured models should appear in the model picker.
/connectfor a no-auth local provider should surface the configured server rather thansilently ignoring it.
Actual Behavior
The configured
lmstudioprovider is discarded. Root cause appears to be the integration/catalogtransform in
packages/core/src/config/plugin/provider.ts:Because
lmstudiohas noenv, it is never added toconfiguredIntegrations, and there is nopre-existing integration with that id, so the entire loop iteration is skipped — including the
catalog.provider.update(...)that would apply the config. Local/open-weight providers that needno credential therefore cannot be configured through
providers.<id>.Additionally, the
/connectprovider-selection list (packages/opencode/src/cli/cmd/providers.ts)is built only from ModelsDev + plugin providers and has no entry for user-configured custom
providers, so there is no path to authenticate/discover a locally-defined provider either.
Additional Context
packages/core/src/v1/config/migrate.ts) correctly mapsprovider.lmstudio→ V2providers.lmstudio(withpackagefromnpmandsettings.baseURLfrom
api/options). The migrated config is loaded; the drop happens later in theintegration/catalog transform.
available()logic inpackages/core/src/catalog.tsdoes support no-auth providers(
provider.integrationID === undefined && !integration→ available), so the only blocker is theenv-gatedcontinue.envarray to the provider config makes itappear in the integration list, but LM Studio does not use an API key, so this is not a real fix.