ZotSeek

AI semantic search for Zotero, with a built-in MCP server for AI agents (Claude Code, Codex). Find papers by meaning. 100% local and private.

189
Stars
10
Forks
TypeScript
Language
8/23/2026
Added
View on GitHubDownload ZIP

⚠️ Third-Party Software Notice

This skill is third-party open-source software developed and hosted independently on GitHub. SkillTip is an informational directory and does not control or maintain the underlying repository. Any security checks displayed are automated and limited in scope. Review the source code before installing.

Read the Terms of Service

Installation

Add to your Claude Code skills directory:

# Add to your Claude Code skills
git clone https://github.com/introfini/ZotSeek

Getting Started

Guides for using skills like ZotSeek.

Security Report

Verified

Last scanned: —

{
  "status": "PASSED",
  "issues": []
}

README.md

ZotSeek | AI-Powered Semantic Search & MCP Server for Zotero

Find similar papers by meaning, not just keywords. 100% local, no data leaves your machine. Now with a built-in MCP server for AI agents.

Status: ✅ Stable release · Zotero 8, 9 & 10 · Transformers.js running locally

New: 🤖 MCP server built in — Claude Code, Codex, and any MCP client can search your library and cite papers with links that open straight to the matched PDF page. Fully local, read-only, opt-in. Set it up in one line →

New from the same author: 🔎 citefact — audit your manuscript against your Zotero library: citations exist, quotes are verbatim, claims are supported.

ZotSeek Search Dialog


Features

  • 🔒 100% Local - No data sent to cloud, works completely offline
  • 🧠 True Semantic Search - Find papers by meaning, not just keywords
  • 🤖 AI Agent Access (MCP) - Let Claude Code and other MCP clients search your library, fully local and opt-in (docs)
  • 🔍 Find Similar Documents - Right-click any paper → discover related research
  • 📖 Search from PDF Selection - Select text while reading → right-click → find documents about that concept
  • 🔎 Natural Language Search - Search with queries like "machine learning in healthcare"
  • 🔀 Multi-Query Search - Combine up to 4 queries with AND/OR logic to find topic intersections
  • 🔗 Hybrid Search - Combines AI + keyword search for best results
  • Lightning Fast - Searches complete in <100ms
  • 📑 Section-Aware - See which section matched (Abstract, Methods, Results)
  • 📄 Matched-Passage Preview - Hover a result to read the exact passage that matched, with query terms highlighted
  • 📍 Passage-Level Location - Jump to exact page & paragraph in Full Document mode
  • Multi-Select in Results - Select multiple search results, right-click to add to collections
  • 📁 Save Results as Collection - One click saves the full result set into a new Zotero collection so you can revisit the list later without re-running the search
  • 🧩 Selectable Embedding Models - Choose from 4 curated local models, including multilingual options; non-bundled models download once from Hugging Face to your machine
  • 🖥️ Local Inference Server (optional) - Serve the embedding model from LM Studio, Ollama, llama.cpp or vLLM on the same machine for native GPU speed: OpenAI-compatible API, localhost only
  • 🔄 Auto-Index - Automatically index new papers when you add them to your library
  • 👥 Group Libraries (opt-in) - Extend indexing and search to your Zotero group libraries with the Index scope setting
  • 🗑️ Auto-Cleanup - Embeddings automatically removed when items are deleted or trashed
  • 🚫 Tag-Based Exclusion - Tag items with zotseek-exclude to skip them during indexing
  • 📊 Indexing Status Column - "ZotSeek" column in the item list shows whether each paper is fully indexed, partially indexed (chunk limit hit), out of date, excluded, or not indexed
  • ⏸️ Pause & Cancel - Pause or cancel long-running indexing operations at any time
  • 💾 Crash-Resilient - Checkpoint saving every 10 items, auto-resume on next startup if a bulk run was interrupted, worker recovery on sleep/wake, skips problematic chunks automatically
  • 🔌 Plugin API - Other Zotero plugins can call ZotSeek's search programmatically
  • ⚙️ Configurable - Customize via Zotero Settings → ZotSeek (also accessible from search dialog)
  • 🌐 Localized - UI available in English and Chinese (zh-CN)

Privacy & Security

ZotSeek is designed with privacy as a core principle:

AspectGuarantee
AI ModelDefault model bundled (~130MB); optional models download once from Hugging Face on demand — no API keys, no subscription
ProcessingAll AI inference runs locally on your CPU/GPU
Your PapersOnly indexes items from your local Zotero library
NetworkZero network requests for search or indexing, unless you opt into a local inference server (see below)
StorageEmbeddings saved locally in zotseek.sqlite in your Zotero data folder
OfflineWorks completely offline after installation (or after the optional inference server has started)

What this means:

  • Your research never leaves your machine
  • No cloud services, no API keys, no subscriptions
  • No telemetry or usage tracking
  • Uninstalling the plugin removes all ZotSeek data

Optional local inference server: the default is the fully in-process engine described above, which makes no network requests at all. If you choose to add a local inference server (LM Studio, Ollama, llama.cpp or vLLM), the guarantee shifts from "no network code exists" to "network code provably cannot leave the machine": every request is validated at request time against an allow-list of 127.0.0.1, localhost and [::1], there is no preference to override this, redirects to a non-loopback address are refused rather than followed, and cloud or remote endpoints are unsupported by design. This is opt-in and off by default.


More Screenshots

Click to expand

Find Similar Documents

Find Similar Results

Context Menu

Context Menu

PDF Selection Context Menu

PDF Find Related

Settings Panel

Settings Panel

Indexing Progress

Indexing Progress


How It Works

The Big Picture

flowchart TD
    subgraph INDEX["1️⃣ INDEX"]
        A[📄 Paper] --> B[🤖 AI Model] --> C[768 numbers]
    end
    
    subgraph SEARCH["2️⃣ SEARCH"]
        D[🔍 Query] --> E[Query → 768 numbers]
        E --> F{Compare all papers}
        F --> G[📊 Ranked results]
    end
    
    C -.->|stored| F

How it works: Each paper becomes 768 numbers capturing its meaning. To search, we convert your query to numbers and find papers with similar numbers.

Step-by-Step Process

1️⃣ Indexing Your Library

When you use "Index Current Collection" or "Update Library Index":

For each paper:
  1. Extract title + abstract (Abstract mode)
     — OR —
     Extract PDF text page-by-page with exact page numbers (Full Document mode)
  2. Split into paragraphs, filter out References/Bibliography
  3. Send to local AI model (nomic-embed-text-v1.5)
  4. Model outputs 768 numbers per chunk (the "embedding")
  5. Save embeddings + location metadata to local database (zotseek.sqlite)

Time: ~3 seconds per chunk

2️⃣ Finding Similar Documents

When you right-click → "Find Similar Documents":

  1. Load the selected paper's embedding
  2. Compare against all indexed papers (cached in memory)
  3. Rank by semantic similarity
  4. Show top results

Time: ~70ms (with cache)


Hybrid Search

The plugin combines semantic search (AI embeddings) with Zotero's keyword search using Reciprocal Rank Fusion (RRF) for optimal results.

Search Modes

ModeBest ForHow It Works
🔗 Hybrid (Recommended)Most searchesCombines semantic + keyword results
🧠 Semantic OnlyConceptual queriesFinds related papers by meaning
🔤 Keyword OnlyAuthor/year searchesExact title, author, year matching

Why Hybrid Search?

Query TypePure SemanticPure KeywordHybrid
"trust in AI"✅ Great❌ Poor✅ Great
"Smith 2023"❌ Poor✅ Great✅ Great
"RLHF"⚠️ Maybe✅ Exact only✅ Both

Result Indicators

IconMeaning
🔗Found by BOTH semantic and keyword (high confidence)
🧠Found by semantic search only (conceptually related)
🔤Found by keyword search only (exact match)

Section-Aware Results

The Source column shows which section of the paper matched your query:

SourceSection Type
AbstractTitle + Abstract
MethodsIntroduction, Background, Methods
ResultsResults, Discussion, Conclusions
ContentGeneric (sections not detected)

Matched-Passage Preview

Hover any result row to see a tooltip with the exact passage that matched your query, along with its location (page & paragraph), section type, and match score. This lets you judge whether a result is relevant without opening the paper. In Keyword and Hybrid searches the query terms are highlighted inside the passage, and the preview is centered on the first match so the relevant text is always in view. (Pure semantic search has no literal terms to highlight, so the passage is shown without highlighting.)

Result Granularity (Full Document Mode)

When using Full Document indexing mode, you can toggle between two result views:

ModeResultsBest For
By Section (default)1 result per paper, best matching section, with the location of that matchOverview of matching papers
By LocationEvery matching paragraph with exact page & paragraphFinding specific passages

By Section - Aggregates all chunks per paper and shows the highest-scoring match. The Location column shows where that best match was found (page & paragraph), so you get one diverse result per paper without losing the exact location:

By Section Mode

By Location - Returns every matching paragraph individually with its own score:

By Location Mode

In By Location mode, clicking a result opens the PDF to the exact page where the match was found.

Multi-Query Search

Combine up to 4 search queries to find papers at the intersection of multiple topics:

  1. Click the "+" button next to the search field to add more queries
  2. Choose AND or OR to combine results
  3. For AND mode, select a combination formula
OperatorBehaviorBest For
ANDPapers must match ALL queriesFinding topic intersections
ORPapers can match ANY queryBroadening search with synonyms
AND FormulaHow It WorksUse When
Minimum (default)Uses lowest score across queriesYou want strict intersection
ProductGeometric mean of scoresBalanced relevance across all queries
AverageArithmetic mean of scoresMore lenient matching

Example: Search for papers about "machine learning" AND "healthcare" AND "ethics" to find AI ethics papers specifically in the medical domain.

Match column with multiple queries: Shows combined score plus individual per-query scores:

  • 73% (77|73|68) = 73% combined, with 77% for Q1, 73% for Q2, 68% for Q3

For technical details, see docs/SEARCH_ARCHITECTURE.md.


Indexing Modes

ModeWhat Gets IndexedBest For
AbstractTitle + AbstractFast indexing, quick setup
Full Document (default)PDF content split by sectionsDeep content search, better results

Configure via Zotero → Settings → ZotSeek.

Library Scope (Group Libraries)

By default, ZotSeek indexes only My Library. If you use Zotero group libraries, the Index scope setting (under Auto-Indexing) lets you include them:

ScopeWhat Gets Indexed
My Library (default)Your personal library only
All librariesPersonal library + every group library

The scope applies to both the bulk Update Index action and background auto-indexing. Once indexed, group items show up in search results like any other paper, with links that open them in the right library. Searches over MCP/REST can also be limited to a single library with the library_key parameter (see docs/MCP.md).

How Full Document Mode Works

For papers with PDFs, the chunker:

  1. Extracts text page-by-page with exact page numbers
  2. Splits each page into paragraphs
  3. Prepends title to each chunk for context
  4. Automatically filters out References/Bibliography sections

When searching, if any chunk matches your query, the paper ranks highly (MaxSim aggregation in "By Section" mode).

References Filtering

The chunker automatically detects and excludes bibliography sections:

  • Detects headers: "References", "Bibliography", "Works Cited", "Literature Cited"
  • Recognizes citation patterns: [1], Smith, J. (2021)., DOI links
  • Stops indexing once references section is detected

This keeps your search results focused on the actual content of papers.

Chunk Size Trade-offs

The maxTokens setting controls how text is split for embedding. It's a ceiling, not a target — chunks are split at paragraph boundaries and may be smaller.

Chunk SizeSpeedSearch Behavior
500-800Fast (~0.5s/chunk)Higher precision, finds specific passages
2000Moderate (~3s/chunk)Balanced (default)
4000+SlowHigher recall, finds broad topics

Default: 2000 tokens. Firefox 140+ handles larger chunks efficiently.

Recommendations:

  • Large libraries with full-paper indexing: use defaults
  • Finding specific methodologies: try 500-600
  • Broad topic discovery: try 2000-3000

For detailed chunking documentation, see docs/SEARCH_ARCHITECTURE.md.

Indexing Status Column

ZotSeek adds a "ZotSeek" column to the Zotero item list so you can see at a glance how each paper has been indexed. The first time you install this version the column appears automatically; you can hide or reorder it from the column-header menu like any other Zotero column.

GlyphMeaning
Fully indexed
Partial — the paper hit the Max Chunks per Paper limit and only part of its content is in the index. Raise the limit or switch to Abstract mode to capture the full text.
Out of date — the item was modified after it was indexed. Re-index to refresh.
Excluded — the item carries the zotseek-exclude tag.
(empty)Not indexed.

After indexing, a one-line summary in the progress window also warns when any paper hit the chunk limit, and the same warning is written to the debug log per affected paper.


Choose Your Embedding Model

ZotSeek ships with a curated set of local embedding models. The default model is bundled and works immediately; other models download once from Hugging Face and are then available offline.

Go to Zotero → Settings → ZotSeek → Embedding Model to pick the model that fits your library.

ModelDimsMultilingualApprox. sizeWhen to use
nomic-embed-text-v1.5 (default, bundled)768No~130 MBEnglish or mostly-English libraries. Strong all-around retrieval quality, no download needed.
paraphrase-multilingual-MiniLM-L12-v2384Yes~135 MBSmaller and faster; good for hardware-constrained machines or mixed-language collections where speed matters more than top accuracy.
multilingual-e5-base768Yes~110 MBBalanced multilingual quality at the same 768-dimension space as the default. Good first choice for non-English libraries.
BGE-M31024Yes~570 MBHighest-quality multilingual retrieval in the set. Worth the extra size for large, mixed-language collections where accuracy is paramount.

Privacy: models are downloaded once from Hugging Face directly to your Zotero profile directory. No library content is ever sent anywhere — inference runs entirely on your machine.

Coverage indicator: below the model selector, Settings shows "N of M items searchable with the active model." When any items are missing coverage, an Index remaining N button appears. Clicking it indexes those items in the background while you continue working; the button shows "Indexing in the background..." and disables itself while the run is active.

Three ways to index with a model (all preserve other models' embeddings):

  1. The prompt shown immediately after you switch to a new model.
  2. The Index remaining button on the coverage line in Settings.
  3. The toolbar or right-click Index Library action — now model-aware, it backfills items not yet covered by the active model rather than reporting "already indexed."

Switching models: switching to a different model triggers a background re-index for items that have not yet been indexed with the new model. Items indexed with other models retain their embeddings — switching back is instant.

Manage downloaded models: a "Manage downloaded models" panel in Settings shows per-model index statistics (items, chunks, and embedding storage) and lets you delete models you no longer need (this also removes that model's embeddings from the database). The built-in model and whichever model is currently active cannot be removed; each shows an inline reason ("Built-in" / "Active") with a tooltip explaining why.


Using a Local Inference Server

If you have a GPU, running the embedding model in a dedicated inference server (LM Studio, Ollama, llama.cpp or vLLM) is faster than the built-in WASM engine, which runs on CPU inside Zotero. This is entirely optional: the default remains the fully in-process engine, and ZotSeek never talks to anything off this machine.

Setup with LM Studio:

  1. In LM Studio, load an embedding model (e.g. an embedding-capable GGUF) and start the local server. Note the port shown (typically 1234).
  2. In Zotero, go to Settings → ZotSeek → Local inference server and enter the server URL, e.g. http://127.0.0.1:1234.
  3. Click Test connection. ZotSeek lists the models the server currently has loaded.
  4. Pick a model from the dropdown. ZotSeek sends a test embedding request and reports the dimensions it returns.
  5. Click Add model. The model now appears in the main Embedding Model picker alongside the bundled and Hugging Face models.
  6. Select it in the model picker to make it the active model.

Setup with Ollama:

  1. Pull an embedding model, e.g. ollama pull nomic-embed-text. Ollama serves its OpenAI-compatible API on port 11434 by default.
  2. In Settings → ZotSeek → Local inference server, enter http://127.0.0.1:11434.
  3. Follow the same Test connection → pick model → Add model steps as above.

The same flow works with llama.cpp's server (llama-server) and vLLM, since both also expose an OpenAI-compatible /v1/embeddings endpoint on localhost.

Re-indexing note: a server-hosted model is a separate index from the built-in models, even for the same model name: indexing runs once per model, and previous indexes are kept. Switching between a server model and a built-in model does not require re-indexing again later, since both are retained side by side.

API key note: if your server requires an API key, ZotSeek stores it in plain text in the Zotero profile preferences, sends it only to the loopback server you configured, and never logs it.

Choosing a model and task prefixes:

Pick a dedicated embedding model. The server's model list includes every model it has loaded, including chat models, and ZotSeek cannot tell the two apart from the API alone, so it warns you when a selected model's name does not look like an embedding model. Running a chat model as your embedding model produces poor search results.

Some embedding models were trained to expect a short prefix before the text, different for queries versus documents (a "task prefix"). Using the correct prefix helps the model separate what you are searching for from what you indexed.

Model familyQuery prefixDocument prefix
Nomicsearch_query: search_document:
E5query: passage:
Most others (BGE, MiniLM, GTE)nonenone

ZotSeek pre-fills these prefixes automatically when it recognizes the model family from its name. If you are using a model that is not listed here, check the model card on Hugging Face for a prefix requirement, and leave the fields empty if the card does not mention one.

Using the wrong prefixes does not produce an error. Search will simply run and quietly return lower-quality results.


The AI Model

nomic-embed-text-v1.5

PropertyValue
Namenomic-ai/nomic-embed-text-v1.5
Size131 MB (quantized)
Dimensions768 (Matryoshka - can truncate to 256/128)
Context Window8192 tokens
Speed~3 seconds per chunk
QualityOutperforms OpenAI text-embedding-3-small on MTEB
Special FeatureInstruction-aware prefixes for queries vs documents

Why This Model?

  • Superior retrieval quality - Outperforms OpenAI text-embedding-3-small and jina-v2 on MTEB benchmarks
  • 8K context window - Most papers fit in 1-3 chunks (vs 10-20 with 512-token models)
  • Instruction-aware - Uses search_document: for indexing and search_query: for queries
  • Matryoshka embeddings - 768 dims can be truncated to 256/128 with minimal quality loss
  • Fully open - Open weights, open training data, reproducible
  • Works in Zotero - Compatible with Transformers.js v3 via wasmPaths configuration

How Embeddings Work

The model converts text into 768 numbers that capture semantic meaning:

"Machine learning for medical diagnosis"  →  [0.023, -0.045, 0.012, ...]
"AI in healthcare applications"           →  [0.021, -0.048, 0.015, ...]  ← Similar!
"Organic chemistry synthesis"             →  [-0.089, 0.034, 0.067, ...]  ← Different!

Papers with similar meanings have similar numbers, even if they use different words.


Architecture

System Overview

flowchart LR
    subgraph Main["Main Thread"]
        A[Plugin] <--> B[(SQLite)]
        A <--> C[Search]
    end
    
    subgraph Worker["ChromeWorker"]
        D[Transformers.js]
        E[nomic-embed-v1.5]
    end
    
    A -->|text| Worker
    Worker -->|embeddings| A

Why ChromeWorker?

Transformers.js can't run directly in Zotero's main thread because:

  • Missing browser globals (self, navigator, indexedDB)
  • Cache API crashes Zotero
  • Would block UI during model inference

Solution: Run in a separate ChromeWorker thread with special configuration.

Data Storage

Embeddings are stored in a separate SQLite database (zotseek.sqlite) attached to Zotero's connection:

  • Location: <Zotero Data Directory>/zotseek.sqlite
  • Size: ~15KB per paper (abstract mode), ~150KB per paper (full document mode)
  • Benefits: O(1) indexed lookups, in-memory caching, atomic updates, clean uninstall

The SQLite backend uses the ATTACH DATABASE pattern (inspired by Better BibTeX):

  • Separate file - Keeps Zotero's main database clean and unbloated
  • Smart caching - Pre-normalized Float32Arrays cached in memory after first search
  • Reliable queries - Uses columnQueryAsync() and valueQueryAsync() for robust data retrieval
  • Clean uninstall - Database file automatically removed when plugin is uninstalled

Copying the database between machines

ZotSeek stores its embeddings in zotseek.sqlite inside your Zotero data directory. The file is local and is not synced by Zotero's built-in sync.

If your Zotero data folder is on a network drive or NAS: downloadable embedding models are kept next to Zotero's profile instead, not in the data folder, because reading a few hundred megabytes of model weights over a network share can stall indexing. Models downloaded by earlier versions still work from the old location, but if you are on network storage it is worth removing and re-downloading them from Settings → ZotSeek → Models so they end up local.

If you use Zotero on multiple machines and want to avoid re-indexing your library on each one, you can copy the file manually:

  1. Quit Zotero on both machines.
  2. Find your Zotero data directory (Preferences → Advanced → Files and Folders).
  3. Copy zotseek.sqlite from one machine to the other.
  4. Start Zotero on the destination machine.

The plugin identifies items by Zotero's stable item keys (the same identifiers visible in the Zotero web API), so the database works correctly regardless of which machine indexed the items.

Notes:

  • Both Zotero libraries must be in sync — items not yet present on the destination will appear as "unresolved embeddings" in Preferences → Database Health until sync completes.
  • The file can be large (hundreds of MB for libraries with full-document indexing). It is not designed to be cloud-synced continuously.
  • Group libraries are supported via stable group IDs assigned by Zotero's server.

Cosine Similarity

The math behind "how similar are two papers":

$$\text{similarity} = \frac{A \cdot B}{|A| \times |B|}$$

Where:

  • A · B = sum of (a[i] × b[i]) for all 768 dimensions
  • ‖A‖ = sqrt(sum of a[i]²)
  • ‖B‖ = sqrt(sum of b[i]²)

Result: 0.0 (completely different) to 1.0 (identical)

Interpretation:

  • 0.9+ = Very similar (probably same topic)
  • 0.7-0.9 = Related topics
  • 0.5-0.7 = Loosely related
  • <0.5 = Different topics

Use with AI Agents (MCP)

ZotSeek can let Claude Code and other MCP clients search your library semantically, so an agent can find relevant papers and cite them with links that open straight to the right page in Zotero. Each result carries zotero:// deep links: one opens the item, one opens its PDF at the exact page that matched your query.

What this enables — real workflows from a thesis-writing session:

  • "Find me a citable definition of human-AI collaboration" → the agent searches the library, proposes three candidate papers with the matched passages, and links each one so it opens in Zotero at the relevant page.
  • Mark claims in a draft with [citation needed] → the agent hunts your library for sources that actually support each claim and flags the ones nothing supports.
  • "A reviewer says these statements are too strong — what evidence do I have?" → the agent cross-checks the argument against what you have actually collected, paper by paper.

It runs entirely on your machine and is opt-in (off by default). Enable it in Settings → ZotSeek → AI Agent Access, make sure Zotero's local HTTP server is allowed (Settings → Advanced), then connect Claude Code with:

claude mcp add --transport http --scope user zotseek http://localhost:23119/zotseek/mcp

The same searches are also available as plain REST endpoints for scripts. Everything is read-only — nothing can modify your library or index. See docs/MCP.md for the full setup, tool reference, REST API, and security notes.

Once the manuscript is written, the complementary tool citefact closes the loop: point it at the same Zotero collection and it audits the finished draft — citations exist, quotes are verbatim, and each source actually supports the claim citing it.


Built with ZotSeek

Independent projects built on ZotSeek's local API:

  • Wordbot by @Addy-ad — a Microsoft Word add-in for researchers. It converts LLM output into native Word formatting (tables, equations, code blocks, headings) and grounds it in your library: it runs semantic searches through ZotSeek, then writes text with inline citations that Zotero's own Word plugin recognises, so you can build a unified bibliography from them. Runs entirely offline against a local LLM server. Windows and macOS. See the author's introduction and demo for what it looks like in use and which edition to pick.

These are third-party projects, maintained by their authors and released under their own licences (Wordbot is non-commercial). Please report problems with them on their own issue trackers.


Installation

For Users

Requirements: Zotero 8.0 or newer (Zotero 9 and Zotero 10 supported).

  1. Download the latest zotseek-X.Y.Z.xpi from the Releases page.
  2. In Zotero, open Tools → Plugins.
  3. Click the gear icon (⚙️) in the top-right and choose Install Plugin From File…
  4. Select the downloaded .xpi file.
  5. Restart Zotero when prompted.

After installation, ZotSeek is ready to use — open Zotero → Settings → ZotSeek to configure it, then right-click a collection and choose "Update Library Index" to build your index.

Updating: ZotSeek checks for updates automatically. New releases are delivered through Zotero's built-in plugin update mechanism, so you'll be notified when a new version is available.

For Developers

# Clone the repository
git clone https://github.com/introfini/ZotSeek
cd zotseek

# Install dependencies (includes zotero-plugin-toolkit for stable progress windows)
npm install

# Build the plugin
npm run build

# Create extension proxy file (macOS)
echo "$(pwd)/build" > ~/Library/Application\ Support/Zotero/Profiles/*.default/extensions/zotseek@zotero.org

# Restart Zotero with debug console
open -a Zotero --args -purgecaches -ZoteroDebugText -jsconsole

Building a Distributable XPI

npm run release

The interactive release script bumps the version, syncs manifest.json and update.json, rebuilds, and packages zotseek-X.Y.Z.xpi at the project root.


Usage

Index Your Library

  1. Right-click on a collection → "Index Current Collection". Subcollections are included. On Zotero 10 you can select several collections first and index them in one pass; items filed in more than one of them are indexed once.
  2. Or use "Update Library Index" to index all items
  3. A progress window will appear showing:
    • Current item being processed
    • Progress percentage
    • Estimated time remaining (ETA)
    • Option to cancel at any time
  4. Indexing speed: ~3 seconds per chunk

Automatic Compaction (Zotero 10+): Re-indexing, switching models and purging orphans all leave free space inside ZotSeek's database file. Zotero 10 runs its own database maintenance after a few minutes of idle, and ZotSeek reclaims its space in the same window — but only when there is a meaningful amount to recover and no indexing is running. Turn it off under Settings → ZotSeek → Integrations & Maintenance, where the manual Compact Database button also lives.

Crash-Resilient Indexing:

  • Progress is saved every 25 items (checkpoint saving)
  • If Zotero crashes or you need to stop, simply re-run "Update Index"
  • Already-indexed items are automatically skipped
  • No need to start over from scratch

Progress Window Features:

  • ✅ AI model loaded status
  • ✅ Extraction progress (chunks from items)
  • 📊 Current paper being processed
  • 📈 Progress bar with percentage
  • ⏱️ ETA countdown
  • ⏸ Pause/resume button (pauses at batch boundaries, all progress saved)
  • ✕ Cancel button (shows quiet notification, no error alert)

Find Similar Documents

  1. Select any paper in your library
  2. Right-click → "Find Similar Documents"
  3. Results appear showing similarity percentages

Save Results as Collection

Every ZotSeek search result set can be saved into a Zotero collection so you can come back to the same list later without re-running the search:

  • In the search dialog, click "Save Results as Collection" in the footer to export every result.
  • Or right-click any subset of results and choose Add to Collection → New collection... to export just the selection.
  • The same button appears in the Find Similar Documents dialog.

The modal pre-fills a sensible name (your query + today's date, e.g. ZotSeek: "machine learning" · 2026-04-21) that you can edit. A live status line shows N items → My Library so you know where the collection will land.

New collections are created at the target library's root. If you want them in a specific subfolder, drag them from Zotero's sidebar after the export — faster and more flexible than a dropdown.

When search results span multiple libraries (for example, your personal library and a group library), a Library dropdown appears so you can pick which library receives the new collection. Items in other libraries are reported as skipped in the confirmation status.

Search from PDF Selection

While reading a PDF, you can search for related documents based on selected text:

  1. Open a PDF in Zotero's reader
  2. Select a passage that describes a concept you want to explore
  3. Right-click → "Find Related Documents"
  4. ZotSeek opens with the selected text as the search query
  5. Results show documents related to that concept (current document is excluded)

This is useful for:

  • Exploring unfamiliar concepts while reading
  • Finding additional sources on a specific topic
  • Discovering related work mentioned in a paper

Auto-Index New Papers

ZotSeek can automatically index papers as you add them to your library:

  1. Go to Zotero → Settings → ZotSeek
  2. Enable "Auto-index new items"
  3. Now when you add papers (via browser connector, drag & drop, etc.), they'll be indexed automatically

How it works:

  • Detects when new items are added to your library
  • Waits for PDF attachments to arrive (with automatic retry)
  • Batches multiple items together with a configurable delay (default: 10 seconds)
  • Each new item resets the countdown, preventing indexing during bulk imports
  • Shows a brief progress indicator while indexing
  • Respects your indexing mode setting (Abstract or Full Document)

Configuring the delay: Go to Zotero Settings > ZotSeek and adjust the Auto-index delay slider (1-300 seconds). Longer delays are useful when importing large batches via browser connector or RSS feeds.

Managing the Index

Automatic cleanup: When you delete or trash items in Zotero, their embeddings are automatically removed from the ZotSeek index. This prevents ghost search results and keeps the index clean — no action needed on your part.

Manual removal: To remove specific items from the index without deleting them:

  1. Select one or more items in Zotero
  2. Right-click → "Remove from ZotSeek Index"
  3. A notification confirms how many items were removed

This is useful when you want to re-index specific items (e.g., after updating a PDF), or to exclude items from search results without deleting them from your library.

Excluding Items from Indexing

You can prevent specific items from being indexed by tagging them:

  1. Select one or more items in Zotero
  2. Add the tag zotseek-exclude (or your custom tag name)
  3. These items will be skipped during all indexing operations

Customizing the tag name: Go to Zotero → Settings → ZotSeek → Advanced Settings and change the Exclude tag field. Leave it empty to disable tag-based exclusion.

Tip: Use Zotero's advanced search (Edit → Advanced Search) to find items by title, type, collection, etc., then bulk-tag them. This is more flexible than regex-based filtering since it leverages Zotero's native search capabilities.

ZotSeek Search Dialog

  1. Click the ZotSeek button in the toolbar (🔍✨)
  2. Or right-click → "Open ZotSeek..."
  3. Enter a natural language query (e.g., "machine learning for medical diagnosis")
  4. Optional: Click "+" to add more queries (up to 4) and combine with AND/OR
  5. View results ranked by semantic similarity
  6. Double-click any result to open it in Zotero
  7. Click ⚙ Settings (bottom-left) to quickly access ZotSeek preferences

Working with Multiple Search Results

Select multiple items in the ZotSeek search results:

  1. Select multiple items:
    • Shift+click to select a range of items
    • Cmd+click (Mac) or Ctrl+click (Windows/Linux) to toggle individual items
  2. Right-click on the selection to open the context menu:
    • Show in Library - Selects all items in Zotero's main pane
    • Add to Collection - Add all selected items to any collection
  3. Click "Open Selected" to select all items in the Zotero library (when multiple selected)

View Debug Output

Help → Debug Output Logging → View Output

Look for [ZotSeek] entries.


Configuration

Settings Panel

Access settings via Zotero → Settings → ZotSeek (or Zotero → Preferences on macOS).

The settings panel allows you to configure:

  • Indexing Mode: Abstract only or Full Document
  • Search Options: Maximum results, minimum similarity threshold
  • Exclusion: Exclude books, exclude by tag
  • Actions: Clear index, re-index library

Preferences Reference

Preferences are stored in Zotero's preferences system:

Search Settings:

PreferenceDefaultDescription
zotseek.minSimilarityPercent30Minimum similarity % to show in results
zotseek.topK20Maximum number of results
zotseek.autoIndexfalseAutomatically index new papers when added
zotseek.autoIndexDelay10Seconds to wait after last item before auto-indexing (1-300)

Indexing Settings:

PreferenceDefaultDescription
zotseek.indexingMode"full""abstract" or "full"
zotseek.maxTokens2000Max tokens per chunk
zotseek.maxChunksPerPaper100Max chunks per paper
zotseek.excludeBookstrueSkip books during indexing
zotseek.excludeTag"zotseek-exclude"Tag name to skip items during indexing (empty to disable)

Hybrid Search Settings:

PreferenceDefaultDescription
zotseek.hybridSearch.enabledtrueEnable hybrid search
zotseek.hybridSearch.mode"hybrid""hybrid", "semantic", or "keyword"
zotseek.hybridSearch.semanticWeightPercent50Semantic weight (0-100)
zotseek.hybridSearch.rrfK60RRF constant
zotseek.hybridSearch.autoAdjustWeightstrueAuto-adjust based on query

You can also access preferences via about:config (Help → Debug Output Logging → View Output, then navigate to about:config).


Performance

Tested on MacBook Pro M3:

OperationTime
Model loading~1.5 seconds (bundled, 131MB)
Index 1 chunk~3 seconds (optimized from ~45s)
Index 10 papers (40 chunks)~2 minutes
First search~130ms (loads cache)
Subsequent searches~70ms (uses cache)
Hybrid search~70ms (with cache)
Storage size~130 KB per 10 papers (full mode)
Memory usage (cached)+75MB for 1,000 papers

Performance Optimizations

The plugin includes several performance optimizations:

  1. Tuned Chunk Size - 2000 tokens (~3s/chunk) balances recall and speed while avoiding the O(n²) attention bottleneck
  2. In-Memory Caching - Embeddings cached after first search
  3. Pre-normalized Vectors - Float32Arrays normalized on load for fast dot product
  4. Parallel Searches - Semantic and keyword searches run simultaneously
  5. Reliable SQLite Methods - Uses columnQueryAsync() and valueQueryAsync()

GPU Acceleration (Experimental)

ZotSeek automatically detects and uses WebGPU for GPU-accelerated embeddings when available:

BackendWhen UsedSpeed
WebGPU (GPU)If browser/Zotero supports WebGPUUp to 10-20x faster
WASM (CPU)Fallback when WebGPU unavailable~3 seconds per chunk

Current status (August 2026):

  • Firefox 141 shipped WebGPU on Windows only (July 2025)
  • macOS and Linux WebGPU support is still in progress at Mozilla
  • Zotero 8, 9 and 10 all ship Firefox 140 ESR — one version before the first WebGPU build, so GPU acceleration is still gated on an upstream Firefox ESR bump

When will GPU work? Once Zotero upgrades to a Firefox ESR with WebGPU support for your platform, GPU acceleration will automatically activate — no plugin update needed.

Check if GPU is being used: Look for "Model loaded on GPU" or "Model loaded on CPU" in Zotero's debug console (Help → Debug Output Logging → View Output).

Note: If WebGPU is unavailable or fails, the plugin automatically falls back to CPU without interruption.


Limitations

  • Default model is English-optimized - The bundled nomic-embed-text-v1.5 is trained primarily on English text; switch to a multilingual model in Settings for non-English libraries (UI available in English and Chinese)
  • Large plugin size - ~131MB due to bundled AI model
  • CPU only (for now) - GPU acceleration ready but waiting for Zotero/Firefox WebGPU support
  • Zotero 8 or newer required - As of v1.12.0, Zotero 7 is no longer supported. Users on Zotero 7 should upgrade to Zotero 8 or later, or stay on ZotSeek v1.11.x.

Comparison with OpenAI

FeatureThis Plugin (Local)OpenAI API
CostFree~$0.02 per 1K papers
Privacy100% localData sent to OpenAI
OfflineYes (after model loads)No
QualityExcellent (outperforms text-embedding-3-small)Good
Speed~70-130ms~100ms
Context8192 tokens8191 tokens

Technical Details

See the docs/ folder for detailed documentation:

  • API.md - Plugin API for integration with other Zotero plugins
  • SEARCH_ARCHITECTURE.md - Hybrid search, RRF fusion, chunking strategy
  • DEVELOPMENT.md - Development guide, ChromeWorker + Transformers.js implementation
  • ROADMAP.md - Planned features and improvements
  • MCP.md - Local MCP server and REST API for AI agents and scripts

Changelog

See CHANGELOG.md for version history.

License

MIT License - see LICENSE


Related Projects

  • citefact — CLI that audits a manuscript against the full text of its cited sources, straight from a Zotero collection. ZotSeek helps you find the right papers; citefact verifies the final draft actually uses them correctly. uvx citefact check manuscript.md --zotero-collection "My Collection".

Acknowledgments


ZotSeek: AI-Powered Semantic Search for Zotero — Built by José Fernandes

Frequently Asked Questions

What is ZotSeek?

ZotSeek is an open-source ai agents skill for AI coding assistants such as Claude Code, Codex CLI, and ChatGPT, built by introfini. AI semantic search for Zotero, with a built-in MCP server for AI agents (Claude Code, Codex). Find papers by meaning. 100% local and private. It has 189 GitHub stars.

Is ZotSeek safe to use?

ZotSeek failed SkillsLLM's automated security scan, which flagged one or more high-severity issues. Review the Security Report section carefully before using it.

How do I install ZotSeek?

Clone the repository with "git clone https://github.com/introfini/ZotSeek" and add it to your Claude Code skills directory (see the Installation section above).

What programming language is ZotSeek written in?

ZotSeek is primarily written in TypeScript. It is open-source under introfini on GitHub, so you can review or fork the full source.

Are there alternatives to ZotSeek?

Yes. SkillsLLM lists many other AI Agents skills you can browse and compare side by side. Open the AI Agents category from the badge at the top of this page, or use the Related Skills and comparison links further down to weigh ZotSeek against similar tools.

Comments (0)

No comments yet. Be the first to share your thoughts!

ECC

by affaan-m

10

The agent harness performance optimization system. Skills, instincts, memory, security, and research-first development for Claude Code, Codex, Opencode, Cursor and beyond.

242,21936,702JavaScript
AI Agentsai-agentsanthropicclaude-code
View details
15

An agentic skills framework & software development methodology that works.

234,96620,863Shell
AI Agentsai-agentsbrainstorming
View details

The agent harness performance optimization system. Skills, instincts, memory, security, and research-first development for Claude Code, Codex, Opencode, Cursor and beyond.

185,94028,768JavaScript
AI Agentsai-agentsanthropicclaude-code
View details

cc-switch

by farion1231

3

A cross-platform desktop All-in-One assistant for Claude Code, Codex, OpenCode, OpenClaw, Grok Build & Hermes Agent. Only official website: ccswitch.io

128,8688,826Rust
AI Agentsclaude-codeai-tools
View details

claude-code

by anthropics

Claude Code is an agentic coding tool that lives in your terminal, understands your codebase, and helps you code faster by executing routine tasks, explaining complex code, and handling git workflows - all through natural language commands.

120,03119,897Shell
AI Agents
View details

Developers Also Liked

Based on votes and bookmarks from developers who liked this skill

ECC

by affaan-m

10

The agent harness performance optimization system. Skills, instincts, memory, security, and research-first development for Claude Code, Codex, Opencode, Cursor and beyond.

242,21936,702JavaScript
AI Agentsai-agentsanthropicclaude-code
View details
15

An agentic skills framework & software development methodology that works.

234,96620,863Shell
AI Agentsai-agentsbrainstorming
View details

n8n

by n8n-io

12

Fair-code workflow automation platform with native AI capabilities. Combine visual building with custom code, self-host or cloud, 400+ integrations.

201,88160,308TypeScript
MCP Serversapisai-tools
View details

The agent harness performance optimization system. Skills, instincts, memory, security, and research-first development for Claude Code, Codex, Opencode, Cursor and beyond.

185,94028,768JavaScript
AI Agentsai-agentsanthropicclaude-code
View details

cc-switch

by farion1231

3

A cross-platform desktop All-in-One assistant for Claude Code, Codex, OpenCode, OpenClaw, Grok Build & Hermes Agent. Only official website: ccswitch.io

128,8688,826Rust
AI Agentsclaude-codeai-tools
View details