You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: CLAUDE.md
+15-12Lines changed: 15 additions & 12 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -4,11 +4,12 @@ This file provides guidance to Claude Code (claude.ai/code) when working with co
4
4
5
5
## Stack overview
6
6
7
-
Containerised RAG system for Obsidian Markdown vaults. Uses **Podman** (not Docker) via `podman compose`. Three services:
7
+
Containerised RAG system for Obsidian Markdown vaults. Uses **Podman** (not Docker) via `podman compose`. Two services:
8
8
-**rag** (`app/`) — FastAPI server + indexer, built from `app/Dockerfile`
9
-
-**ollama** — local LLM and embedding model server
10
9
-**watcher** (`app/watcher.py`) — watchdog sidecar that posts changed paths to the RAG API
11
10
11
+
Ollama runs **on the host** (Metal GPU on macOS); containers reach it via `host.containers.internal:11434`. There is no `ollama` container service.
12
+
12
13
Embeddings and chunks persist in **Chroma** (`/index/chroma` volume). Index state (mtimes + chunk counts per file) is tracked in `index_state.json` alongside the Chroma DB.
13
14
14
15
## Common commands
@@ -22,8 +23,8 @@ make logs-watcher # tail watcher logs
22
23
make ps # show container status
23
24
make shell # bash into rag container
24
25
25
-
# First-time model pull (after make up)
26
-
make pull
26
+
# First-time model pull (run before make up)
27
+
make ollama-bootstrap
27
28
28
29
# Indexing
29
30
make reindex # full incremental reindex
@@ -32,14 +33,14 @@ make reindex-files # partial reindex for specific files (prompts for paths)
32
33
make reindex-status # check last reindex result
33
34
34
35
# Debugging retrieval
35
-
make debug-retrieve # vector search only, no metadata
36
-
make debug-retrieve-dated # vector search with metadata (date, entities, etc.)
36
+
make retrieve# vector search only, no metadata
37
+
make retrieve-dated# vector search with metadata (date, entities, etc.)
37
38
make parse-dates # test date parsing on a query
38
39
39
40
# Querying
40
41
make ask # single question, blocking
41
42
make ask-stream # streaming answer
42
-
./chat.sh# interactive chat loop
43
+
make chat # interactive chat loop (python3 chat.py)
43
44
44
45
# MCP
45
46
make mcp-install # install scripts/requirements.txt for MCP server
@@ -59,15 +60,15 @@ make test # run full suite with coverage report
-`entities` — comma-separated `prefix:Value` strings from spaCy NER (PERSON, ORG, GPE, WORK_OF_ART), merged from file-level and chunk-level extraction
93
+
-`tags` — from frontmatter `tags` field (list or string, normalised to space-separated string)
92
94
-`chunk_index` — position within the file
93
95
94
-
Each chunk's embedded text is prefixed with `[title: ...] [entities: ...] [source: ...] [date: ...]` to strengthen metadata relevance in vector search.
96
+
Each chunk's embedded text is prefixed with `[title: ...] [entities: ...] [source: ...] [date: ...] [tags: ...]` to strengthen metadata relevance in vector search.
95
97
96
98
### Retrieval logic (`rag_server._retrieve`)
97
99
@@ -125,7 +127,7 @@ All settings are in `app/settings.py` via env vars. Key ones:
125
127
-`RAG_URL` — base URL for the running RAG API (default: `http://localhost:8000`)
-`read_note`, `list_notes`, `create_note`, `update_note`, `delete_note`, `lint_note` — provided by obsidian-mcp-guard (path safety, write-vault isolation, mdlint-obsidian validation built in)
130
132
131
133
`fastmcp` and `obsidian-mcp-guard` are real installed packages in the test venv; no stubbing needed. `conftest.py` sets `HOST_VAULT_PATH=/tmp/test-vault-root` so `create_vault_server()` doesn't error at import time.
@@ -154,3 +156,4 @@ Tests live in `tests/` and run **locally** (no container). Use `make test` to ru
154
156
-`entry_date_ts` was added later; a full reindex is needed on existing installations to backfill it.
155
157
- Chroma persistence is automatic (`PersistentClient`); do not call `.persist()` explicitly.
156
158
- The watcher uses `RAG_FILES_URL` to call `/reindex/files`; if that fails it falls back to `/reindex` (full).
159
+
-`NUM_PREDICT` defaults to `-1` (unlimited). Do **not** set a low value (e.g. 256 or 800) — thinking models (like gemma4) consume their entire token budget reasoning before generating any response, so a low cap produces empty answers.
-`GET /retrieve/dated?q=...&k=5` → top-k candidates with full metadata; response includes `filter` showing the parsed date range that was applied.
110
+
111
+
### Indexing
109
112
-`POST /reindex` → full incremental reindex.
110
113
-`POST /reindex/scan` → enumerate vault and queue only changed/removed files since last index state, then partial reindex.
111
114
-`POST /reindex/files` → partial reindex of given `{"files": ["path.md", ...]}` relative to the vault.
112
115
-`GET /reindex/status` → last reindex summary.
113
116
117
+
### Utilities
118
+
-`GET /utils/parse-dates?q=...` → parsed `{start, end}` date range for a query string; useful for verifying date extraction.
119
+
-`POST /utils/split-by-date` → show how a markdown document is split by date headings; POST form field `text` or upload a `file`.
120
+
114
121
## Startup indexing
115
122
- On container start, if `REINDEX_ON_START=true`, `app/run.sh` triggers `POST /reindex/scan`.
116
123
- The scan compares current vault mtimes vs `index_state.json` and queues only changed/removed files, then calls the same partial reindex worker path the watcher uses.
@@ -156,15 +163,15 @@ markdown-rag/
156
163
|`make reindex-files`| Partial reindex for specific vault-relative paths (prompts for input). |
157
164
|`make reindex-status`| Show last reindex result. |
158
165
159
-
### Querying / debugging
166
+
### Querying
160
167
161
168
| Target | Description |
162
169
|--------|-------------|
163
170
|`make ask`| Interactive single question (blocking). |
164
171
|`make ask-stream`| Interactive single question (streaming). |
165
-
|`make debug-retrieve`| Vector search only, no metadata in response. |
166
-
|`make debug-retrieve-dated`| Vector search with full metadata (date, entities, etc.). |
167
-
|`make parse-dates`|Test date parsing on a query. |
172
+
|`make retrieve`| Vector search, returns source/title/date/snippet per result. |
173
+
|`make retrieve-dated`| Vector search with full metadata; shows the date filter that was applied. |
174
+
|`make parse-dates`|Show the parsed date range for a query; useful for verifying date extraction. |
168
175
169
176
### Podman machine (macOS)
170
177
@@ -197,15 +204,15 @@ make test # run all tests with coverage
197
204
198
205
### Coverage
199
206
200
-
230 tests across 8 files; overall coverage ~93% on `app/` modules:
207
+
222 tests across 8 files; overall coverage ~91% on `app/` modules:
201
208
202
209
| Module | Coverage |
203
210
|--------|----------|
204
211
|`settings.py`, `md_loader.py`| 100% |
205
212
|`rag_server.py`| 97% |
206
-
|`date_parser.py`, `watcher.py`| 96% |
207
-
|`indexer.py`|84% |
208
-
|`name_parser.py`| 83% |
213
+
|`watcher.py`| 96% |
214
+
|`date_parser.py`|93% |
215
+
|`indexer.py`, `name_parser.py`| 83% |
209
216
210
217
## Troubleshooting
211
218
-**No results for sentence queries with a name**: ensure your notes have the person name in title, filename, headings, or a parent folder (so it gets into `entities`). Run `make reindex`.
0 commit comments