From 2efd6caa65325fa297222ab45c7a1ae5d60a6948 Mon Sep 17 00:00:00 2001 From: Nat Welch Date: Mon, 19 Oct 2026 00:56:27 +0000 Subject: [PATCH] feat: add local ollama provider Co-Authored-By: Claude Opus 5.5 --- README.md | 1 + opencode.jsonc | 24 ++++++++++++++++++++++++ tests/routing.test.mjs | 2 +- 3 files changed, 26 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index cd26c6d..bb1184f 100644 --- a/README.md +++ b/README.md @@ -50,6 +50,7 @@ docker compose exec opencode opencode auth login openai --server http://127.0.0. - **Gemini:** choose the API-key method or set `GOOGLE_GENERATIVE_AI_API_KEY`. Organization-backed Code Assist OAuth also needs `OPENCODE_GEMINI_PROJECT_ID`; see the [Gemini plugin's account requirements](https://github.com/jenslys/opencode-gemini-auth). - **Anthropic:** enter a [Console API key](https://console.anthropic.com/settings/keys) or set `ANTHROPIC_API_KEY`. Claude Pro and Max subscriptions do not work outside Claude Code. - **OpenAI:** choose the API-key method with a [platform key](https://platform.openai.com/api-keys) or set `OPENAI_API_KEY`. +- **Ollama:** `qwen3-coder:30b` and `ornith:35b` are served from `http://ollama:11434/v1`, so run an [Ollama](https://docs.ollama.com/docker) container named `ollama` on the same Compose network with those models pulled. It needs no key. - **Git access:** set `GH_TOKEN` or run `docker compose exec opencode gh auth login --hostname github.com --git-protocol https --web`. This is separate from Copilot login; stored credentials persist in `/data/.config/gh`. - **WakaTime:** put your API key in `/data/.wakatime.cfg`, owned by `1000:1000` with mode `600`, using the [plugin's configuration format](https://github.com/angristan/opencode-wakatime#prerequisites). diff --git a/opencode.jsonc b/opencode.jsonc index e5f7a19..6d402b5 100644 --- a/opencode.jsonc +++ b/opencode.jsonc @@ -65,6 +65,25 @@ "model": "anthropic/claude-opus-5-5" } }, + "providers": { + "ollama": { + "name": "Ollama", + "package": "@opencode/ai/providers/openai-compatible", + "settings": { + "baseURL": "http://ollama:11434/v1" + }, + "models": { + "qwen3-coder:30b": { + "name": "Qwen3 Coder 30B", + "limit": { "context": 32768, "output": 8192 } + }, + "ornith:35b": { + "name": "Ornith 35B", + "limit": { "context": 32768, "output": 8192 } + } + } + } + }, "mcp": { "servers": { "notion": { @@ -169,6 +188,11 @@ "action": "provider.use", "resource": "openai", "effect": "allow" + }, + { + "action": "provider.use", + "resource": "ollama", + "effect": "allow" } ] } diff --git a/tests/routing.test.mjs b/tests/routing.test.mjs index 6e0f9fb..3475644 100644 --- a/tests/routing.test.mjs +++ b/tests/routing.test.mjs @@ -43,7 +43,7 @@ test("existing providers, MCP integrations and quota are preserved", () => { assert.deepEqual(Object.keys(config.mcp.servers).sort(), ["context7", "grafana", "karakeep", "lunchmoney", "notion", "robinhood"]); assert.ok(config.plugins.includes("@slkiser/opencode-quota@5.0.3")); const allowed = config.policies.filter(p => p.action === "provider.use" && p.effect === "allow").map(p => p.resource); - assert.deepEqual(allowed.sort(), ["anthropic", "github-copilot", "google", "openai"]); + assert.deepEqual(allowed.sort(), ["anthropic", "github-copilot", "google", "ollama", "openai"]); assert.ok(!config.permissions?.some(rule => rule.action === "*" && rule.effect === "allow")); assert.deepEqual(config.agents.build.permissions[0], { action: "*", resource: "*", effect: "allow" }); for (const name of ["general", "explore"])