feat: document setup, explain unwritable persist paths, add GPU offload - #171
Merged
Merged
Conversation
Three friction points made the stack hard to set up and slow to run. Setup was undocumented: CONTRIBUTING said "Install Task 3.x" with no link or command, and nothing listed the other prerequisites. Adds a prerequisite table (Task, uv, Python, Docker Compose, Ollama) with per-platform install commands and a verification block, cross-linked from README, AGENTS.md, and docs/agent-navigation.md. An unwritable Chroma persist path surfaced as SQLite's bare "attempt to write a readonly database", naming neither the path nor the cause. Adds PersistPathError, raised from a single _connect helper covering both VectorStore.create and .open plus the mkdir path, reporting the resolved path, its owner, and the remedy. The remedy branches on cause: a path owned by another user needs chown, one with bad mode bits needs chmod, and suggesting the wrong one sends the reader down a dead end. Unrelated client errors re-raise untouched. README gains a Troubleshooting section covering this and the plugin-registry error that wraps it. The chromadb healthcheck used CMD-SHELL with /dev/tcp, a bash builtin the image's dash /bin/sh lacks, so it failed forever regardless of Chroma's state (65 consecutive failures observed) while other services waited on service_healthy. Switches to CMD with bash, which the image ships. Ollama ran on CPU with no way to opt into a GPU, holding ingest to ~4.7 chunks/s. Adds docker-compose.gpu.yml as an opt-in override so CPU-only hosts keep working, and corrects CONTRIBUTING, which claimed the Compose file already requested a GPU. Measured on an RTX 4070 Ti: 4193 chunks in 224s (18.7 chunks/s) versus 4.7 on CPU, with "offloaded 13/13 layers to GPU" confirming the offload. Claude-Session: https://claude.ai/code/session_0159MZxHDCaAxhZB9V1ab8oJ
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.
Four setup and performance friction points found while getting the stack running locally.
Setup was undocumented
CONTRIBUTING said "Install Task 3.x" with no link and no command, and nothing listed the other prerequisites. Adds a prerequisite table (Task, uv, Python 3.13+, Docker Compose v2, Ollama) with official install links, per-platform Task install commands, and a verification block. Cross-linked from README,
AGENTS.md, anddocs/agent-navigation.md, each noting Task is optional since every task maps to a plainuv run ….Unwritable persist path gave an undiagnosable error
A persist directory owned by another user surfaced as SQLite's bare
attempt to write a readonly database, naming neither the path nor the cause — and reaching the user wrapped inPluginExecutionError: Unable to create retriever plugin 'builtin', which hides it further.Adds
PersistPathError, raised from a single_connecthelper covering bothVectorStore.createand.open(the only twoPersistentClientcall sites) plus themkdirpath for an unwritable parent:The remedy branches on cause — another user's directory needs
chown, one with bad mode bits needschmod. Suggesting the wrong one sends the reader down a dead end. Unrelated client errors re-raise untouched. README gains a Troubleshooting section covering this and the plugin wrapper.chromadb healthcheck could never pass
The probe was
CMD-SHELL "echo > /dev/tcp/localhost/8000", but/dev/tcpis a bash builtin and the image's/bin/shis dash:65 consecutive failures observed while Chroma was serving normally. This is more than cosmetic — other services gate on
depends_on: condition: service_healthy. Switched toCMDwithbash, which the image ships. Verified:STATUS=healthy failing=0after recreate.Ollama ran on CPU with no way to opt into a GPU
Embedding dominated ingest at ~4.7 chunks/s, flat across file sizes. Adds
docker-compose.gpu.ymlas an opt-in override, so the base stack keeps working on hosts without a GPU:Also corrects CONTRIBUTING, which claimed the Compose file already requested an NVIDIA GPU — it had no GPU block at all.
Verification
Measured end to end on an RTX 4070 Ti, deleting the
localragcollection and re-ingesting through the GPU override:offloaded 13/13 layers to GPUon CUDA0 confirms the offload; 4193 vectors restored exactly, and a query returned correctly grounded answers with sources.Gates: ruff, ruff format, mypy (100 files), and bandit all clean. 480 unit tests pass, 4 of them new (both remedy branches, unwritable parent, non-permission passthrough).
Note for reviewers
The unit suite reads a developer's real
.env, so 26 tests fail locally whenever one exists (480 passedwith it moved aside,26 failedwith it present). Pre-existing onmainand unrelated to these changes — filed separately rather than widening this branch.https://claude.ai/code/session_0159MZxHDCaAxhZB9V1ab8oJ