--- summary: "Run OpenClaw with Ollama (cloud and local models)" read_when: - You want to run OpenClaw with cloud or local models via Ollama - You need Ollama setup and configuration guidance - You want Ollama vision models for image understanding title: "Ollama" --- OpenClaw talks to Ollama's native API (`/api/chat`), not the OpenAI-compatible `/v1` endpoint. Three modes are supported: | Mode | What it uses | | ------------- | -------------------------------------------------------------------------------- | | Cloud + Local | A reachable Ollama host, serving local models and (if signed in) `:cloud` models | | Cloud only | `https://ollama.com` directly, no local daemon | | Local only | A reachable Ollama host, local models only | For cloud-only setup with the dedicated `ollama-cloud` provider id, see [Ollama Cloud](/providers/ollama-cloud). Use `ollama-cloud/` refs when you want cloud routing kept separate from a local `ollama` provider. Do not use the `/v1` OpenAI-compatible URL (`http://host:11434/v1`). It breaks tool calling and models can emit raw tool-call JSON as plain text. Use the native URL: `baseUrl: "http://host:11434"` (no `/v1`). The canonical config key is `baseUrl`. `baseURL` is also accepted for OpenAI-SDK-style examples, but new config should use `baseUrl`. ## Auth rules Loopback, private-network, `.local`, and bare-hostname Ollama URLs do not need a real bearer token. OpenClaw uses the `ollama-local` marker for these. Public remote hosts and `https://ollama.com` require a real credential: `OLLAMA_API_KEY`, an auth profile, or the provider's `apiKey`. For direct hosted use, prefer the `ollama-cloud` provider. A custom provider with `api: "ollama"` follows the same rules. For example, an `ollama-remote` provider pointed at a private LAN host can use `apiKey: "ollama-local"`; sub-agents resolve that marker through the Ollama provider hook instead of treating it as a missing credential. `memory.search.provider` can also point at a custom provider id so embeddings use that Ollama endpoint. SQLite auth stores hold the credential for a provider id; put endpoint settings (`baseUrl`, `api`, models, headers, timeouts) in `models.providers.`. Older flat `auth-profiles.json` files such as `{ "ollama-windows": { "apiKey": "ollama-local" } }` are not a runtime format; `openclaw doctor --fix` imports them into SQLite as a canonical `ollama-windows:default` API-key profile with a backup. A `baseUrl` value in that legacy file is noise and should move to provider config. Bearer auth for Ollama memory embeddings is scoped to the host it was declared for: - A provider-level key is sent only to that provider's host. - `memory.search.remote.apiKey` and per-agent overrides are sent only to their remote embedding host. - A pure `OLLAMA_API_KEY` env value is treated as the Ollama Cloud convention and is not sent to local/self-hosted hosts by default. ## Getting started ```bash openclaw onboard ``` Select **Ollama**, then pick a mode: **Cloud + Local**, **Cloud only**, or **Local only**. On a fresh guided setup, OpenClaw first checks the default or configured Ollama host. Automatic discovery considers only models already loaded in memory, as reported by `/api/ps`, with tool support and at least 16K of context confirmed by `/api/show`. An eligible model installed on disk but not loaded is not an automatic candidate. The selected route still needs a real completion before OpenClaw saves it; discovery never pulls or loads an idle model. To use an installed but idle model in desktop Model Setup, choose **Choose connection** on the Ollama card, then **Local only**. This explicit setup path can prepare an eligible installed model for the live check without requiring it to be loaded already. `Cloud only` prompts for `OLLAMA_API_KEY` and suggests hosted cloud defaults. `Cloud + Local` and `Local only` prompt for an Ollama base URL and inspect installed models. If no tools-capable model is found, setup can ask permission to pull a recommended model. An installed `:latest` tag such as `gemma4:latest` is shown once instead of duplicating `gemma4`. `Cloud + Local` also checks whether the host is signed in for cloud access. ```bash openclaw models list --provider ollama ``` Non-interactive: ```bash openclaw onboard --non-interactive --accept-risk --skip-health \ --auth-choice ollama \ --custom-base-url "http://ollama-host:11434" \ --custom-model-id "qwen3.5:27b" ``` `--custom-base-url` and `--custom-model-id` are optional; omitting them uses the local default host and the `gemma4` suggested model. Get it from [ollama.com/download](https://ollama.com/download), then pull a model: ```bash ollama pull gemma4 ``` For hybrid cloud access, run `ollama signin` on the same host. ```bash export OLLAMA_API_KEY="ollama-local" # local/LAN host, any value works export OLLAMA_API_KEY="your-real-key" # https://ollama.com only ``` Or in config: `openclaw config set models.providers.ollama.apiKey "OLLAMA_API_KEY"`. ```bash openclaw models list openclaw models set ollama/gemma4 ``` Or in config: ```json5 { agents: { defaults: { model: { primary: "ollama/gemma4" }, }, }, } ``` ## Cloud models through a local host `Cloud + Local` routes both local and `:cloud` models through one reachable Ollama host — this is Ollama's hybrid flow and the mode to pick during setup when you want both. OpenClaw prompts for the base URL, discovers local models, and checks `ollama signin` status. When signed in, it suggests hosted defaults (`kimi-k2.5:cloud`, `minimax-m2.7:cloud`, `glm-5.1:cloud`, `glm-5.2:cloud`). If not signed in, setup stays local-only until you run `ollama signin`. For cloud-only access without a local daemon, use `openclaw onboard --auth-choice ollama-cloud` and see [Ollama Cloud](/providers/ollama-cloud) — that path does not need `ollama signin` or a running server: ```bash openclaw onboard --auth-choice ollama-cloud openclaw models set ollama-cloud/kimi-k2.5:cloud ``` The cloud model list shown during `openclaw onboard` is populated live from `https://ollama.com/api/tags`, capped at 500 entries, so the picker reflects the current hosted catalog. If `ollama.com` is unreachable or returns no models at setup time, OpenClaw falls back to its hardcoded suggested list so onboarding still completes. ## Model discovery (implicit provider) When `OLLAMA_API_KEY` (or an auth profile) is set and neither `models.providers.ollama` nor another custom provider with `api: "ollama"` is defined, OpenClaw discovers models from `http://127.0.0.1:11434`: | Behavior | Detail | | -------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Catalog query | `/api/tags` | | Capability detection | Best-effort `/api/show` reads `contextWindow`, `num_ctx` Modelfile parameters, and capabilities (vision/tools/thinking) | | Vision models | A `vision` capability from `/api/show` marks the model image-capable (`input: ["text", "image"]`) | | Reasoning detection | Uses the `thinking` capability from `/api/show` when available; falls back to a name heuristic (`r1`, `reason`, `reasoning`, `think`) when Ollama omits capabilities. `glm-5.2:cloud` and `deepseek-v4-flash\|pro:cloud` are always treated as reasoning regardless of reported capabilities. | | Token limits | `maxTokens` defaults to OpenClaw's Ollama max-token cap | | Costs | All costs are `0` | ```bash ollama list openclaw models list ``` A **nonempty** `models.providers.ollama.models` list selects manual models and skips discovery. When Ollama is in the agent's model scope, an explicit self-hosted endpoint with `models: []` remains eligible for discovery; `models.providers.ollama.apiKey` alone does not select that provider for Gateway model browsing. Failed discovery records an unavailable or catalog-authentication failure and keeps the last successful inventory for the same endpoint and credentials. A successful empty response clears discovered models. Manual models stay separate. Hosted `https://ollama.com` entries skip discovery because Ollama Cloud models are provider-managed. Without an explicit Ollama endpoint, a custom provider with `api: "ollama"` and a non-loopback `baseUrl` suppresses ambient localhost discovery; list that custom provider's models manually (see [Configuration](#configuration)). Loopback custom providers such as `http://127.0.0.2:11434` keep ambient local discovery eligible. You can use a full ref such as `ollama/:latest` without a hand-written `models.json` entry; OpenClaw resolves it live. For signed-in hosts, selecting an unlisted `ollama/:cloud` ref validates that exact model with `/api/show` and adds it to the runtime catalog only if Ollama confirms metadata — typos still fail as unknown models. ### Smoke tests For a narrow text probe that skips the full agent tool surface: ```bash OLLAMA_API_KEY=ollama-local \ openclaw infer model run \ --local \ --model ollama/llama3.2:latest \ --prompt "Reply with exactly: pong" \ --json ``` Add `--file` with an image for a lean vision-model probe (accepts PNG/JPEG/WebP; non-image files are rejected before Ollama is called — use `openclaw infer audio transcribe` for audio): ```bash OLLAMA_API_KEY=ollama-local \ openclaw infer model run \ --local \ --model ollama/qwen2.5vl:7b \ --prompt "Describe this image in one sentence." \ --file ./photo.jpg \ --json ``` Neither path loads chat tools, memory, or session context. If it succeeds while normal agent replies fail, the issue is likely the model's tool/agent capacity, not the endpoint. Selecting a model with `/model ollama/` is an exact user choice: if the configured `baseUrl` is unreachable, the next reply fails with the provider error instead of silently falling back to another configured model. Isolated cron jobs add one local safety check before starting the agent turn: if the selected model resolves to a local/private-network/`.local` Ollama provider and `/api/tags` is unreachable, OpenClaw records that run as `skipped` with the model in the error text. This endpoint check is cached for 5 minutes per host, so repeated cron jobs against a stopped daemon do not all launch failing requests. Live verification: ```bash OPENCLAW_LIVE_TEST=1 OPENCLAW_LIVE_OLLAMA=1 OPENCLAW_LIVE_OLLAMA_WEB_SEARCH=0 \ pnpm test:live -- extensions/ollama/ollama.live.test.ts ``` For Ollama Cloud, point the same live test at the hosted endpoint (skips embeddings by default; force with `OPENCLAW_LIVE_OLLAMA_EMBEDDINGS=1` since a cloud key may not authorize `/api/embed`): ```bash export OLLAMA_API_KEY='' OPENCLAW_LIVE_TEST=1 OPENCLAW_LIVE_OLLAMA=1 \ OPENCLAW_LIVE_OLLAMA_BASE_URL=https://ollama.com \ OPENCLAW_LIVE_OLLAMA_MODEL=glm-5.1:cloud \ OPENCLAW_LIVE_OLLAMA_WEB_SEARCH=1 \ pnpm test:live -- extensions/ollama/ollama.live.test.ts ``` To add a model, pull it and it is discovered automatically: ```bash ollama pull mistral ``` ## Node-local inference Agents can delegate a short task to an Ollama model on a paired desktop or server node. The prompt and response cross the existing authenticated Gateway/node connection; the request runs on the node's own loopback Ollama endpoint (`http://127.0.0.1:11434`). ```bash ollama pull qwen3:0.6b ollama list ``` ```bash openclaw node run \ --host \ --port 18789 \ --display-name "Local inference" ``` Approve the device and its node commands on the Gateway host, then verify: ```bash openclaw devices list openclaw devices approve openclaw nodes pending openclaw nodes approve openclaw nodes status --connected ``` A first connection, or an upgrade that adds Ollama commands, can trigger node-command approval. If the node connects without advertising `ollama.models` and `ollama.chat`, check `openclaw nodes pending` again. The bundled Ollama plugin exposes the `node_inference` tool. Agents call `action: "discover"` first, then `action: "run"` with a node and model from that result (`run` can omit the node when exactly one capable node is connected). For example: "Discover the Ollama models on my nodes, then use the fastest loaded model to summarize this text." Discovery reads `/api/tags`, checks `/api/show` capabilities, and uses `/api/ps` when available to rank already-loaded models first. It returns only local models Ollama reports as chat-capable (`completion` capability) — Ollama Cloud rows and embedding-only models are excluded. Each run disables model thinking and defaults output to 512 tokens (hard cap 8192) unless the tool call requests a different `maxTokens`; some models (for example GPT-OSS) do not support disabling thinking and may still emit reasoning tokens. To keep Ollama running on a node without exposing it to agents: ```bash openclaw config set plugins.entries.ollama.config.nodeInference.enabled false ``` Restart the node (`openclaw node restart`, or stop/rerun `openclaw node run` for a foreground session). The node stops advertising `ollama.models` and `ollama.chat`; Ollama itself and the Gateway's Ollama provider are unaffected. Set the value back to `true` and restart to re-enable; a changed command surface may need `openclaw nodes pending` approval again after reconnect. Verify the node commands directly, without an agent turn: ```bash openclaw nodes invoke \ --node "Local inference" \ --command ollama.models \ --params '{}' \ --invoke-timeout 90000 \ --timeout 100000 openclaw nodes invoke \ --node "Local inference" \ --command ollama.chat \ --params '{"model":"qwen3:0.6b","prompt":"Reply with exactly: pong","maxTokens":32,"timeoutMs":120000}' \ --invoke-timeout 130000 \ --timeout 140000 ``` `--invoke-timeout` bounds how long the node has to run the command; `--timeout` bounds the overall Gateway call and should be larger. Node-local inference always uses the node's own loopback endpoint — it does not reuse a configured remote/cloud `models.providers.ollama.baseUrl`. The node commands are available by default on macOS, Linux, and Windows node hosts and remain subject to normal node pairing/command policy. ## Vision and image description The bundled Ollama plugin registers Ollama as an image-capable media-understanding provider, so OpenClaw can route explicit image-description requests and configured image-model defaults through local or hosted Ollama vision models. ```bash ollama pull qwen2.5vl:7b export OLLAMA_API_KEY="ollama-local" openclaw infer image describe --file ./photo.jpg --model ollama/qwen2.5vl:7b --json ``` `--model` must be a full `` ref; when set, `infer image describe` tries that model first instead of skipping description for models that already support native vision. If the call fails, OpenClaw can continue through `agents.defaults.imageModel.fallbacks`; file/URL preparation errors fail before fallback is attempted. Use `infer image describe` for OpenClaw's image-understanding flow and configured `imageModel`; use `infer model run --file` for a raw multimodal probe with a custom prompt. To make Ollama the default image-understanding provider for inbound media: ```json5 { agents: { defaults: { imageModel: { primary: "ollama/qwen2.5vl:7b", }, }, }, } ``` Prefer the full `ollama/` ref. A bare `imageModel` ref such as `qwen2.5vl:7b` normalizes to `ollama/qwen2.5vl:7b` only when that exact model is listed under `models.providers.ollama.models` with `input: ["text", "image"]` and no other configured image provider exposes the same bare id; otherwise use the provider prefix explicitly. Slow local vision models can need a longer image-understanding timeout than cloud models, and can crash on constrained hardware if Ollama tries to allocate the model's full advertised vision context. Set a capability timeout and cap `num_ctx`: ```json5 { models: { providers: { ollama: { models: [ { id: "qwen2.5vl:7b", name: "qwen2.5vl:7b", input: ["text", "image"], params: { num_ctx: 2048, keep_alive: "1m" }, }, ], }, }, }, tools: { media: { models: [ { provider: "ollama", model: "qwen2.5vl:7b", timeoutSeconds: 300, capabilities: ["image"], }, ], image: { timeoutSeconds: 180, }, }, }, } ``` This timeout applies to inbound image understanding and to the explicit `view_image` tool. `models.providers.ollama.timeoutSeconds` still controls the underlying Ollama HTTP request guard for normal model calls. Live verification: ```bash OPENCLAW_LIVE_TEST=1 OPENCLAW_LIVE_OLLAMA_IMAGE=1 \ pnpm test:live -- src/agents/tools/image-tool.ollama.live.test.ts ``` If you define `models.providers.ollama.models` manually, mark vision models explicitly: ```json5 { id: "qwen2.5vl:7b", name: "qwen2.5vl:7b", input: ["text", "image"], contextWindow: 128000, maxTokens: 8192, } ``` OpenClaw rejects image-description requests for models not marked image-capable. With implicit discovery, this comes from `/api/show`'s vision capability. ## Configuration ```bash export OLLAMA_API_KEY="ollama-local" ``` If `OLLAMA_API_KEY` is set, you can omit `apiKey` in the provider entry; OpenClaw fills it in for availability checks. Use explicit config for hosted cloud setup, a non-default host/port, forced context windows, or fully manual model lists: ```json5 { models: { providers: { ollama: { baseUrl: "https://ollama.com", apiKey: "OLLAMA_API_KEY", api: "ollama", models: [ { id: "kimi-k2.5:cloud", name: "kimi-k2.5:cloud", reasoning: false, input: ["text", "image"], cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, contextWindow: 128000, maxTokens: 8192 } ] } } } } ``` This example uses a nonempty manual model list, so it skips discovery: ```json5 { models: { providers: { ollama: { apiKey: "ollama-local", baseUrl: "http://ollama-host:11434", // No /v1 - native Ollama API URL api: "ollama", // Explicit: guarantees native tool-calling behavior timeoutSeconds: 300, // Optional: longer connect/stream budget for cold local models models: [ { id: "qwen3:32b", name: "qwen3:32b", params: { keep_alive: "15m", // Optional: keep the model loaded between turns }, }, ], }, }, }, } ``` Do not add `/v1`. That path selects OpenAI-compatible mode, where tool calling is not reliable. ## Common recipes Replace model IDs with exact names from `ollama list` or `openclaw models list --provider ollama`. Ollama on the same machine as the Gateway, discovered automatically: ```bash ollama serve ollama pull gemma4 export OLLAMA_API_KEY="ollama-local" openclaw models list --provider ollama openclaw models set ollama/gemma4 ``` Leave `models.providers.ollama` unset to use the default local endpoint, or configure a self-hosted endpoint with `models: []` to keep discovery eligible. ```json5 { models: { providers: { ollama: { baseUrl: "http://gpu-box.local:11434", apiKey: "ollama-local", api: "ollama", timeoutSeconds: 300, maxTokens: 8192, models: [ { id: "qwen3.5:9b", name: "qwen3.5:9b", reasoning: true, input: ["text"], contextTokens: 32768, params: { num_ctx: 32768, thinking: false, keep_alive: "15m", }, }, ], }, }, }, agents: { defaults: { model: { primary: "ollama/qwen3.5:9b" }, }, }, } ``` `contextTokens` caps OpenClaw's active-input budget; `params.num_ctx` sets Ollama's request context. Keep them aligned when hardware cannot run the model's full advertised context. No local daemon, hosted models directly: ```bash export OLLAMA_API_KEY="your-ollama-api-key" ``` ```json5 { models: { providers: { ollama: { baseUrl: "https://ollama.com", apiKey: "OLLAMA_API_KEY", api: "ollama", models: [ { id: "kimi-k2.5:cloud", name: "kimi-k2.5:cloud", reasoning: false, input: ["text", "image"], contextWindow: 128000, maxTokens: 8192, }, ], }, }, }, agents: { defaults: { model: { primary: "ollama/kimi-k2.5:cloud" }, }, }, } ``` For the dedicated `ollama-cloud` provider id instead of this shape, see [Ollama Cloud](/providers/ollama-cloud). ```bash ollama signin ollama pull gemma4 ``` ```json5 { models: { providers: { ollama: { baseUrl: "http://127.0.0.1:11434", apiKey: "ollama-local", api: "ollama", timeoutSeconds: 300, models: [ { id: "gemma4", name: "gemma4", input: ["text"] }, { id: "kimi-k2.5:cloud", name: "kimi-k2.5:cloud", input: ["text", "image"] }, ], }, }, }, agents: { defaults: { model: { primary: "ollama/gemma4", fallbacks: ["ollama/kimi-k2.5:cloud"], }, }, }, } ``` Custom provider IDs when running more than one Ollama server; each gets its own host, models, auth, and timeout. ```json5 { models: { providers: { "ollama-fast": { baseUrl: "http://mini.local:11434", apiKey: "ollama-local", api: "ollama", models: [ { id: "gemma4", name: "gemma4", input: ["text"], contextTokens: 32768 }, ], }, "ollama-large": { baseUrl: "http://gpu-box.local:11434", apiKey: "ollama-local", api: "ollama", timeoutSeconds: 420, maxTokens: 16384, models: [ { id: "qwen3.5:27b", name: "qwen3.5:27b", input: ["text"], contextTokens: 131072 }, ], }, }, }, agents: { defaults: { model: { primary: "ollama-fast/gemma4", fallbacks: ["ollama-large/qwen3.5:27b"], }, }, }, } ``` OpenClaw strips the active provider prefix (falling back to a bare `ollama/` prefix) before calling Ollama, so `ollama-large/qwen3.5:27b` reaches Ollama as `qwen3.5:27b`. Local Ollama models automatically use structured [Tool Search](/tools/tool-search) when `tools.toolSearch` is unset. This keeps optional capabilities available while loading their schemas only when needed. Setup does not enable lean mode. App, interactive CLI, and non-interactive setup use a 32,768-token runtime context, or the model's native window if smaller. The advertised native window is retained separately; known cloud routes keep their hosted context. Large file reads use OpenClaw's context-based paging. The native adapter preserves those text pages and their continuation instructions; structured fallback data is bounded separately. Bound any explicit context override to what the host can support: ```json5 { agents: { entries: { local: { default: true, model: { primary: "ollama/gemma4" }, }, }, }, models: { providers: { ollama: { baseUrl: "http://127.0.0.1:11434", apiKey: "ollama-local", api: "ollama", models: [ { id: "gemma4", name: "gemma4", input: ["text"], contextTokens: 32768, params: { num_ctx: 32768 }, }, ], }, }, }, } ``` Explicit `tools.toolSearch` settings take precedence, including `false`. Tool Search does not change Ollama's context or thinking mode. Ollama thinking defaults to off; an explicit thinking setting can change that independently. If you previously enabled `localModelLean`, set it to `false` to restore optional tools while retaining automatic Tool Search. Use `compat.supportsTools: false` only when the model or server reliably fails on tool schemas; it disables tool use entirely. For a deliberately narrower agent, prefer `tools.profile` or a per-agent tool policy. ### Model selection ```json5 { agents: { defaults: { model: { primary: "ollama/gpt-oss:20b", fallbacks: ["ollama/llama3.3", "ollama/qwen2.5-coder:32b"], }, }, }, } ``` Custom provider ids work the same way: for a ref using the active provider prefix, such as `ollama-spark/qwen3:32b`, OpenClaw strips that prefix before calling Ollama, sending `qwen3:32b`. For slow local models, prefer provider-scoped tuning before raising the whole agent runtime timeout: ```json5 { models: { providers: { ollama: { timeoutSeconds: 300, models: [ { id: "gemma4:26b", name: "gemma4:26b", params: { keep_alive: "15m" }, }, ], }, }, }, } ``` `timeoutSeconds` covers the model HTTP request: connection setup, headers, body streaming, and the total guarded-fetch abort. `params.keep_alive` is forwarded as top-level `keep_alive` on native `/api/chat` requests; set it per model when first-turn load time is the bottleneck. ### Quick verification ```bash # Ollama daemon visible to this machine curl http://127.0.0.1:11434/api/tags # OpenClaw catalog and selected model openclaw models list --provider ollama openclaw models status # Direct model smoke openclaw infer model run \ --model ollama/gemma4 \ --prompt "Reply with exactly: ok" ``` For remote hosts, replace `127.0.0.1` with the `baseUrl` host. If `curl` works but OpenClaw does not, check whether the Gateway runs on a different machine, container, or service account. ## Ollama Web Search OpenClaw bundles **Ollama Web Search** as a `web_search` provider. | Property | Detail | | ----------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------- | | Host | `models.providers.ollama.baseUrl` when set, otherwise `http://127.0.0.1:11434`; `https://ollama.com` uses the hosted API directly | | Auth | Key-free for a signed-in local host; `OLLAMA_API_KEY` or configured provider auth for direct `https://ollama.com` search or auth-protected hosts | | Requirement | Local/self-hosted hosts must be running and signed in with `ollama signin`; direct hosted search needs `baseUrl: "https://ollama.com"` plus a real API key | Choose it during `openclaw onboard` or `openclaw configure --section web`, or set: ```json5 { tools: { web: { search: { provider: "ollama", }, }, }, } ``` For direct hosted search through Ollama Cloud: ```json5 { models: { providers: { ollama: { baseUrl: "https://ollama.com", apiKey: "OLLAMA_API_KEY", api: "ollama", models: [{ id: "kimi-k2.5:cloud", name: "kimi-k2.5:cloud", input: ["text"] }], }, }, }, tools: { web: { search: { provider: "ollama" }, }, }, } ``` For a self-hosted host, OpenClaw first tries the local `/api/experimental/web_search` proxy, then falls back to the hosted `/api/web_search` path on the same host; a signed-in local daemon normally answers through the local proxy. Direct `https://ollama.com` calls always use the hosted `/api/web_search` endpoint. For full setup and behavior, see [Ollama Web Search](/tools/ollama-search). ## Advanced configuration **Tool calling is not reliable in this mode.** Use it only when a proxy needs OpenAI format and you do not depend on native tool calling. Set `api: "openai-completions"` explicitly for a proxy behind `/v1/chat/completions`: ```json5 { models: { providers: { ollama: { baseUrl: "http://ollama-host:11434/v1", api: "openai-completions", injectNumCtxForOpenAICompat: true, // default: true apiKey: "ollama-local", models: [...] } } } } ``` This mode may not support streaming and tool calling simultaneously; you may need `params: { streaming: false }` on the model. OpenClaw injects `options.num_ctx` by default in this mode so Ollama does not silently fall back to a 4096-token context. If your proxy rejects unknown `options` fields, disable it: ```json5 { models: { providers: { ollama: { baseUrl: "http://ollama-host:11434/v1", api: "openai-completions", injectNumCtxForOpenAICompat: false, apiKey: "ollama-local", models: [...] } } } } ``` For auto-discovered models, OpenClaw uses the context window `/api/show` reports, including larger `PARAMETER num_ctx` values from custom Modelfiles; otherwise it falls back to OpenClaw's default Ollama context window. Per-model `contextWindow` declares native window metadata, and per-model `contextTokens` caps active input. Provider-level `maxTokens` remains an output-token default; a model entry can override it. Native `/api/chat` requests set `options.num_ctx` from a positive `params.num_ctx` first, then from the effective model `contextTokens` when present. Local discovery normally caps `contextTokens` at 32,768 (or the model's smaller native window), so OpenClaw can override a smaller Modelfile context even without an explicit `params.num_ctx`. Invalid, zero, negative, or non-finite `params.num_ctx` values are ignored. Only when neither value is available does Ollama choose its own model, Modelfile, `OLLAMA_CONTEXT_LENGTH`, or VRAM-based default; the native adapter does not fall back directly to the advertised `contextWindow`. After upgrading an older configuration, run `openclaw doctor --fix`. Doctor preserves current `contextTokens` caps without creating a stronger model or provider `num_ctx` pin; uncapped legacy native entries still migrate their older context budgets. Existing explicit `params.num_ctx` values remain authoritative, including pins an older Doctor already wrote. Review or remove an oversized existing pin to let `contextTokens` drive the request again. Use `params.num_ctx` to override the native request context explicitly. The OpenAI-compatible adapter still injects `options.num_ctx` by default from `params.num_ctx`, then the matching model entry's `contextTokens` or `contextWindow`; disable with `injectNumCtxForOpenAICompat: false` if the upstream rejects `options`. Native model entries also accept common Ollama runtime options under `params`, forwarded as native `/api/chat` `options`: `num_keep`, `seed`, `num_predict`, `top_k`, `top_p`, `min_p`, `typical_p`, `repeat_last_n`, `temperature`, `repeat_penalty`, `presence_penalty`, `frequency_penalty`, `stop`, `num_batch`, `num_gpu`, `main_gpu`, `use_mmap`, and `num_thread`. Runtime sampling controls (`temperature`, `topP`, `frequencyPenalty`, `presencePenalty`, and `seed`) override the matching model defaults, including explicit zero values. The Gateway's Chat Completions API maps `top_p`, `frequency_penalty`, and `presence_penalty` to these controls. With `temperature: 0`, OpenClaw still normalizes `top_p` to `1` for greedy sampling after applying overrides. A few keys (`format`, `keep_alive`, `truncate`, `shift`) are forwarded as top-level request fields instead of nested `options`. Local native chat requests default to `truncate: false` and `shift: false`, so supporting servers reject overflowing input instead of silently dropping history. OpenClaw then attempts compaction and retries, or reports the failure. Generation that fills the window can still produce a labeled partial reply. This behavior is verified with Ollama 0.33.3; older servers may ignore the fields. Explicit per-model values override these defaults. Hosted models and the OpenAI-compatible endpoint keep their existing behavior. OpenClaw only forwards these Ollama request keys, so runtime-only params such as `streaming` are never sent to Ollama. Use `params.think` (or `params.thinking`) to set top-level `think`; `false` disables API-level thinking for Qwen-style thinking models. ```json5 { models: { providers: { ollama: { models: [ { id: "llama3.3", contextWindow: 131072, contextTokens: 32768, maxTokens: 65536, params: { num_ctx: 32768, temperature: 0.7, top_p: 0.9, thinking: false, }, } ] } } } } ``` Per-model `agents.defaults.models["ollama/"].params.num_ctx` also works; the explicit provider model entry wins if both are set. Native local Ollama compaction summaries default to thinking off. This keeps summarization from using its default three-minute request window for reasoning; Qwen3.5 treats `low` as thinking enabled rather than a reduced thinking budget. An explicit `agents.defaults.compaction.thinkingLevel` overrides this preference. Existing per-model `params.think`/`params.thinking` settings keep their normal precedence. Hosted routes keep their compaction defaults. OpenClaw forwards thinking as Ollama expects it: top-level `think`, not `options.think`. Auto-discovered models whose `/api/show` reports a `thinking` capability expose `/think low`, `/think medium`, `/think high`, and `/think max`; non-thinking models expose only `/think off`. ```bash openclaw agent --model ollama/gemma4 --thinking off openclaw agent --model ollama/gemma4 --thinking low ``` Or set a model default: ```json5 { agents: { defaults: { models: { "ollama/gemma4": { params: { thinking: "low" }, }, }, }, }, } ``` Per-model `params.think`/`params.thinking` can disable or force API thinking for a specific model. OpenClaw preserves that explicit config when the active run only has the implicit `off` default; a non-off runtime command such as `/think medium` still overrides it. A truthy thinking request is never sent to a model explicitly marked `reasoning: false`; a `think: false` request is always sent regardless. Models named `deepseek-r1`, `reasoning`, `reason`, or `think` are treated as reasoning-capable by default — no extra config needed: ```bash ollama pull deepseek-r1:32b ``` Ollama runs locally and is free, so all model costs are `0` for both auto-discovered and manually defined models. The bundled Ollama plugin registers a memory embedding provider for [memory search](/concepts/memory). It uses the configured Ollama base URL and API key, calls `/api/embed`, and batches multiple memory chunks into one `input` request when possible. When `proxy.enabled=true`, embedding requests to the exact host-local loopback origin derived from the configured `baseUrl` use OpenClaw's guarded direct path instead of the managed forward proxy. The configured hostname must itself be `localhost` or a loopback IP literal — DNS names that merely resolve to loopback still use the managed proxy path. LAN, tailnet, private-network, and public Ollama hosts always stay on the managed proxy path, and redirects to another host/port do not inherit trust. `proxy.loopbackMode: "proxy"` routes loopback traffic through the proxy anyway; `proxy.loopbackMode: "block"` denies it before connecting — see [Managed proxy](/security/network-proxy#gateway-loopback-mode). | Property | Value | | --- | --- | | Default model | `nomic-embed-text` | | Auto-pull | Yes, if not present locally | | Embedding concurrency | Provider-owned; no memory-search tuning key is required | Query-time embeddings use retrieval prefixes for models that require or recommend them: `nomic-embed-text`, `qwen3-embedding`, and `mxbai-embed-large`. Document batches stay raw, so existing indexes need no format migration. Embedding concurrency and batching behavior are owned by the Ollama memory provider. For a remote embedding host, use the supported `remote.baseUrl` and `remote.apiKey` fields to keep auth scoped to that host: ```json5 { memory: { search: { provider: "ollama", model: "nomic-embed-text", remote: { baseUrl: "http://gpu-box.local:11434", apiKey: "ollama-local", }, }, }, } ``` Ollama uses the **native API** (`/api/chat`) by default, which supports streaming and tool calling together — no special config needed. For native requests, thinking control is forwarded directly: `/think off` and `openclaw agent --thinking off` send top-level `think: false` unless an explicit `params.think`/`params.thinking` is configured; `/think low|medium|high` send the matching effort string. Verified full-effort Ollama Cloud families such as GLM 5.2 and DeepSeek V4 also send native `think: "max"` for `/think max`; other models and local servers keep the compatible `think: "high"` mapping. For the OpenAI-compatible endpoint instead, see "Legacy OpenAI-compatible mode" above — streaming and tool calling may not work together there. ## Troubleshooting On WSL2 with NVIDIA/CUDA, the official Ollama Linux installer creates an `ollama.service` systemd unit with `Restart=always`. If that service autostarts and loads a GPU-backed model during WSL2 boot, Ollama can pin host memory while loading; Hyper-V memory reclaim cannot always reclaim those pages, so Windows can terminate the WSL2 VM, systemd restarts Ollama, and the loop repeats. Evidence: repeated WSL2 reboots/terminations, high CPU in `app.slice` or `ollama.service` right after WSL2 startup, and SIGTERM from systemd rather than the Linux OOM killer. OpenClaw logs a startup warning when it detects WSL2, `ollama.service` enabled with `Restart=always`, and visible CUDA markers. Mitigation: ```bash sudo systemctl disable ollama ``` On the Windows side, add this to `%USERPROFILE%\.wslconfig`, then run `wsl --shutdown`: ```ini [experimental] autoMemoryReclaim=disabled ``` Or shorten keep-alive / start Ollama manually only when needed: ```bash export OLLAMA_KEEP_ALIVE=5m ollama serve ``` See [ollama/ollama#11317](https://github.com/ollama/ollama/issues/11317). Confirm Ollama is running and is in the agent's model scope. For ambient localhost discovery, set `OLLAMA_API_KEY` (or an auth profile). A nonempty manual model list skips discovery; an explicit self-hosted endpoint with `models: []` does not: ```bash ollama serve curl http://localhost:11434/api/tags ``` Pull the model locally, or define it explicitly in `models.providers.ollama`: ```bash ollama list # See what's installed ollama pull gemma4 ollama pull gpt-oss:20b ollama pull llama3.3 # Or another model ``` ```bash # Check if Ollama is running ps aux | grep ollama # Or restart Ollama ollama serve ``` Verify from the same machine and runtime that runs the Gateway: ```bash openclaw gateway status --deep curl http://ollama-host:11434/api/tags ``` Common causes: - `baseUrl` points at `localhost`, but the Gateway runs in Docker or on another host. - The URL uses `/v1`, selecting OpenAI-compatible behavior instead of native Ollama. - The remote host needs firewall or LAN binding changes. - The model is on your laptop's daemon but not the remote one. Usually the provider is in OpenAI-compatible mode, or the model cannot handle tool schemas. Prefer native mode: ```json5 { models: { providers: { ollama: { baseUrl: "http://ollama-host:11434", api: "ollama", }, }, }, } ``` If a small local model still fails on tool schemas, set `compat.supportsTools: false` on that model entry and retest. Hosted Kimi/GLM responses that are long, non-linguistic symbol runs are treated as a failed provider call rather than a successful reply, so normal retry/fallback/error handling takes over instead of persisting corrupted text into the session. If it recurs, capture the model name, the current session file, and whether the run used `Cloud + Local` or `Cloud only`, then try a fresh session and a fallback model: ```bash openclaw infer model run --model ollama/kimi-k2.5:cloud --prompt "Reply with exactly: ok" --json openclaw models set ollama/gemma4 ``` Large local models can need a long first load. Scope the timeout to the Ollama provider and optionally keep the model loaded between turns: ```json5 { models: { providers: { ollama: { timeoutSeconds: 300, models: [ { id: "gemma4:26b", name: "gemma4:26b", params: { keep_alive: "15m" }, }, ], }, }, }, } ``` If the host itself is slow to accept connections, `timeoutSeconds` also extends the guarded connect timeout for this provider. Many models advertise contexts larger than your hardware can run comfortably. Native requests forward the effective `contextTokens` unless `params.num_ctx` overrides it. Cap both OpenClaw's budget and Ollama's request context for predictable first-token latency: ```json5 { models: { providers: { ollama: { maxTokens: 8192, models: [ { id: "qwen3.5:9b", name: "qwen3.5:9b", contextTokens: 32768, params: { num_ctx: 32768, thinking: false }, }, ], }, }, }, } ``` Lower the model entry's `contextTokens` if OpenClaw sends too much prompt. Lower `params.num_ctx` if Ollama's runtime context is too large for the machine. Lower `maxTokens` if generation runs too long. More help: [Troubleshooting](/help/troubleshooting) and [FAQ](/help/faq). ## Related Cloud-only setup with the dedicated `ollama-cloud` provider. Overview of all providers, model refs, and failover behavior. How to choose and configure models. Full setup and behavior details for Ollama-powered web search. Full config reference.