diff --git a/docs/docs_map.md b/docs/docs_map.md
index 352c9fddd966..488132c0b0dd 100644
--- a/docs/docs_map.md
+++ b/docs/docs_map.md
@@ -8585,7 +8585,7 @@ Do not edit it by hand; run `pnpm docs:map:gen`.
- Headings:
- H2: Getting started
- H2: Config example
- - H2: Built-in catalog
+ - H2: Catalog
- H2: Advanced configuration
- H2: Related
diff --git a/docs/gateway/doctor.md b/docs/gateway/doctor.md
index 367d7ae26c4f..420f4deb277c 100644
--- a/docs/gateway/doctor.md
+++ b/docs/gateway/doctor.md
@@ -352,7 +352,7 @@ That stages grounded durable candidates into the short-term dreaming store while
- If you have added `models.providers.opencode`, `opencode-zen`, or `opencode-go` manually, it overrides the built-in OpenCode catalog from `openclaw/plugin-sdk/llm`. That can force models onto the wrong API or zero out costs. Doctor warns so you can remove the override and restore per-model API routing + costs.
+ If you have added `models.providers.opencode`, `opencode-zen`, or `opencode-go` manually while the matching official external plugin is installed and enabled, it overrides that plugin-provided catalog. That can force models onto the wrong API or zero out costs. Doctor warns so you can remove the override and restore per-model API routing + costs. Without the matching plugin, the entry remains a valid standalone custom provider.
If your browser config still points at the removed Chrome extension path, doctor normalizes it to the current host-local Chrome MCP attach model (`browser.profiles.*.driver: "extension"` → `"existing-session"`; `browser.relayBindHost` removed).
diff --git a/docs/help/testing-live.md b/docs/help/testing-live.md
index 67e51602457f..3fe3e21cc356 100644
--- a/docs/help/testing-live.md
+++ b/docs/help/testing-live.md
@@ -612,7 +612,7 @@ If you have keys enabled, you can also test via:
More providers you can include in the live matrix (if you have creds/config):
-- Built-in: `anthropic`, `cerebras`, `github-copilot`, `google`, `google-antigravity`, `google-gemini-cli`, `google-vertex`, `groq`, `mistral`, `openai`, `openrouter`, `opencode`, `opencode-go`, `xai`, `zai`
+- First-party provider plugins: `anthropic`, `cerebras`, `github-copilot`, `google`, `google-antigravity`, `google-gemini-cli`, `google-vertex`, `groq`, `mistral`, `openai`, `openrouter`, `opencode`, `opencode-go`, `xai`, `zai`
- Via `models.providers` (custom endpoints): `minimax` (cloud/API), plus any OpenAI/Anthropic-compatible proxy (LM Studio, vLLM, LiteLLM, etc.)
diff --git a/docs/plugins/plugin-inventory.md b/docs/plugins/plugin-inventory.md
index df2ecc079383..53beb0a3f99f 100644
--- a/docs/plugins/plugin-inventory.md
+++ b/docs/plugins/plugin-inventory.md
@@ -51,7 +51,7 @@ Each entry lists the package, distribution route, and description.
## Core npm package
-56 plugins
+55 plugins
- **[admin-http-rpc](/plugins/reference/admin-http-rpc)** (`@openclaw/admin-http-rpc`) - included in OpenClaw. OpenClaw admin HTTP RPC endpoint.
@@ -133,8 +133,6 @@ Each entry lists the package, distribution route, and description.
- **[openai](/plugins/reference/openai)** (`@openclaw/openai-provider`) - included in OpenClaw. Adds OpenAI model provider support to OpenClaw.
-- **[opencode-go](/plugins/reference/opencode-go)** (`@openclaw/opencode-go-provider`) - included in OpenClaw. Adds OpenCode Go model provider support to OpenClaw.
-
- **[openrouter](/plugins/reference/openrouter)** (`@openclaw/openrouter-provider`) - included in OpenClaw. Adds OpenRouter model provider support to OpenClaw.
- **[policy](/plugins/reference/policy)** (`@openclaw/policy`) - included in OpenClaw. Adds policy-backed doctor checks for workspace conformance.
@@ -167,7 +165,7 @@ Each entry lists the package, distribution route, and description.
## Official external packages
-89 plugins
+90 plugins
- **[acpx](/plugins/reference/acpx)** (`@openclaw/acpx`) - npm; ClawHub. OpenClaw ACP runtime backend with plugin-owned session and transport management.
@@ -281,6 +279,8 @@ Each entry lists the package, distribution route, and description.
- **[opencode](/plugins/reference/opencode)** (`@openclaw/opencode-provider`) - npm; ClawHub: `clawhub:@openclaw/opencode-provider`. Adds OpenCode model provider support to OpenClaw.
+- **[opencode-go](/plugins/reference/opencode-go)** (`@openclaw/opencode-go-provider`) - npm; ClawHub: `clawhub:@openclaw/opencode-go-provider`. Adds OpenCode Go model provider support to OpenClaw.
+
- **[openshell](/plugins/reference/openshell)** (`@openclaw/openshell-sandbox`) - npm; ClawHub. OpenClaw sandbox backend for the NVIDIA OpenShell CLI with mirrored local workspaces and SSH command execution.
- **[parallel](/tools/parallel-search)** (`@openclaw/parallel-plugin`) - npm; ClawHub: `clawhub:@openclaw/parallel-plugin`. Adds web search provider support.
diff --git a/docs/plugins/reference/opencode-go.md b/docs/plugins/reference/opencode-go.md
index 37a5c4453171..5e85c69c8237 100644
--- a/docs/plugins/reference/opencode-go.md
+++ b/docs/plugins/reference/opencode-go.md
@@ -12,7 +12,7 @@ Adds OpenCode Go model provider support to OpenClaw.
## Distribution
- Package: `@openclaw/opencode-go-provider`
-- Install route: included in OpenClaw
+- Install route: npm; ClawHub: `clawhub:@openclaw/opencode-go-provider`
## Surface
diff --git a/docs/providers/opencode-go.md b/docs/providers/opencode-go.md
index 25c678b7bfdc..f81530153b37 100644
--- a/docs/providers/opencode-go.md
+++ b/docs/providers/opencode-go.md
@@ -9,16 +9,25 @@ title: "OpenCode Go"
OpenCode Go is the Go catalog inside [OpenCode](/providers/opencode). It shares
the `OPENCODE_API_KEY` credential with the Zen catalog, but keeps its own
runtime provider id (`opencode-go`) so upstream per-model routing stays
-correct.
+correct. OpenClaw provides it as the official external
+`@openclaw/opencode-go-provider` plugin.
| Property | Value |
| ---------------- | -------------------------------------------------- |
| Runtime provider | `opencode-go` |
+| Plugin | `@openclaw/opencode-go-provider` |
| Auth | `OPENCODE_API_KEY` (alias: `OPENCODE_ZEN_API_KEY`) |
| Parent setup | [OpenCode](/providers/opencode) |
## Getting started
+Install the official plugin and restart the Gateway:
+
+```bash
+openclaw plugins install @openclaw/opencode-go-provider
+openclaw gateway restart
+```
+
@@ -65,10 +74,10 @@ correct.
}
```
-## Built-in catalog
+## Catalog
Run `openclaw models list --provider opencode-go` for the current model list.
-Bundled rows:
+Current rows:
| Model ref | Name | Context | Max output | Image input |
| ------------------------------- | ----------------- | --------- | ---------- | ----------- |
diff --git a/docs/providers/opencode.md b/docs/providers/opencode.md
index 4c2fc132d78c..c7d0ae7836ae 100644
--- a/docs/providers/opencode.md
+++ b/docs/providers/opencode.md
@@ -55,6 +55,12 @@ one OpenCode setup.
**Best for:** the OpenCode-hosted Kimi, GLM, MiniMax, Qwen, and DeepSeek lineup.
+
+ ```bash
+ openclaw plugins install @openclaw/opencode-go-provider
+ openclaw gateway restart
+ ```
+
```bash
openclaw onboard --auth-choice opencode-go
diff --git a/extensions/opencode-go/README.md b/extensions/opencode-go/README.md
new file mode 100644
index 000000000000..ac22575a8b6c
--- /dev/null
+++ b/extensions/opencode-go/README.md
@@ -0,0 +1,16 @@
+# OpenClaw OpenCode Go Provider
+
+Official OpenClaw provider plugin for the OpenCode Go model catalog.
+
+Install from OpenClaw:
+
+```bash
+openclaw plugins install @openclaw/opencode-go-provider
+openclaw gateway restart
+```
+
+Configure `OPENCODE_API_KEY` or `OPENCODE_ZEN_API_KEY`, then select an
+`opencode-go/...` model.
+
+See for setup and the current
+model catalog.
diff --git a/extensions/opencode-go/index.ts b/extensions/opencode-go/index.ts
index bca0731cb50d..994a8c16952a 100644
--- a/extensions/opencode-go/index.ts
+++ b/extensions/opencode-go/index.ts
@@ -41,7 +41,7 @@ function resolveOpencodeGoCatalogAuth(
export default defineSingleProviderPluginEntry({
id: PROVIDER_ID,
name: "OpenCode Go Provider",
- description: "Bundled OpenCode Go provider plugin",
+ description: "Official OpenCode Go provider plugin",
manifest,
provider: {
label: "OpenCode Go",
diff --git a/extensions/opencode-go/package.json b/extensions/opencode-go/package.json
index b9bc0b455596..ce82d8a23c7c 100644
--- a/extensions/opencode-go/package.json
+++ b/extensions/opencode-go/package.json
@@ -1,8 +1,11 @@
{
"name": "@openclaw/opencode-go-provider",
"version": "2026.7.2",
- "private": true,
"description": "OpenClaw OpenCode Go provider plugin",
+ "repository": {
+ "type": "git",
+ "url": "https://github.com/openclaw/openclaw"
+ },
"type": "module",
"devDependencies": {
"@openclaw/plugin-sdk": "workspace:*"
@@ -10,6 +13,23 @@
"openclaw": {
"extensions": [
"./index.ts"
- ]
+ ],
+ "install": {
+ "clawhubSpec": "clawhub:@openclaw/opencode-go-provider",
+ "npmSpec": "@openclaw/opencode-go-provider",
+ "defaultChoice": "npm",
+ "minHostVersion": ">=2026.7.2"
+ },
+ "compat": {
+ "pluginApi": ">=2026.7.2"
+ },
+ "build": {
+ "openclawVersion": "2026.7.2",
+ "bundledDist": false
+ },
+ "release": {
+ "publishToClawHub": true,
+ "publishToNpm": true
+ }
}
}
diff --git a/package.json b/package.json
index 15a31184f05c..ef91f544801c 100644
--- a/package.json
+++ b/package.json
@@ -295,6 +295,7 @@
"!dist/extensions/nostr/**",
"!dist/extensions/novita/**",
"!dist/extensions/opencode/**",
+ "!dist/extensions/opencode-go/**",
"!dist/extensions/parallel/**",
"!dist/extensions/perplexity/**",
"!dist/extensions/qianfan/**",
diff --git a/scripts/lib/official-external-provider-catalog.json b/scripts/lib/official-external-provider-catalog.json
index 91f21ec83ff6..c3a3566bd5ad 100644
--- a/scripts/lib/official-external-provider-catalog.json
+++ b/scripts/lib/official-external-provider-catalog.json
@@ -1190,6 +1190,69 @@
}
}
},
+ {
+ "name": "@openclaw/opencode-go-provider",
+ "description": "OpenClaw OpenCode Go provider plugin",
+ "source": "official",
+ "kind": "provider",
+ "openclaw": {
+ "plugin": {
+ "id": "opencode-go",
+ "label": "OpenCode Go"
+ },
+ "providerEndpoints": [
+ {
+ "endpointClass": "opencode-native",
+ "hostSuffixes": [
+ "opencode.ai"
+ ]
+ }
+ ],
+ "providers": [
+ {
+ "id": "opencode-go",
+ "name": "OpenCode Go",
+ "docs": "/providers/opencode-go",
+ "categories": [
+ "cloud",
+ "llm"
+ ],
+ "envVars": [
+ "OPENCODE_API_KEY",
+ "OPENCODE_ZEN_API_KEY"
+ ],
+ "authChoices": [
+ {
+ "method": "api-key",
+ "choiceId": "opencode-go",
+ "choiceLabel": "OpenCode Go catalog",
+ "groupId": "opencode",
+ "groupLabel": "OpenCode",
+ "groupHint": "Shared API key for Zen + Go catalogs",
+ "optionKey": "opencodeGoApiKey",
+ "cliFlag": "--opencode-go-api-key",
+ "cliOption": "--opencode-go-api-key ",
+ "cliDescription": "OpenCode API key (Go catalog)",
+ "onboardingScopes": [
+ "text-inference"
+ ]
+ }
+ ]
+ }
+ ],
+ "contracts": {
+ "mediaUnderstandingProviders": [
+ "opencode-go"
+ ]
+ },
+ "install": {
+ "clawhubSpec": "clawhub:@openclaw/opencode-go-provider",
+ "npmSpec": "@openclaw/opencode-go-provider",
+ "defaultChoice": "npm",
+ "minHostVersion": ">=2026.7.2"
+ }
+ }
+ },
{
"name": "@openclaw/pixverse-provider",
"description": "OpenClaw PixVerse video provider plugin",
diff --git a/src/cli/plugins-location-bridges.test.ts b/src/cli/plugins-location-bridges.test.ts
index f7ac26c7988d..0ff68efde751 100644
--- a/src/cli/plugins-location-bridges.test.ts
+++ b/src/cli/plugins-location-bridges.test.ts
@@ -170,6 +170,7 @@ describe("listPersistedBundledPluginLocationBridges", () => {
["mistral", "@openclaw/mistral-provider", true],
["novita", "@openclaw/novita-provider", true],
["opencode", "@openclaw/opencode-provider", true],
+ ["opencode-go", "@openclaw/opencode-go-provider", true],
["synthetic", "@openclaw/synthetic-provider", true],
["teams-meetings", "@openclaw/teams-meetings", true],
["volcengine", "@openclaw/volcengine-provider", true],
diff --git a/src/commands/doctor-config-analysis.test.ts b/src/commands/doctor-config-analysis.test.ts
index d329a47ee578..4bdfba8000a4 100644
--- a/src/commands/doctor-config-analysis.test.ts
+++ b/src/commands/doctor-config-analysis.test.ts
@@ -6,6 +6,7 @@ import { OpenClawSchema } from "../config/zod-schema.js";
import {
formatConfigPath,
noteImplicitFallbackClobberWarnings,
+ noteOpencodeProviderOverrides,
noteSandboxOriginProxyWarning,
resolveConfigPathTarget,
stripUnknownConfigKeys,
@@ -23,6 +24,66 @@ function collectImplicitFallbackClobberWarnings(cfg: OpenClawConfig): string[] {
}
describe("doctor config analysis helpers", () => {
+ it("describes OpenCode overrides against the plugin-provided catalog", () => {
+ noteMock.mockClear();
+
+ noteOpencodeProviderOverrides(
+ {
+ models: {
+ providers: {
+ opencode: {
+ baseUrl: "https://opencode.ai/zen/v1",
+ api: "openai-completions",
+ models: [],
+ },
+ },
+ },
+ },
+ { opencodePluginActive: true },
+ );
+
+ expect(noteMock).toHaveBeenCalledWith(
+ expect.stringContaining("plugin-provided OpenCode Zen catalog"),
+ "OpenCode",
+ );
+ expect(noteMock.mock.calls.at(-1)?.[0]).not.toContain("built-in");
+ });
+
+ it("classifies external OpenCode overrides only while their plugins are active", () => {
+ noteMock.mockClear();
+
+ const cfg: OpenClawConfig = {
+ models: {
+ providers: {
+ opencode: {
+ baseUrl: "https://opencode.ai/zen/v1",
+ api: "openai-completions",
+ models: [],
+ },
+ "opencode-go": {
+ baseUrl: "https://opencode.ai/zen/go/v1",
+ api: "openai-completions",
+ models: [],
+ },
+ },
+ },
+ };
+
+ noteOpencodeProviderOverrides(cfg);
+ expect(noteMock).not.toHaveBeenCalled();
+
+ noteOpencodeProviderOverrides(cfg, {
+ opencodePluginActive: true,
+ opencodeGoPluginActive: true,
+ });
+ expect(noteMock).toHaveBeenCalledWith(
+ expect.stringMatching(
+ /plugin-provided OpenCode Zen catalog[\s\S]*plugin-provided OpenCode Go catalog/u,
+ ),
+ "OpenCode",
+ );
+ });
+
it("formats config paths predictably", () => {
expect(formatConfigPath([])).toBe("");
expect(formatConfigPath(["channels", "slack", "accounts", 0, "token"])).toBe(
diff --git a/src/commands/doctor-config-analysis.ts b/src/commands/doctor-config-analysis.ts
index 778946dff05c..be1933866e2d 100644
--- a/src/commands/doctor-config-analysis.ts
+++ b/src/commands/doctor-config-analysis.ts
@@ -129,21 +129,24 @@ export function stripUnknownConfigKeys(config: OpenClawConfig): {
return { config: next, removed };
}
-/** Warns when legacy OpenCode provider overrides shadow the built-in catalog. */
-export function noteOpencodeProviderOverrides(cfg: OpenClawConfig): void {
+/** Warns when legacy OpenCode overrides shadow an active plugin-provided catalog. */
+export function noteOpencodeProviderOverrides(
+ cfg: OpenClawConfig,
+ options: { opencodePluginActive?: boolean; opencodeGoPluginActive?: boolean } = {},
+): void {
const providers = cfg.models?.providers;
if (!providers) {
return;
}
const overrides: string[] = [];
- if (providers.opencode) {
+ if (options.opencodePluginActive === true && providers.opencode) {
overrides.push("opencode");
}
- if (providers["opencode-zen"]) {
+ if (options.opencodePluginActive === true && providers["opencode-zen"]) {
overrides.push("opencode-zen");
}
- if (providers["opencode-go"]) {
+ if (options.opencodeGoPluginActive === true && providers["opencode-go"]) {
overrides.push("opencode-go");
}
if (overrides.length === 0) {
@@ -158,7 +161,7 @@ export function noteOpencodeProviderOverrides(cfg: OpenClawConfig): void {
? providerEntry.api
: undefined;
return [
- `- models.providers.${id} is set; this overrides the built-in ${providerLabel} catalog.`,
+ `- models.providers.${id} is set; this overrides the plugin-provided ${providerLabel} catalog.`,
api ? `- models.providers.${id}.api=${api}` : null,
].filter((line): line is string => Boolean(line));
});
diff --git a/src/commands/doctor-config-flow.ts b/src/commands/doctor-config-flow.ts
index 3bcc5ee20b5f..27046a11e674 100644
--- a/src/commands/doctor-config-flow.ts
+++ b/src/commands/doctor-config-flow.ts
@@ -476,7 +476,23 @@ export async function loadAndMaybeMigrateDoctorConfig(params: {
candidate: cfg,
});
- noteOpencodeProviderOverrides(cfg);
+ const configuredOpencodePluginIds = [
+ cfg.models?.providers?.opencode || cfg.models?.providers?.["opencode-zen"]
+ ? "opencode"
+ : undefined,
+ cfg.models?.providers?.["opencode-go"] ? "opencode-go" : undefined,
+ ].filter((pluginId): pluginId is string => pluginId !== undefined);
+ const activeOpencodePluginIds =
+ configuredOpencodePluginIds.length > 0
+ ? (await import("../plugins/providers.js")).resolveEnabledProviderPluginIds({
+ config: cfg,
+ onlyPluginIds: configuredOpencodePluginIds,
+ })
+ : [];
+ noteOpencodeProviderOverrides(cfg, {
+ opencodePluginActive: activeOpencodePluginIds.includes("opencode"),
+ opencodeGoPluginActive: activeOpencodePluginIds.includes("opencode-go"),
+ });
noteImplicitFallbackClobberWarnings(cfg);
noteSandboxOriginProxyWarning(cfg);
diff --git a/src/commands/doctor.warns-state-directory-is-missing.e2e.test.ts b/src/commands/doctor.warns-state-directory-is-missing.e2e.test.ts
index 9a7eda7d378f..803648b70279 100644
--- a/src/commands/doctor.warns-state-directory-is-missing.e2e.test.ts
+++ b/src/commands/doctor.warns-state-directory-is-missing.e2e.test.ts
@@ -196,7 +196,7 @@ describe("doctor command", () => {
}
});
- it("warns about opencode provider overrides", async () => {
+ it("warns about active OpenCode provider overrides", async () => {
mockDoctorConfigSnapshot({
config: {
models: {
diff --git a/src/plugins/official-external-plugin-catalog.test.ts b/src/plugins/official-external-plugin-catalog.test.ts
index a82cead9a40f..10d3603033ba 100644
--- a/src/plugins/official-external-plugin-catalog.test.ts
+++ b/src/plugins/official-external-plugin-catalog.test.ts
@@ -1981,6 +1981,27 @@ describe("official external plugin catalog", () => {
]);
});
+ it("lists OpenCode Go with its provider and media-understanding contracts", () => {
+ const opencodeGo = expectCatalogEntry("opencode-go");
+ const manifest = getOfficialExternalPluginCatalogManifest(opencodeGo);
+
+ expect(resolveOfficialExternalPluginId(opencodeGo)).toBe("opencode-go");
+ expect(resolveOfficialExternalPluginInstall(opencodeGo)).toEqual({
+ clawhubSpec: "clawhub:@openclaw/opencode-go-provider",
+ npmSpec: "@openclaw/opencode-go-provider",
+ defaultChoice: "npm",
+ minHostVersion: ">=2026.7.2",
+ });
+ expect(manifest?.providers?.map((provider) => provider.id)).toEqual(["opencode-go"]);
+ expect(manifest?.contracts?.mediaUnderstandingProviders).toEqual(["opencode-go"]);
+ expect(manifest?.providerEndpoints).toEqual([
+ {
+ endpointClass: "opencode-native",
+ hostSuffixes: ["opencode.ai"],
+ },
+ ]);
+ });
+
it("lists Synthetic as an official external provider", () => {
const synthetic = expectCatalogEntry("synthetic");
diff --git a/test/scripts/bundled-plugin-build-entries.test.ts b/test/scripts/bundled-plugin-build-entries.test.ts
index 4aeb36016349..1c2e6872994b 100644
--- a/test/scripts/bundled-plugin-build-entries.test.ts
+++ b/test/scripts/bundled-plugin-build-entries.test.ts
@@ -349,6 +349,7 @@ describe("bundled plugin build entries", () => {
"mistral",
"novita",
"opencode",
+ "opencode-go",
"xiaomi",
]) {
expect(artifacts).not.toContain(`dist/extensions/${pluginId}/index.js`);