QMD Semantic Search
pendingby Oleksii Chekulaiev
Semantic-first search for your vault using QMD (Quick Markdown Search). Provides vector-based semantic search with keyword fallback.
QMD Semantic Search for Obsidian
A fully local, privacy-first semantic search plugin for Obsidian. Powered by QMD (Quick Markdown Search), it brings AI-powered vector search to your vault without sending a single byte to any cloud service, API, or remote LLM. All embedding generation and search runs entirely on your machine.
Features
- 100% Local - No API keys, no cloud services, no remote LLMs. Your notes never leave your machine
- Semantic Search - Find notes by meaning, not just keywords. Ask questions like "notes about productivity" or "ideas related to machine learning"
- Automatic Fallback - Gracefully falls back to keyword (BM25) search when semantic search is unavailable
- Automatic Indexing & Embedding - Keeps your vault indexed and embedded in the background as you create and edit notes
- Responsive Search - 1-second debounce waits for you to stop typing, with animated progress indicator
- Cancellable - Typing while searching cancels the previous search immediately
- Native UX - Search modal and optional sidebar pane follow Obsidian design patterns
- Desktop Only - Requires filesystem access (macOS, Windows, Linux)
Prerequisites
Install QMD
This plugin requires QMD to be installed on your system. QMD is a standalone CLI tool for semantic markdown search that runs entirely locally.
System Requirements
- Bun >= 1.0.0 - Required runtime for QMD
- Disk space: ~300MB for embedding model (this plugin only uses
searchandvsearch) - Network: Internet connection required for first-time model download
Installation
macOS:
# Install Homebrew SQLite (required for QMD extensions)
# If you don't have Homebrew: /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
brew install sqlite
# Install Bun if needed
curl -fsSL https://bun.sh/install | bash
# Install QMD globally
bun install -g https://github.com/tobi/qmd
Linux:
# Install Bun if needed
curl -fsSL https://bun.sh/install | bash
# Install QMD globally
bun install -g https://github.com/tobi/qmd
Windows:
- Install Bun from bun.sh
- Run:
bun install -g https://github.com/tobi/qmd
Verify installation:
qmd --version
First-Time Model Download
When you first use QMD, it automatically downloads AI models from HuggingFace:
| Model | Purpose | Size | When Downloaded |
|---|---|---|---|
| embeddinggemma-300M-Q8_0 | Vector embeddings | ~300MB | First embed |
| qwen3-reranker-0.6b-q8_0 | Re-ranking | ~640MB | First query |
| Qwen3-1.7B-Q8_0 | Query expansion | ~2.2GB | First query |
Models are cached in ~/.cache/qmd/models/ and only downloaded once.
Note: This plugin uses search (keyword) and vsearch (semantic), which only require the embedding model (~300MB). The larger query expansion and reranking models are only needed if you use QMD's query command directly.
Installation
From Obsidian Community Plugins
- Open Obsidian Settings → Community Plugins
- Browse and search for "QMD Semantic Search"
- Install and enable the plugin
Manual Installation
- Download the latest release (
main.js,manifest.json,styles.css) - Create a folder
obsidian-qmdin your vault's.obsidian/plugins/directory - Copy the downloaded files into this folder
- Enable the plugin in Obsidian Settings → Community Plugins
Development Installation
# Clone the repository
git clone https://github.com/achekulaev/obsidian-qmd.git
cd obsidian-qmd
# Install dependencies
npm install
# Build the plugin
npm run build
# For development with hot reload
npm run dev
Getting Started
1. First-Time Setup
After enabling the plugin, it will automatically:
- Create a QMD collection for your vault
- Build an initial keyword index
2. Embeddings for Semantic Search
Semantic search requires AI embeddings. By default, embeddings are generated automatically when the plugin detects they're missing.
On first run:
- QMD downloads ~300MB embedding model (one-time)
- Generates embeddings for all markdown files (may take a few minutes for large vaults)
- Shows a notice when complete
You can disable auto-generation in Settings → QMD Semantic Search → "Auto-generate embeddings".
To manually regenerate embeddings, use Command Palette: "QMD: Generate Embeddings" or "QMD: Force Rebuild Embeddings".
3. Start Searching
- Command Palette: Run "QMD: Search"
- Ribbon Icon: Click the search icon in the left sidebar (if enabled)
- Keyboard Shortcut: Assign a hotkey in Settings → Hotkeys
How It Works
Semantic-First Philosophy
This plugin prioritizes semantic (AI/vector) search over traditional keyword search:
- Primary: Semantic search using
qmd vsearch - Fallback: Keyword (BM25) search using
qmd search
When you search:
- The plugin waits 1 second after you stop typing (debounce)
- An animated progress bar appears below the search input
- Semantic search is attempted first
- If semantic search fails (no embeddings, error, or optionally zero results), it falls back to keyword search
- A subtle notice indicates when fallback is used
Tip: If you start typing again while a search is running, the previous search is cancelled immediately.
Search Modes
| Mode | Description | When Used |
|---|---|---|
| Semantic | AI-powered meaning-based search | Default, when embeddings exist |
| Keyword | Traditional BM25 text matching | Fallback, or when explicitly selected |
Configuration
Access settings via Obsidian Settings → QMD Semantic Search
Core Settings
| Setting | Description | Default |
|---|---|---|
| QMD Binary Path | Path to QMD executable | qmd |
| Collection Name | QMD collection name | (derived from vault name) |
| Index Name | Optional QMD index override | (none) |
| File Mask | Glob pattern for files to index | **/*.md |
Indexing
| Setting | Description | Default |
|---|---|---|
| Debounce Delay | Wait time after changes before indexing | 45 seconds |
| Periodic Updates | Enable timed index updates | On |
| Update Interval | Minutes between periodic updates | 15 |
Search Behavior
| Setting | Description | Default |
|---|---|---|
| Default Search Mode | Primary search method | Semantic |
| Fallback on Failure | Use keyword if semantic fails | On |
| Fallback on Zero Results | Use keyword if no semantic results | Off |
| Show Embeddings Banner | Notify when embeddings missing | On |
| Auto-generate Embeddings | Generate embeddings automatically | On |
User Interface
| Setting | Description | Default |
|---|---|---|
| Ribbon Icon | Show search icon in sidebar | On |
| Search Pane | Enable persistent sidebar pane | Off |
| Show Scores | Display relevance scores | On |
Commands
| Command | Description |
|---|---|
| QMD: Search | Open the search modal |
| QMD: Open Search Pane | Open search in sidebar (if enabled) |
| QMD: Update Index Now | Manually trigger index update |
| QMD: Generate Embeddings | Build AI embeddings |
| QMD: Force Rebuild Embeddings | Rebuild all embeddings from scratch |
| QMD: Ensure Collection | Create collection if missing |
Troubleshooting
"QMD binary not found"
Ensure QMD is installed and accessible from your terminal:
which qmd # macOS/Linux
where qmd # Windows
If QMD is installed but not in PATH, specify the full path in settings.
First-time embedding fails
If embedding generation fails on first run:
- Check internet connection - Models must be downloaded from HuggingFace
- Check disk space - Need ~300MB free for embedding model
- macOS users - Ensure Homebrew SQLite is installed:
brew install sqlite - Check Bun installation - Run
bun --versionto verify Bun is installed - Try manually - Run
qmd embedin terminal to see detailed errors
"Semantic search unavailable"
This means embeddings haven't been generated. Either:
- Wait for auto-generation to complete (check for notice)
- Manually run "QMD: Generate Embeddings"
- Check Settings → Diagnostics for errors
Embedding generation is slow
First-time embedding involves:
- Downloading ~300MB embedding model (one-time)
- Processing all markdown files in your vault
For large vaults (1000+ files), this can take 5-10 minutes. Subsequent runs are faster.
Search is slow
- Large vaults may take time to search
- Consider reducing the file mask to index fewer files
- Ensure QMD has enough system resources
Index seems outdated
- Run "QMD: Update Index Now"
- Check that the debounce delay isn't too long
- Verify file watching is working (check vault events)
Desktop Only
This plugin requires direct filesystem access and only works on:
- macOS
- Windows
- Linux
Mobile platforms (iOS/Android) are not supported as they don't provide direct filesystem access to Obsidian plugins.
Development
Project Structure
obsidian-qmd/
├── src/
│ ├── main.ts # Plugin entry point
│ ├── settings.ts # Settings types and defaults
│ ├── qmd.ts # QMD CLI wrapper
│ ├── searchModal.ts # Search modal UI
│ ├── searchPane.ts # Sidebar search pane
│ ├── settingsTab.ts # Settings UI
│ └── __mocks__/ # Test mocks
├── manifest.json # Obsidian plugin manifest
├── package.json # Dependencies and scripts
└── tsconfig.json # TypeScript configuration
Scripts
# Development build with watch
npm run dev
# Production build
npm run build
# Run tests
npm test
# Run tests with coverage
npm run test:coverage
# Lint code
npm run lint
# Auto-fix lint issues
npm run lint:fix
Testing
# Run all tests
npm test
# Watch mode
npm run test:watch
# With coverage report
npm run test:coverage
Contributing
Contributions are welcome! Please:
- Fork the repository
- Create a feature branch
- Make your changes
- Run tests and linting
- Submit a pull request
License
MIT License - see LICENSE for details.
Credits
For plugin developers
Search results and similarity scores are powered by semantic analysis of your plugin's README. If your plugin isn't appearing for searches you'd expect, try updating your README to clearly describe your plugin's purpose, features, and use cases.