A DeepSeekHarness (dsh) plugin for Zotero: automatically syncs your Zotero library, parses PDFs with MinerU, reads full texts with DeepSeek, compiles everything into a searchable Obsidian wiki, and lets your agent answer questions with traceable literature citations.
Positioning & Scope
What it is: a Node/Cordis-style dsh plugin plus a standalone CLI that turns your Zotero library into a continuously updated Obsidian knowledge base, exposing native tools for agent retrieval.
Full pipeline:
Zotero (local DB / Web API)
└─ sync: incremental metadata sync → .zotero-sync/sync.db (SQLite state)
└─ parse: MinerU PDF parsing → raw/ bundles + DeepSeek full-text notes → wiki/ pages
└─ compile: topic reviews, indexes, cross-links, archive marks
└─ query: agents search via query_zotero_wiki, answers cite [Zotero key, §section]
Explicitly out of scope (kept lightweight): vector databases, automatic clustering, multi-user server, scheduled background services, Web UI, Zotero annotation/highlight sync, page-number citations.
Features
Feature
Description
Dual-source sync
Local zotero.sqlite (read-only temp copy, never blocks Zotero) or Zotero Web API (version-cursor incremental)
Interactive scope
All / specific Collections (incl. children) / tag filter; the choice is persisted and silently reused at startup
PDF parsing
MinerU official open platform (upload → poll → zip); results stored as raw/ bundles (Markdown + images/); original PDFs are never persisted
No PDF or parse failure → concise note from title + abstract; automatically upgraded to a full-text note once a PDF is added
Quota & concurrency
Per-run parse cap MAX_PARSE_PER_SYNC (default 50), concurrency 3, failures recorded and retryable next run
Wiki compile
LLM topic reviews (incremental rewrite), index/authors/years pages, See Also cross-links, archive marks (no page deletion), append-only log
Agent query
minisearch in-memory full-text search with Chinese bigram tokenization; returns snippets with [key, §section] citations; explicitly reports "not found", never fabricates
Installation
Requirements
Node.js ≥ 22.19 (uses built-in node:sqlite)
A local Zotero library or a Zotero Web API key
(for parse) a MinerU token (from mineru.net) and a DeepSeek API key
Install from source (recommended during MVP)
git clone dsh-zotero-wiki && cd dsh-zotero-wiki
npm install
cp .env.example .env # then edit; see Configuration below
npm run build
Register as a dsh plugin (local-path install)
npx -y @deepseek-ai/dsh plugin --profile web add file:/path/to/dsh-zotero-wiki
Once loaded, dsh silently runs an incremental sync at startup and rebuilds the query index; the three native tools become available in chat.
Configuration
All settings live in .env inside the plugin directory (see .env.example). Key entries:
Key
Required
Default
Purpose
ZOTERO_MODE
yes
local
local / web
ZOTERO_DATA_DIR
local, optional
auto-detect
Directory containing zotero.sqlite and storage/
ZOTERO_API_KEY / ZOTERO_USER_ID / ZOTERO_GROUP_ID
web
—
Web API credentials (Group wins over User)
OBSIDIAN_VAULT_PATH
yes
—
Vault root
SYNC_SCOPE_JSON
no
interactive
Persisted sync scope, e.g. {"mode":"all","collectionKeys":[],"tags":[]}
MINERU_TOKEN
parse
—
MinerU official platform token
MINERU_MODEL_VERSION
no
pipeline
vlm for higher quality
DEEPSEEK_API_KEY
parse/reviews
—
DeepSeek API key
NOTE_TOKEN_LIMIT
no
100000
Per-paper truncation cap (conservative char-based estimate)
MAX_PARSE_PER_SYNC
no
50
Max uploads per run (protects MinerU free quota)
PARSE_CONCURRENCY
no
3
Parse concurrency
REVIEW_REGEN_THRESHOLD
no
5
Regenerate a topic review after N accumulated new notes
Search the wiki; returns snippets, metadata and [Zotero key, §section] citations; replies "nothing found in the wiki" when empty
sync_zotero_wiki()
Manual incremental sync + index rebuild
parse_zotero_wiki()
Manual parse & note generation (quota-limited) + index rebuild
Sync behavior contract
Startup sync silently reuses the last persisted scope; interactive selection only happens on first run or with --interactive
Existing pages are updated/extended, new items create new pages, log.md is append-only; pages are never physically deleted — items removed from Zotero get status: archived and are auto-restored if they come back
Items without any Collection are skipped until classified in Zotero
An item in multiple Collections: one copy in raw/ (first Collection), one note page per topic in wiki/
Development
npm run typecheck # tsc --noEmit
npm test # vitest (18 test files / 82 cases)
npm run build # vite → dist/cli.js + dist/plugin.js
npm run dev # watch build
Q: Startup says "SYNC_SCOPE_JSON not configured"?
Run node dist/cli.js sync once in a terminal to complete the interactive scope selection; the dsh runtime has no interactive TTY, so first-time configuration must go through the CLI.
Q: Local mode can't find the Zotero data directory?
Set ZOTERO_DATA_DIR in .env explicitly to the directory containing zotero.sqlite.
Q: parse is slow or items stay pending?
MinerU's free quota is 2000 high-priority pages/day; beyond that, jobs queue at lower priority. Lower MAX_PARSE_PER_SYNC and run in multiple rounds.
Q: Chinese search quality?
Tokenization is bigram-based keyword search (zero native dependencies). Try more specific keywords or a topic filter; vector retrieval is on the roadmap.
Q: Can I hand-edit notes in Obsidian?
Yes. Only the ## See Also section, the index pages (index/authors/years) and archive notice blocks are rewritten automatically; everything else is preserved.