Skip to content

feat: document setup, explain unwritable persist paths, add GPU offload - #171

Merged
n0nuser merged 1 commit into
mainfrom
feat/setup-docs-persist-path-errors-gpu-offload
Aug 6, 2026
Merged

feat: document setup, explain unwritable persist paths, add GPU offload#171
n0nuser merged 1 commit into
mainfrom
feat/setup-docs-persist-path-errors-gpu-offload

Conversation

@n0nuser

@n0nuser n0nuser commented Aug 6, 2026

Copy link
Copy Markdown
Owner

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, and docs/agent-navigation.md, each noting Task is optional since every task maps to a plain uv 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 in PluginExecutionError: Unable to create retriever plugin 'builtin', which hides it further.

Adds PersistPathError, raised from a single _connect helper covering both VectorStore.create and .open (the only two PersistentClient call sites) plus the mkdir path for an unwritable parent:

PersistPathError: Chroma persist path is not writable: /home/user/dev/LocalRAG/data/chroma
(owned by root:root, running as user:user). Fix ownership with:
sudo chown -R $(id -un):$(id -gn) /home/user/dev/LocalRAG/data/chroma
— or point CHROMA_PERSIST_PATH at a directory you own.

The remedy branches on cause — another user's directory needs chown, one with bad mode bits needs chmod. 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/tcp is a bash builtin and the image's /bin/sh is dash:

/bin/sh: 1: cannot create /dev/tcp/localhost/8000: Directory nonexistent

65 consecutive failures observed while Chroma was serving normally. This is more than cosmetic — other services gate on depends_on: condition: service_healthy. Switched to CMD with bash, which the image ships. Verified: STATUS=healthy failing=0 after 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.yml as an opt-in override, so the base stack keeps working on hosts without a GPU:

docker compose -f docker-compose.yml -f docker-compose.gpu.yml up -d

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 localrag collection and re-ingesting through the GPU override:

CPU GPU
Rate 4.7 chunks/s 18.7 chunks/s
4193 chunks ~15 min 224 s

offloaded 13/13 layers to GPU on 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 passed with it moved aside, 26 failed with it present). Pre-existing on main and unrelated to these changes — filed separately rather than widening this branch.

https://claude.ai/code/session_0159MZxHDCaAxhZB9V1ab8oJ

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
@n0nuser
n0nuser enabled auto-merge (rebase) August 6, 2026 16:38
@n0nuser
n0nuser merged commit fbe663b into main Aug 6, 2026
6 of 12 checks passed
@n0nuser
n0nuser deleted the feat/setup-docs-persist-path-errors-gpu-offload branch August 6, 2026 16:43
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant