ECDO is a local-first hybrid search + RAG system over a corpus of
anomaly-research, geology, earth-history / polar-motion, and Hermetic
literature. Documents are extracted from PDFs/EPUBs with MinerU, chunked,
embedded (nomic-embed-text via Ollama), and indexed in LanceDB.
Search fuses dense-vector, lexical (boolean), and reciprocal-rank-fusion
results.
| Syntax | Meaning |
|---|---|
word | Required term — AND with other bare words. |
"exact phrase" | Phrase that must appear verbatim. |
+required | Explicit required token. |
-excluded / NOT excluded | Token must not appear. |
!fuzzy term | Soft / substring match — bonus only, not mandatory. |
A NEAR B | A and B co-occur within ~8 words (windowed). |
A OR B | Either clause may match (OR across clauses). |
A AND B | Explicit AND (default for bare words). |
OR into clauses. A document
matches if any clause is satisfied; within a clause, terms are
AND'd. So volcano OR earthquake mantle means
(volcano) OR (earthquake AND mantle) — OR binds looser than AND.
| Mode | Behaviour |
|---|---|
hybrid default | Vector + lexical, fused with RRF. Best general recall. |
vector | Dense semantic similarity only. |
lexical | Pure boolean / keyword — operators apply strictly. |
volcano earthquake # both words volcano OR earthquake # either word volcano OR earthquake mantle # (volcano) OR (earthquake AND mantle) "hermetic" OR "kybalion" # either phrase polar motion NOT noise # both words, exclude "noise" mars NEAR water # co-occurrence within 8 words catastrophism !comet # term + soft bonus, not mandatory
Base URL: http://127.0.0.1:8800 (also reachable on the LAN /
Tailscale IP on port 8800). All responses are JSON. search is
also available as a GET for convenience.
| Method | Endpoint | Description |
|---|---|---|
| POST / GET | /api/v1/search?q=&top_k=&mode=&target=&fold= |
Ranked chunks. Honors all search syntax + modes. target scopes to a classified category; fold=false returns raw chunks. |
| GET | /api/v1/doc?rel=<rel_path> |
Full extracted text of a source document (chunks joined) plus the chunk list. |
| GET | /api/v1/chunk?rel=<rel>&idx=<n> |
A single chunk by index. |
| GET | /api/v1/image?rel=<rel>&name=<file>&b64=1 |
Image artifact — base64 JSON (b64=1) for direct reuse, or raw binary otherwise. |
| GET | /api/v1/artifacts?rel=<rel> |
PDF / JSON / image metadata for a document. |
| GET | /api/v1/doi?rel=<rel>&title=<t> |
DOI — embedded in the PDF header, else a Crossref fallback (title-guarded). |
| GET | /api/v1/health · /api/v1/stats |
Engine + UI status; indexed chunk count; live queue depth. |
| GET | /api/parse-query?q= |
Parsed operators (phrases / required / excluded / fuzzy / near / segments) — powers the syntax chips. |
Let agents prioritise active research: promote existing queue items to the
front, or add already-ingested corpus docs (present under RAG/ but
not yet queued) to the front for re-processing. New files dropped into the RAG
folder are automatically unshifted to the front of the queue.
| Method | Endpoint | Description |
|---|---|---|
| GET | /api/ingest-queue |
Full queue: paused, parallel, queue_len,
active (in-flight jobs w/ progress), and the ordered queue list. |
| POST | /api/ingest-settings {paused, parallel} |
Pause (or set parallel 0–8) / resume ingestion. |
| POST | /api/ingest-reorder {order:[rel_keys]} |
Replace the queue order with the given full rel_key list. |
| POST | /api/ingest-promote {rel_keys:[...]} |
Move existing queue items to the FRONT (top), preserving listed order. Ignores unknown keys. |
| POST | /api/ingest-add {rel_keys:[...], manual?} |
Add existing corpus docs (not yet queued) to the FRONT; already-queued docs are promoted, not duplicated. |
| POST | /api/upload (multipart file) |
Upload a new document to the RAG folder; it is placed at the top of the queue (manual). |
curl -X POST http://127.0.0.1:8800/api/v1/search \
-H 'Content-Type: application/json' \
-d '{"query":"polar motion earth rotation","top_k":8,"mode":"hybrid"}'
curl "http://127.0.0.1:8800/api/v1/search?q=volcano%20OR%20earthquake&top_k=5"
curl "http://127.0.0.1:8800/api/v1/doc?rel=root/1908kybalion/1908kybalion/vlm/1908kybalion.md"
curl "http://127.0.0.1:8800/api/v1/image?rel=root/x/vlm/x.md&name=fig1.png&b64=1"
A zero-dependency client is bundled at the repo root
(ecdo_client.py) — usable from any Python 3, or as a CLI:
python3 ecdo_client.py search "polar motion" --top-k 8 --mode hybrid python3 ecdo_client.py doc "root/1908kybalion/1908kybalion/vlm/1908kybalion.md" python3 ecdo_client.py image "root/x/vlm/x.md" "fig1.png" --out /tmp/fig1.png python3 ecdo_client.py health python3 ecdo_client.py stats
ECDO is also registered as a Hermes local search provider (MCP server
ecdo, enabled). Tools: search, get_text,
get_chunk, list_artifacts, get_image
(base64), get_doi, health — usable alongside
SearXNG / web search.
hermes mcp list # ecdo → enabled, 7 tools hermes mcp test ecdo # connectivity + tool discovery
Drop source files into RAG/ — including subfolders
(the ingestor traverses recursively). Supported:
.pdf .epub .jpg .jpeg .png .webp .tiff .bmp. The daemon picks
them up automatically; MinerU's own working trees (vlm/,
images/, .mineru_output/) are excluded. The status
bar shows live queue depth.