diff --git a/VERDICT-FORK.md b/VERDICT-FORK.md
index 43a42d3..9662a83 100644
--- a/VERDICT-FORK.md
+++ b/VERDICT-FORK.md
@@ -44,6 +44,26 @@ the client to providers' billing APIs).

The compiled standalone verdict binary — VERDICT wordmark + titlebar, no auto-update dialog.
+## Local LLM / Ollama OpenAI-compat
+
+caseforge drives this runtime with a custom `@ai-sdk/openai-compatible` provider
+whose `options.baseURL` is `VERDICT_LLM_BASEURL`. The SDK POSTs
+`${baseURL}/chat/completions`.
+
+| `VERDICT_LLM_BASEURL` | Request path | Typical Ollama response |
+|---|---|---|
+| `http://host:11434/v1` | `/v1/chat/completions` | OpenAI-shaped JSON (success or `model … not found`) |
+| `http://host:11434` (no `/v1`) | `/chat/completions` | plain `404 page not found` |
+
+This fork does **not** rewrite bare Ollama roots — missing `/v1` is a caller
+config issue (normalize in caseforge / env). Residual checks:
+
+```bash
+bash scripts/check-httpapi-error-contracts.sh # always offline
+# optional live probe (SKIP when host unset/down):
+VERDICT_LLM_BASEURL=http://host:11434/v1 bash scripts/check-ollama-openai-compat.sh
+```
+
## Build & run
Same as upstream (Bun ≥ 1.3.14, no Go needed):
diff --git a/packages/opencode/test/provider/provider.test.ts b/packages/opencode/test/provider/provider.test.ts
index 18ec8f9..18ca14b 100644
--- a/packages/opencode/test/provider/provider.test.ts
+++ b/packages/opencode/test/provider/provider.test.ts
@@ -847,6 +847,56 @@ it.instance(
},
)
+// Ollama OpenAI-compat: @ai-sdk/openai-compatible POSTs ${baseURL}/chat/completions.
+// Ollama only serves that under /v1; a bare host:port root yields "404 page not found".
+// This runtime does not auto-append /v1 — callers (caseforge VERDICT_LLM_BASEURL) must.
+it.instance(
+ "Ollama-style openai-compatible baseURL with /v1 is preserved on the provider",
+ Effect.gen(function* () {
+ const providers = yield* list
+ const id = ProviderV2.ID.make("ollama-local")
+ expect(providers[id].options.baseURL).toBe("http://10.126.60.100:11434/v1")
+ expect(providers[id].models["local"].api.npm).toBe("@ai-sdk/openai-compatible")
+ }),
+ {
+ config: {
+ provider: {
+ "ollama-local": {
+ name: "Ollama local",
+ npm: "@ai-sdk/openai-compatible",
+ env: [],
+ models: { local: { name: "Local", tool_call: true, limit: { context: 8192, output: 2048 } } },
+ options: { apiKey: "local", baseURL: "http://10.126.60.100:11434/v1" },
+ },
+ },
+ },
+ },
+)
+
+it.instance(
+ "Ollama-style openai-compatible baseURL without /v1 is not rewritten by the provider",
+ Effect.gen(function* () {
+ const providers = yield* list
+ const id = ProviderV2.ID.make("ollama-bare")
+ // Intentionally bare: documents that missing /v1 is a caller config bug, not engine path join.
+ expect(providers[id].options.baseURL).toBe("http://10.126.60.100:11434")
+ expect(String(providers[id].options.baseURL).endsWith("/v1")).toBe(false)
+ }),
+ {
+ config: {
+ provider: {
+ "ollama-bare": {
+ name: "Ollama bare root",
+ npm: "@ai-sdk/openai-compatible",
+ env: [],
+ models: { local: { name: "Local", tool_call: true, limit: { context: 8192, output: 2048 } } },
+ options: { apiKey: "local", baseURL: "http://10.126.60.100:11434" },
+ },
+ },
+ },
+ },
+)
+
// Edge cases for model configuration
it.instance(
diff --git a/scripts/check-ollama-openai-compat.sh b/scripts/check-ollama-openai-compat.sh
new file mode 100755
index 0000000..12916d5
--- /dev/null
+++ b/scripts/check-ollama-openai-compat.sh
@@ -0,0 +1,68 @@
+#!/usr/bin/env bash
+# Optional smoke: Ollama OpenAI-compat /v1/chat/completions is reachable.
+#
+# Distinguishes:
+# - correct base (.../v1) → OpenAI-shaped error JSON for unknown model (route exists)
+# - bare root (no /v1) → plain "404 page not found" (the m13 agent-path failure mode)
+#
+# Offline-friendly: SKIP (exit 0) when host is unset or unreachable.
+# Usage:
+# VERDICT_LLM_BASEURL=http://host:11434/v1 bash scripts/check-ollama-openai-compat.sh
+# OLLAMA_HOST=http://host:11434 bash scripts/check-ollama-openai-compat.sh
+set -euo pipefail
+
+raw="${VERDICT_LLM_BASEURL:-${OLLAMA_HOST:-${CASEFORGE_SPARK_ENDPOINT:-}}}"
+if [[ -z "${raw}" ]]; then
+ echo "SKIP: set VERDICT_LLM_BASEURL, OLLAMA_HOST, or CASEFORGE_SPARK_ENDPOINT"
+ exit 0
+fi
+
+# Strip trailing slash; strip a single trailing /v1 for origin probes.
+origin="${raw%/}"
+origin="${origin%/v1}"
+v1_chat="${origin}/v1/chat/completions"
+bare_chat="${origin}/chat/completions"
+tags="${origin}/api/tags"
+
+if ! curl -sS -m 2 -o /dev/null "${tags}"; then
+ echo "SKIP: Ollama unreachable at ${origin} (tags probe failed)"
+ exit 0
+fi
+
+body='{"model":"__opencode_ollama_smoke_missing__","messages":[{"role":"user","content":"ping"}]}'
+
+v1_body="$(mktemp)"
+bare_body="$(mktemp)"
+trap 'rm -f "${v1_body}" "${bare_body}"' EXIT
+
+v1_code="$(curl -sS -m 5 -o "${v1_body}" -w "%{http_code}" \
+ -X POST "${v1_chat}" -H "Content-Type: application/json" -d "${body}")"
+bare_code="$(curl -sS -m 5 -o "${bare_body}" -w "%{http_code}" \
+ -X POST "${bare_chat}" -H "Content-Type: application/json" -d "${body}")"
+
+v1_text="$(cat "${v1_body}")"
+bare_text="$(cat "${bare_body}")"
+
+# Route under /v1 must not be the Go/Ollama plain page-not-found body.
+if [[ "${v1_text}" == *"404 page not found"* ]]; then
+ echo "FAIL: ${v1_chat} returned plain page-not-found (http=${v1_code})"
+ echo " body: ${v1_text}"
+ exit 1
+fi
+
+# Accept any non-page-not-found response that looks like OpenAI-compat JSON error or success.
+if [[ "${v1_text}" != *"error"* && "${v1_text}" != *"choices"* ]]; then
+ echo "FAIL: ${v1_chat} unexpected body (http=${v1_code}): ${v1_text}"
+ exit 1
+fi
+
+# Document the bare-root failure mode (expected when baseURL omits /v1).
+if [[ "${bare_text}" != *"404 page not found"* ]]; then
+ echo "WARN: bare ${bare_chat} did not return page-not-found (http=${bare_code}); body=${bare_text}"
+fi
+
+echo "PASS: Ollama OpenAI-compat reachable"
+echo " origin=${origin}"
+echo " v1_chat=${v1_chat} http=${v1_code}"
+echo " bare_chat=${bare_chat} http=${bare_code} (expect page-not-found when /v1 omitted from baseURL)"
+echo " note: @ai-sdk/openai-compatible POSTs \${baseURL}/chat/completions — baseURL must include /v1"