Local no-API-key mode: Ollama sidecar + compact local runtime#13
Merged
Conversation
Run the whole stack with zero API keys: COMPOSE_PROFILES=local adds an Ollama sidecar whose models are baked into the image at build time (qwen2.5:1.5b + qwen3-embedding:0.6b, ~2 GB; nothing downloads after the stack is up). Real keys, when present, always win. Engine: with no key configured, the runner dispatches jobs to a new LocalOllamaRuntime (AgentRuntime.local_runtime() hook) — a compact tool-calling loop over Ollama's native /api/chat with the role prompt, the workspace tools, and the attached MCP servers' tools (CLAUDE_ENGINE_LOCAL_REMOTE_TOOLS, '*' = all), plus its own FS session store for resume. The Claude CLI path is impractical locally: its ~21.5K-token scaffolding takes minutes of CPU prompt-eval per turn, while the compact loop answers in ~30s (follow-ups in seconds via the prefix cache, OLLAMA_NUM_PARALLEL=1). Indexer: embedding provider default becomes "auto" (voyage → openai → ollama by configured credential) with a new OllamaProvider over /api/embed; no key now degrades to local embeddings instead of disabling semantic search. Sidecar tuning baked into the text model's Modelfile (not global env, so the embedding model keeps its small KV cache): num_ctx 16384 and num_thread 4 — pinned threads are dramatically faster than llama.cpp's all-cores default on laptops (measured 31.6 vs 0.1 tok/s). The entrypoint pre-loads the text model so the first turn skips the cold load. Non-reasoning model on purpose: reasoning models burn the whole turn "thinking" on CPU. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01D6Wso8dGjAk7QrjvHWy5ma
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
Run the whole stack with zero API keys: uncomment
COMPOSE_PROFILES=localin.envandmake up. An Ollama sidecar serves a small local text model + code embeddings, with both models baked into the image at build time (~2 GB download at first build; nothing downloads after the stack is up). Real keys, when present, always win — a keyed setup is byte-identical to today.How
Engine —
LocalOllamaRuntime(engine_core/local_runtime.py)/api/chatvia the newAgentRuntime.local_runtime()hook — not the Claude CLI, whose ~21.5K-token scaffolding takes minutes of CPU prompt-eval per turn.CLAUDE_ENGINE_LOCAL_REMOTE_TOOLS, default*= all; narrow it if a small model stops calling tools).Indexer —
autoembedding providervoyage→auto: voyage (key) → openai (key) → ollama (sidecar) — no key now means local embeddings instead of "semantic search disabled".OllamaProviderover/api/embed(1024-dimqwen3-embedding:0.6b, matchesDEXIASK_EMBEDDING_DIM; retry/backoff, offline constructor, dim guard).Sidecar —
ollama/OLLAMA_MODELS=/models;/root/.ollamais a shadowed VOLUME).num_ctx 16384,num_thread 4— pinned threads measured 31.6 vs 0.1 tok/s against llama.cpp's all-cores default on laptops.OLLAMA_NUM_PARALLEL=1so the prefix cache makes follow-up turns fast.qwen2.5:1.5b— deliberately non-reasoning (reasoning models burn the whole turn "thinking" on CPU) and tool-capable.Verified end-to-end (no keys, CPU-only laptop)
semantic_search→ grounded answer naming the right file, ~50sTests
tests/core/test_local_runtime.py— streaming, tool dispatch, session resume, truncation, arg parsing; runner swap/precedence tests), ruff cleanautoresolution matrix), ruff cleango test+go vet, web vitest: green🤖 Generated with Claude Code
https://claude.ai/code/session_01D6Wso8dGjAk7QrjvHWy5ma