winboost40 downloadsSearch your vault locally with QMD semantic and keyword search.
A minimal, local-first Obsidian desktop plugin for semantic search through your vault using QMD.
The plugin is intentionally small: it provides the Obsidian UI, vault setup flow, search modal, and file-opening behavior. QMD does the actual indexing, embedding, and searching locally.
Ctrl/Cmd + Shift + S (assign it in Obsidian hotkey settings if you want it).This plugin requires the local QMD command-line tool to be installed first.
Install QMD with Bun:
bun install -g @tobilu/qmd
Or with npm:
npm install -g @tobilu/qmd
You can test QMD outside Obsidian with:
qmd status
On some Windows systems, Bun's generated qmd.exe shim may fail because QMD's package entrypoint uses a shell script. This plugin detects Bun's global QMD install and bypasses the shim by running QMD's JavaScript CLI through Bun directly:
bun run ~/.bun/install/global/node_modules/@tobilu/qmd/dist/cli/qmd.js ...
So the plugin can still work even if the qmd shim itself is unreliable.
Download the latest qmd-semantic-search.zip from the GitHub Releases page, then extract it into your vault so the folder is named qmd-semantic-search.
The release contains these three production files:
main.js
manifest.json
styles.css
Alternatively, build from source and copy those same three files into your vault:
<your-vault>/.obsidian/plugins/qmd-semantic-search/
Final structure:
<your-vault>/.obsidian/plugins/qmd-semantic-search/main.js
<your-vault>/.obsidian/plugins/qmd-semantic-search/manifest.json
<your-vault>/.obsidian/plugins/qmd-semantic-search/styles.css
Then in Obsidian:
When the plugin starts, it checks whether this vault has a local QMD index.
If not, it opens a setup window explaining what will happen:
Click Prepare search.
The setup window shows:
You can cancel during preparation. Partial progress is kept, and you can resume later.
After setup, open semantic search with any of these:
Optional: assign Ctrl/Cmd + Shift + S to Semantic search in Obsidian hotkey settings.
Type a query. The plugin shows fast keyword results first and then tries semantic refinement briefly.
Why this design? Local semantic search can be slow on the first query because QMD may need to load the embedding model. Showing keyword results first keeps the UI responsive.
Click a result or press Enter on the selected result.
The plugin opens the note and tries to jump to the relevant part inside the note. It uses QMD's line information when available and also falls back to matching the snippet/query against the note content.
For very broad semantic matches, line placement may not be perfect, but the plugin tries to land near the relevant section instead of only opening the file at the top.
The plugin intentionally does not refresh automatically.
That is a deliberate performance/privacy/UX choice: no background indexing, no hidden embedding jobs, no surprise CPU/GPU usage while you are writing.
When you add or edit notes and want search to include them, open the command palette with Ctrl/Cmd + P and run:
QMD Semantic Search: Refresh semantic index now
Or open plugin settings and click:
Refresh semantic index
This runs locally:
qmd update
qmd embed
The vault-specific QMD database and config are stored inside the vault plugin folder:
<your-vault>/.obsidian/plugins/qmd-semantic-search/qmd/index.sqlite
<your-vault>/.obsidian/plugins/qmd-semantic-search/qmd/config/index.yml
This keeps each vault's index separate.
Large downloaded QMD model files are still stored in QMD's normal global model cache, for example:
~/.cache/qmd/models/
This avoids downloading/copying large model files for every vault.
This plugin does not call remote APIs.
It does not use:
fetchIt only starts the local QMD executable through child_process.spawn() with shell: false and argument arrays.
Important distinction: this plugin can only vouch for its own behavior. QMD is separate software. QMD may download local models from Hugging Face the first time embeddings are generated.
The plugin delegates to local QMD commands:
qmd collection add <vault> --name <collection> --mask **/*.md
qmd update
qmd embed
qmd search <query> --json
qmd vsearch <query> --json
QMD stores documents and vectors in SQLite. Semantic search works by converting text to vectors with a local embedding model, then finding nearby vectors for your query.
No chat LLM is required for embeddings. An embedding model is an AI model, but it can run fully locally and simply maps text to numeric vectors.
npm install
npm run build
Or with Bun:
bun install
bun run build
The build outputs:
main.js
manifest.json
styles.css
src/main.ts plugin source
main.js bundled production plugin
manifest.json Obsidian plugin manifest
styles.css plugin styles
production/qmd-semantic-search copy-ready production folder
Install it:
bun install -g @tobilu/qmd
or:
npm install -g @tobilu/qmd
Then restart Obsidian.
Open the command palette with Ctrl/Cmd + P and run:
Refresh semantic index now
Try fewer words or more exact terms. Technical command searches often work better with keyword matching, which the plugin shows first.
The first semantic query may need to load the local embedding model. Later queries are usually faster. The plugin uses keyword-first search so you are not stuck waiting for semantic results.
That is the default. The plugin does not auto-refresh. It only indexes/embeds when you explicitly prepare or refresh.
MIT