dsh-plugin-kb4rag

August 30, 2026 · View on GitHub

English | 中文

A local paper knowledge base plugin for DeepSeek Harness (DSH): turns folders of PDF/DOCX papers into a semantically searchable knowledge base inside DSH sessions, giving long-form writing (theses, papers, books) cross-chapter consistency and literature recall.

Why

The three pains of long-form writing: writing chapter N and not remembering how chapter 1 defined the same concept, terminology drift, and digging through dozens of PDFs for one passage. This plugin makes "search the papers" a native one-step action for the DSH agent: recall passages (with source file and page) before/during writing, keeping terminology and arguments consistent across chapters. Embedding runs on a local Ollama (bge-m3 recommended); data stays local; no external APIs.

How it works

papers/ (PDF/DOCX/TXT, one or more directories)
   │  scripts/paper_kb.py extract   ← per-page text extraction with pymupdf

papers_extract.jsonl                ← one {relpath, page, text} per line
   │  scripts/paper_kb.py build     ← sentence-boundary chunking (600-900 chars, overlap)
   ▼                                   + Ollama embedding
kb-data/chunks.bin                  ← N×dim float32 vectors
kb-data/index.json                  ← chunk metadata + text + source/page

   ▼  DSH loads the plugin (index.js)
paperkb_search  ← embed query → cosine Top-K → sourced snippets
paperkb_stats   ← index statistics
  • Zero runtime dependencies: search runs purely in Node (Float32Array dot products; ~9k×1024 ≈ tens of ms). No Python, no database, no MCP.
  • Native DSH tools: registered via ctx.tools.register(); schemas flow into system-prompt assembly automatically, and the permission system and Code Mode (tools.paperkb_search(...)) work out of the box.
  • Build-time only Python (stdlib only) plus a reachable Ollama.

Install

dsh plugin --profile web add dsh-plugin-kb4rag

Until published on npm, install from a local path:

dsh plugin --profile web add /path/to/dsh-plugin-kb4rag

Then restart dsh (or validate with dsh --profile web --dump-config).

Configuration

Plugin row id: kb4rag:

KeyDefaultMeaning
ollamahttp://127.0.0.1:11434Ollama HTTP endpoint (e.g. http://<ip>:11435 for a LAN instance)
modelbge-m3Embedding model (bge-m3 recommended for Chinese/English papers)
topK5Default result count
minScore0Minimum cosine similarity
home./data in the packageKnowledge base directory (chunks.bin + index.json)

Override by row id in your profile's cordis.patch.yml (an id-targeted entry replaces the whole config; unset keys fall back to JS defaults):

- id: kb4rag
  config:
    ollama: http://192.168.3.22:11435
    home: D:\kb\my-papers

You can also fall back to environment variables (lower precedence than a patch override, higher than built-in defaults): set KB4RAG_OLLAMA, KB4RAG_MODEL, KB4RAG_HOME in the shell that starts dsh, e.g. set KB4RAG_OLLAMA=http://192.168.3.22:11435. Precedence: patch override > environment > default http://127.0.0.1:11434.

Ollama integration

  1. Install Ollama and pull an embedding model:
    ollama pull bge-m3        # 1024-dim, strong on mixed Chinese/English papers
    # nomic-embed-text is smaller (274MB) but clearly weaker on Chinese — not recommended
    
  2. LAN access: Ollama binds 127.0.0.1 by default. To call it from another machine, serve with OLLAMA_HOST=0.0.0.0:11435 (in a systemd unit: Environment=OLLAMA_HOST=0.0.0.0:11435). Do not expose the port to the public internet.
  3. GPU pinning: on multi-GPU machines use CUDA_VISIBLE_DEVICES=<index>. ⚠️ Verified on ollama 0.5.x: its internal GPU ordering can be the reverse of nvidia-smi (setting 1 selected the card nvidia-smi reports as 0). After changing it, trigger one /api/embed and check nvidia-smi --query-compute-apps=pid,gpu_bus_id --format=csv to confirm where the runner landed.
  4. Smoke test: curl http://<host>:<port>/api/embed -d '{"model":"bge-m3","input":["hello"]}'.

Pointing at a different Ollama (host/port mismatch)

The endpoint is resolved in this order:

  1. an ollama override for the kb4rag row in the profile's cordis.patch.yml (highest),
  2. the KB4RAG_OLLAMA environment variable (set where dsh runs),
  3. the built-in default http://127.0.0.1:11434.

For a LAN instance (e.g. 192.168.3.22:11435), either patch the config or run set KB4RAG_OLLAMA=http://192.168.3.22:11435 before starting dsh (Linux/macOS: export KB4RAG_OLLAMA=...).

Troubleshooting

paperkb_search errorMeaningFix
cannot reach Ollama at <url> (ECONNREFUSED)Service down or wrong portStart ollama serve on that host; check the port (default 11434)
cannot reach Ollama ... (ENOTFOUND)Hostname does not resolveFix the URL or use an IP address
cannot reach Ollama ... (ETIMEDOUT)Firewall blockingAllow the port; for cross-machine use serve with OLLAMA_HOST=0.0.0.0:PORT
ollama /api/embed 404Embedding model not pulledollama pull bge-m3 on that host
knowledge base not found at "<home>"Index missing or wrong pathRun extract+build, or point home at an existing index

Debug order:

  1. curl http://<host>:<port>/api/tags — a JSON reply means service + port are fine;
  2. call paperkb_stats in a DSH session — it reports the configured endpoint, the index directory and a live reachability probe, telling you at a glance whether the index or the service is the problem;
  3. fix per the table; config changes in the profile patch take effect after a dsh restart.

Building the knowledge base

python scripts/paper_kb.py extract /path/to/papers -o papers_extract.jsonl
# or several directories at once (the directory name is kept in each source path):
python scripts/paper_kb.py extract dir1 dir2 dir3 -o papers_extract.jsonl
python scripts/paper_kb.py build papers_extract.jsonl -o kb-data \
    --ollama http://127.0.0.1:11434 --model bge-m3
python scripts/paper_kb.py stats kb-data
  • Extraction needs pip install pymupdf (PDF) and optionally python-docx; scanned PDFs (no text layer) are listed as warnings — OCR them first.
  • Building uses only the Python standard library; ~8000 chunks embed at ~50 chunks/s on an RTX 3090 with bge-m3.
  • Point home at kb-data (or copy it into the package's data/) and restart dsh.

Tools

  • paperkb_search(query, topK) — semantic search; full sentences or terms (Chinese or English); returns score, source file, page and snippet text.
  • paperkb_stats() — chunk count, source documents, vector dimension, embedding model, plus the configured Ollama endpoint and a live reachability probe — call it first when search fails.

CLI equivalents without DSH:

python scripts/paper_kb.py search kb-data "morphology intelligence mechanisms" -k 4 --ollama http://192.168.3.22:11435

Limitations & roadmap

  • Text only: formulas, figures and tables are not embedded (poor extraction quality).
  • Chunks respect sentence boundaries within a page; no cross-page merging.
  • Full rebuild: new papers require re-running extract+build (incremental indexing planned).
  • Roadmap: incremental indexing & dedup, a settings-panel card (settings.plugin.item), a search result card (presentResult), hybrid keyword+vector search, per-document filters.

License

MIT