You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
acp: session/new catalog ignores config providers, agents, and default model since 2.0.4 #50236
Since v2.0.4, opencode acp stops loading user configuration when building the session/new catalog (the configOptions list). Custom providers (e.g. Ollama), custom agents/modes, and the configured default model are missing; ACP clients like Zed only get built-in models (opencode/*, Google) and the default build/plan modes.
Works on 2.0.3 (global and project config both honored).
Broken identically on 2.0.4, 2.0.6, 2.0.11.
Plugins
None. Config only: ~/.config/opencode/opencode.json with provider.ollama (baseURL http://localhost:11434/v1), a non-default model, and custom primary agents (~/.config/opencode/agents/*.md). Ollama daemon confirmed running at localhost:11434.
OpenCode version
2.0.4 / 2.0.6 / 2.0.11 (regression); 2.0.3 working
Steps to reproduce
Configure the Ollama provider + models + a custom primary agent as above.
Pipe a raw ACP handshake into opencode acp:
send JSON-RPC initialize, then session/new with cwd = the project directory (machine has Ollama running).
Inspect configOptions in the session/new response.
Expected id: "model" options include the Ollama models and currentValue equals the configured default; id: "mode" includes the custom agent.
Actual: 45 built-in models only, default falls back to google/gemini-3.8-flash, modes are build + plan.
Screenshot and/or share link
N/A — raw ACP probe output available on request.
Operating System
macOS (Darwin, arm64)
Terminal
Bare stdio JSON-RPC probe (also reproducible from Zed's agent panel / any ACP client)
refactor(protocol): remove plugin activation wait — deletes client.plugin.awaitActivation({ location }) from loadCatalog() in packages/cli/src/acp/service.ts; replaced by a 5 s poll that exits on the first enabled model, so config-sourced providers lose the race.
refactor(core): split provider and model registries (#48901) — provider visibility is gated on provider.activation === "enabled"; the built-in Ollama plugin only sets that after an async GET /api/tags discovery round, which never completes before the ACP poll exits.
I'll take this. The regression is between 2.0.3 and 2.0.4 — configOptions / catalog loses user config when the session comes in via ACP. The v2.0.4 boundary lines up with the session/prompt module split, so I expect the leak to be in the ACP-driven session bootstrap (likely somewhere around packages/opencode/src/acp/... plus the session/new handler in core) where the per-location config resolution was wired to the runtime location.
Plan: locate the session/new request handler for ACP, check what config it loads vs what the non-ACP server bootstrap loads, and either thread the missing entries or fix the location resolution. I'll add a regression test that drives a session/new with a non-default provider + a custom agent and asserts configOptions contains them.
Polling GET /api/model on a fresh opencode serve shows the catalog filling in over ~50ms: 0 → 74 (raw Zen) → 7 (free Zen) → 8 (+weave/auto) on 2.0.14, and 0 → 7 → 8 on 2.0.5. /api/model/default reads as a Zen model until the last stage, so the "default model must be present" check in the catalog poll doesn't hold it either. In 24 ACP session/new probes across both versions, weave/auto was never in configOptions. After ~2s, /api/model for the same directory lists it. On 2.0.3 the same config works 9/9.
Two details that make this hard to work around client-side:
The catalog is cached per cwd for the connection's lifetime, and no config_option_update is sent when models change.
session/set_config_option with model=weave/auto is rejected with model not found, so a client can't select the provider even if it discovers it some other way.
Things that don't help: disabled_providers: ["opencode"] or enabled_providers: [...] (applied in the same late stage), or delaying session/new.
This also breaks Conductor, which bundles opencode 2.0.5 as its managed ACP harness, so config-defined providers never show up in its model picker. #50619's approach of waiting for activation before reading the catalog looks like the right fix. Happy to test it against this setup.
Have the same issue as well - it completely ignores my llama-server models and shows only cloud and lmstudio ones (and I'm using neither). Before V2 migration everything was fine.
Confirming this still reproduces on 2.0.16 (npm @opencode/cli, macOS arm64 — installed 2026-09-25). The highest version reported in this thread so far was 2.0.14, so the regression is still present in the latest release.
Setup here is a config-only OpenAI-compatible provider (no discovery plugin, no Ollama, no auth.json entry): provider.<id> in ~/.config/opencode/opencode.json with npm: "@ai-sdk/openai-compatible", inline options.apiKey/baseURL, and an explicit models map.
Observed on 2.0.16:
ACP session/new → configOptions[model].options contains zero models from that provider, and currentValue falls back to a built-in (opencode/*, or xiaomi/* on a setup with other credentials stored).
session/set_config_option with model=<provider>/<model> → -32602 Invalid params: model not found: <provider>/<model> (data.providerId is parsed correctly), so a client cannot select the provider even when it knows the id.
Same build, same config: opencode models lists the provider's models and opencode run --model <provider>/<model> answers normally — ACP catalog only.
List size is not stable across runs with an identical config: 7 / 8 / 17 / 19 / 20 options observed in isolated XDG_* sandboxes, and 95 (= providers from the models.dev catalog with stored credentials) on a long-lived setup. That matches the "poll exits before config-sourced providers activate" diagnosis above.
Client impact worth noting: an ACP client (Obsidian's Grimoire plugin) renders the model not found error as "The selected OpenCode model is unavailable for this account or plan. Choose another model, then retry.", which sends users chasing billing/plan issues instead of this bug.
Client-side workarounds: none for config-declared providers. Selecting a model that is in the catalog works in the same session, and the CLI is unaffected.
Extra data point that isolates this to the ACP catalog loader rather than config loading: on 2.0.16 (macOS arm64), with an intact config containing a config-declared OpenAI-compatible provider, the HTTP API and ACP disagree at the same moment:
GET /api/model → 38 models including the provider's 5 ({opencode: 8, xiaomi: 6, openai: 15, deepseek: 4, <custom>: 5}), and GET /api/provider lists the custom provider with activation: "enabled".
opencode acp → session/new immediately after → configOptions[model].options = 95 models from github-copilot / openai / xiaomi only, custom provider absent (reproduced twice, ~2 min apart).
So config loading and provider activation do complete for the server; only the ACP catalog snapshot misses them (or misses them most of the time — the same probes returned 7 / 8 / 17 / 19 / 20 / 95 entries depending on run, which is why I think the poll-exit timing is the deciding factor rather than any file/config difference).
Worth noting for anyone debugging: opencode reload or a service restart does not change the ACP result, but the server's /api/model picks the provider up right away.
Adding two data points that extend @munir-weave's timing analysis and sharpen the failure signature for @holny's fix (repro details below, raw JSON-RPC against opencode acp, no third-party client — consistent with the snapshot-timing finding: the catalog the ACP layer serves looks like a pre-config-merge snapshot, which is why only bare upstream ids and the generic effort ladder appear).
1. Set-accepts / prompt-rejects split.session/set_config_option with a generic effort value (high from the advertised none/minimal/low/medium/high/default ladder) is accepted and stored on the session — then the prompt-time resolver rejects the same ref against the config-merged catalog:
So a host that picks only from advertised options — protocol-correct behavior — still produces a session that fails at first prompt, surfaced as a generic provider.no-route error rather than invalid-params. Same root as #50378. A regression test for the fix should assert not only that configOptions contains the config-defined entries, but that a set-then-prompt using advertised values succeeds.
2. A verified workaround (no fix required): make the config coincide with what the pre-merge snapshot advertises — bare upstream model ids, variant ids renamed to the generic ladder, same reasoningEffort values:
Verified end-to-end on 2.0.16: after this change, sessions selected entirely from advertised options resolve and prompt.
Environment: opencode 2.0.16, macOS 15 arm64 (official bun binary), config-only OpenAI-compatible providers (aisdk:@ai-sdk/openai-compatible, suffixed ids like deepseek-v4.1-flash:cloud, custom variant names thinking/low-effort/max-effort — all resolvable in the TUI). The original failure was observed through an ACP desktop host as provider.no-route cards at first prompt.
Adding a data point that may explain why this looks like a v2 login requirement, since that is the conclusion the behavior invites — it is not one.
On 2.0.16, with no Zen credential anywhere (no OPENCODE_API_KEY in the environment, nothing Zen-related in opencode auth list, global ~/.config/opencode/opencode.jsonc containing only $schema):
opencode run -m opencode/space-bunny-free "say hi" in a project directory → answers normally, as > <agent> · space-bunny-free.
opencode acp in that same directory → the model session option contains zeroopencode/* entries, and a new session comes up on the "newest available supported model" from an unrelated provider instead.
So the free Zen models are reachable without any credential (they also answer a plain POST https://opencode.ai/zen/v1/chat/completions with no Authorization header), but the ACP catalog never lists them.
Setting OPENCODE_API_KEY to a dummy value makes the opencode/* and opencode-go/* entries appear in the catalog and the configured model pin get honored — session/new then reports currentModelId=opencode-go/space-bunny-free — but every prompt fails with:
even though that same model is the one that just worked unauthenticated over plain HTTP. That points at a client-side credential gate in the catalog/availability path rather than at anything the endpoint requires.
Asking for either of these would make the failure much easier to act on:
treat a provider as available when the model is actually reachable, not only when a credential is stored (or let the catalog include keyless-reachable free models), and
when a configured model is dropped for a fallback, say why in the session result or a log line, so a working pin failing to apply does not look like a policy change.
Context: hit this through acp-chat-sloppy-bridge 0.7.0 driving opencode acp over stdio, where the user-visible symptom is "the bot answers its own messages but the agent never replies".
Still reproduces on 2.0.18 (npm @opencode/cli-linux-x64, Linux x64). The setup is opencode acp over stdio with a config-only OpenAI-compatible provider and a top-level model. Some details that may matter for #50619 and for anyone who needs a workaround now:
It's intermittent, not deterministic. Across our runs, about half of the fresh opencode acp processes came up with a Zen-only catalog. In those, currentValue was an opencode/*-free model and none of the config provider's models were listed. The other half came up correct.
A bad snapshot sticks for the life of the process.catalog(cwd) in packages/cli/src/acp/service.ts caches the loadCatalog promise per cwd. Every later session/new or session/load in the same process reuses the stale catalog. session/set_config_option for a config model then fails with Invalid params: model not found: <provider>/<model>, and the prompt runs on the Zen fallback. Retrying the session in the same process never recovers.
experimental.policies doesn't help. We added provider.use deny * and allow <provider>. It removes the Zen models from GET /api/model once the process is warm, but the ACP snapshot is taken before the policy transform applies, so the same race still happens.
Workaround (client side): after session/new/session/load, check that configOptions[model].options contains the expected models. If they're missing, kill the process and spawn a new one. In practice it converges within a few restarts, about 1 s each. The rejected attempts leave empty sessions behind in the session list.
Update — a better workaround without respawning: the catalog snapshot happens right after the first request boots the location. The config provider arrives 0.3–0.6 s later, and the bundled models.dev catalog already has Zen models, so the poll exits at once. Emptying the built-in catalog removes the race:
With no built-in models, loadCatalog keeps polling until the config provider shows up. Result: 8/8 fresh processes and 4 concurrent ones all came up with the correct catalog and default model, with no retries. Obviously only an option when every model comes from config providers.
I am required to use OpenCode v2 (acp) in Xcode 27 set up with a locally-hosted offline-only Ollama provider and a model configured.
If OpenCode acp cannot be set up with locally-hosted offline-only models, and instead uses the free models, I cannot use it at all.
~/.config/opencode/opencode.jsonc:
In Xcode 27, the opencode executable is set, and the argument acp is provided; otherwise nothing is set — no environment variables. I'm keen to learn if there is any workaround, e.g. via the environment variables instead of via the config file, to get opencode acp to use Ollama.
Fixed by #52286 (merged in 1844c11): ACP no longer pins agent/model from an early catalog snapshot on session/new, and it refreshes the catalog (pushing config_option_update / available_commands_update) when plugins finish loading config agents, providers, and commands. It also reloads the catalog before rejecting an unknown model or mode in set_config_option / set_mode. Please reopen if you still see this on a release that includes the fix.
Activity
draftseventhirty commentedon Sep 21, 2026
i have this issue as well on 2.0.12 when trying to access a custom openAI provider through Zed
holny commentedon Sep 22, 2026
I'll take this. The regression is between 2.0.3 and 2.0.4 — configOptions / catalog loses user config when the session comes in via ACP. The v2.0.4 boundary lines up with the session/prompt module split, so I expect the leak to be in the ACP-driven session bootstrap (likely somewhere around
packages/opencode/src/acp/...plus the session/new handler in core) where the per-location config resolution was wired to the runtime location.Plan: locate the session/new request handler for ACP, check what config it loads vs what the non-ACP server bootstrap loads, and either thread the missing entries or fix the location resolution. I'll add a regression test that drives a session/new with a non-default provider + a custom agent and asserts configOptions contains them.
Fixes #50236
munir-weave commentedon Sep 22, 2026
Confirming on 2.0.5 and 2.0.14 (macOS arm64) with a plain config-only provider, with no discovery plugin involved:
Polling
GET /api/modelon a freshopencode serveshows the catalog filling in over ~50ms:0 → 74 (raw Zen) → 7 (free Zen) → 8 (+weave/auto)on 2.0.14, and0 → 7 → 8on 2.0.5./api/model/defaultreads as a Zen model until the last stage, so the "default model must be present" check in the catalog poll doesn't hold it either. In 24 ACPsession/newprobes across both versions,weave/autowas never inconfigOptions. After ~2s,/api/modelfor the same directory lists it. On 2.0.3 the same config works 9/9.Two details that make this hard to work around client-side:
cwdfor the connection's lifetime, and noconfig_option_updateis sent when models change.session/set_config_optionwithmodel=weave/autois rejected withmodel not found, so a client can't select the provider even if it discovers it some other way.Things that don't help:
disabled_providers: ["opencode"]orenabled_providers: [...](applied in the same late stage), or delayingsession/new.This also breaks Conductor, which bundles opencode 2.0.5 as its managed ACP harness, so config-defined providers never show up in its model picker. #50619's approach of waiting for activation before reading the catalog looks like the right fix. Happy to test it against this setup.
igorkis-scrts commentedon Sep 24, 2026
Have the same issue as well - it completely ignores my llama-server models and shows only cloud and lmstudio ones (and I'm using neither). Before V2 migration everything was fine.

HuHong-Tao commentedon Sep 25, 2026
Confirming this still reproduces on 2.0.16 (npm
@opencode/cli, macOS arm64 — installed 2026-09-25). The highest version reported in this thread so far was 2.0.14, so the regression is still present in the latest release.Setup here is a config-only OpenAI-compatible provider (no discovery plugin, no Ollama, no
auth.jsonentry):provider.<id>in~/.config/opencode/opencode.jsonwithnpm: "@ai-sdk/openai-compatible", inlineoptions.apiKey/baseURL, and an explicitmodelsmap.Observed on 2.0.16:
session/new→configOptions[model].optionscontains zero models from that provider, andcurrentValuefalls back to a built-in (opencode/*, orxiaomi/*on a setup with other credentials stored).session/set_config_optionwithmodel=<provider>/<model>→-32602 Invalid params: model not found: <provider>/<model>(data.providerIdis parsed correctly), so a client cannot select the provider even when it knows the id.opencode modelslists the provider's models andopencode run --model <provider>/<model>answers normally — ACP catalog only.XDG_*sandboxes, and 95 (= providers from the models.dev catalog with stored credentials) on a long-lived setup. That matches the "poll exits before config-sourced providers activate" diagnosis above.Client impact worth noting: an ACP client (Obsidian's Grimoire plugin) renders the
model not founderror as "The selected OpenCode model is unavailable for this account or plan. Choose another model, then retry.", which sends users chasing billing/plan issues instead of this bug.Client-side workarounds: none for config-declared providers. Selecting a model that is in the catalog works in the same session, and the CLI is unaffected.
HuHong-Tao commentedon Sep 25, 2026
Extra data point that isolates this to the ACP catalog loader rather than config loading: on 2.0.16 (macOS arm64), with an intact config containing a config-declared OpenAI-compatible provider, the HTTP API and ACP disagree at the same moment:
GET /api/model→ 38 models including the provider's 5 ({opencode: 8, xiaomi: 6, openai: 15, deepseek: 4, <custom>: 5}), andGET /api/providerlists the custom provider withactivation: "enabled".opencode acp→session/newimmediately after →configOptions[model].options= 95 models fromgithub-copilot/openai/xiaomionly, custom provider absent (reproduced twice, ~2 min apart).So config loading and provider activation do complete for the server; only the ACP catalog snapshot misses them (or misses them most of the time — the same probes returned 7 / 8 / 17 / 19 / 20 / 95 entries depending on run, which is why I think the poll-exit timing is the deciding factor rather than any file/config difference).
Worth noting for anyone debugging:
opencode reloador a service restart does not change the ACP result, but the server's/api/modelpicks the provider up right away.cristoslc commentedon Sep 26, 2026
Adding two data points that extend @munir-weave's timing analysis and sharpen the failure signature for @holny's fix (repro details below, raw JSON-RPC against
opencode acp, no third-party client — consistent with the snapshot-timing finding: the catalog the ACP layer serves looks like a pre-config-merge snapshot, which is why only bare upstream ids and the generic effort ladder appear).1. Set-accepts / prompt-rejects split.
session/set_config_optionwith a generic effort value (highfrom the advertisednone/minimal/low/medium/high/defaultladder) is accepted and stored on the session — then the prompt-time resolver rejects the same ref against the config-merged catalog:So a host that picks only from advertised options — protocol-correct behavior — still produces a session that fails at first prompt, surfaced as a generic
provider.no-routeerror rather than invalid-params. Same root as #50378. A regression test for the fix should assert not only thatconfigOptionscontains the config-defined entries, but that a set-then-prompt using advertised values succeeds.2. A verified workaround (no fix required): make the config coincide with what the pre-merge snapshot advertises — bare upstream model ids, variant ids renamed to the generic ladder, same
reasoningEffortvalues:{ "providers": { "ollama-cloud": { "models": { // was "deepseek-v4.1-flash:cloud" with variants thinking/low-effort/max-effort "deepseek-v4.1-flash": { "limit": { "context": 1000000, "output": 32768 }, "variants": [ { "id": "low", "settings": { "reasoningEffort": "low" } }, { "id": "high", "settings": { "reasoningEffort": "high" } }, { "id": "max", "settings": { "reasoningEffort": "max" } } ] } } } } }Verified end-to-end on 2.0.16: after this change, sessions selected entirely from advertised options resolve and prompt.
Environment: opencode 2.0.16, macOS 15 arm64 (official bun binary), config-only OpenAI-compatible providers (
aisdk:@ai-sdk/openai-compatible, suffixed ids likedeepseek-v4.1-flash:cloud, custom variant namesthinking/low-effort/max-effort— all resolvable in the TUI). The original failure was observed through an ACP desktop host asprovider.no-routecards at first prompt.strk-ai-agent commentedon Sep 26, 2026
Adding a data point that may explain why this looks like a v2 login requirement, since that is the conclusion the behavior invites — it is not one.
On 2.0.16, with no Zen credential anywhere (no
OPENCODE_API_KEYin the environment, nothing Zen-related inopencode auth list, global~/.config/opencode/opencode.jsonccontaining only$schema):opencode run -m opencode/space-bunny-free "say hi"in a project directory → answers normally, as> <agent> · space-bunny-free.opencode acpin that same directory → themodelsession option contains zeroopencode/*entries, and a new session comes up on the "newest available supported model" from an unrelated provider instead.So the free Zen models are reachable without any credential (they also answer a plain
POST https://opencode.ai/zen/v1/chat/completionswith noAuthorizationheader), but the ACP catalog never lists them.Setting
OPENCODE_API_KEYto a dummy value makes theopencode/*andopencode-go/*entries appear in the catalog and the configuredmodelpin get honored —session/newthen reportscurrentModelId=opencode-go/space-bunny-free— but every prompt fails with:even though that same model is the one that just worked unauthenticated over plain HTTP. That points at a client-side credential gate in the catalog/availability path rather than at anything the endpoint requires.
Asking for either of these would make the failure much easier to act on:
modelis dropped for a fallback, say why in the session result or a log line, so a working pin failing to apply does not look like a policy change.Context: hit this through
acp-chat-sloppy-bridge0.7.0 drivingopencode acpover stdio, where the user-visible symptom is "the bot answers its own messages but the agent never replies".lkshrk commentedon Sep 27, 2026
Still reproduces on 2.0.18 (npm
@opencode/cli-linux-x64, Linux x64). The setup isopencode acpover stdio with a config-only OpenAI-compatible provider and a top-levelmodel. Some details that may matter for #50619 and for anyone who needs a workaround now:opencode acpprocesses came up with a Zen-only catalog. In those,currentValuewas anopencode/*-freemodel and none of the config provider's models were listed. The other half came up correct.catalog(cwd)inpackages/cli/src/acp/service.tscaches theloadCatalogpromise per cwd. Every latersession/neworsession/loadin the same process reuses the stale catalog.session/set_config_optionfor a config model then fails withInvalid params: model not found: <provider>/<model>, and the prompt runs on the Zen fallback. Retrying the session in the same process never recovers.experimental.policiesdoesn't help. We addedprovider.usedeny*and allow<provider>. It removes the Zen models fromGET /api/modelonce the process is warm, but the ACP snapshot is taken before the policy transform applies, so the same race still happens.session/new/session/load, check thatconfigOptions[model].optionscontains the expected models. If they're missing, kill the process and spawn a new one. In practice it converges within a few restarts, about 1 s each. The rejected attempts leave empty sessions behind in the session list.Update — a better workaround without respawning: the catalog snapshot happens right after the first request boots the location. The config provider arrives 0.3–0.6 s later, and the bundled models.dev catalog already has Zen models, so the poll exits at once. Emptying the built-in catalog removes the race:
With no built-in models,
loadCatalogkeeps polling until the config provider shows up. Result: 8/8 fresh processes and 4 concurrent ones all came up with the correct catalog and default model, with no retries. Obviously only an option when every model comes from config providers.iamhenry commentedon Sep 28, 2026
i have this issue too. plz fix it
Paul-van-Klaveren commentedon Sep 29, 2026
I am required to use OpenCode v2 (acp) in Xcode 27 set up with a locally-hosted offline-only Ollama provider and a model configured.
If OpenCode acp cannot be set up with locally-hosted offline-only models, and instead uses the free models, I cannot use it at all.
~/.config/opencode/opencode.jsonc:
{ "$schema": "https://opencode.ai/config.json", "model": "ollama/ornith:35b-q8_0", "providers": { "ollama": { "settings": { "baseURL": "http://192.168.12.345:12345/v1" } } } }In Xcode 27, the opencode executable is set, and the argument
acpis provided; otherwise nothing is set — no environment variables. I'm keen to learn if there is any workaround, e.g. via the environment variables instead of via the config file, to get opencode acp to use Ollama.test: 実 OpenCode のテストを上流バグ回避のウォームアップシム経由にし、想定外の失敗で即失敗させる
nexxeln commentedon Sep 30, 2026
Fixed by #52286 (merged in 1844c11): ACP no longer pins agent/model from an early catalog snapshot on
session/new, and it refreshes the catalog (pushingconfig_option_update/available_commands_update) when plugins finish loading config agents, providers, and commands. It also reloads the catalog before rejecting an unknown model or mode inset_config_option/set_mode. Please reopen if you still see this on a release that includes the fix.fix: bump OpenCode to 2.0.26 to restore config-defined models via ACP