# qmd
qmd (Quick Markdown Search) is a local, on-device search engine for personal knowledge management. It indexes markdown files, meeting transcripts, documentation, and other text-based content stored across multiple collections on your computer.
It combines BM25 full-text search, vector semantic search, and LLM re-ranking—all running locally.
## Key Features
### Search Modes
- `search`: Fast BM25 keyword matching
- `vsearch`: Semantic similarity via embeddings
- `query`: Hybrid approach with query expansion and intelligent re-ranking
### Collection Management
- Index multiple directories as named collections
- Filter searches within specific collections
- Add contextual descriptions to help search understand content
### Output Flexibility
Supports multiple output formats: JSON (ideal for AI agents), CSV, markdown, and XML. Results can be displayed with line numbers, full content, or snippets.
### MCP Integration
qmd exposes a Model Context Protocol server, making it accessible to Claude Desktop and Claude Code.
#### Configuration for Claude Desktop
Location: `~/Library/Application Support/Claude/claude_desktop_config.json`
```json
{
"mcpServers": {
"qmd": {
"command": "qmd",
"args": ["mcp"]
}
}
}
```
#### Configuration for Claude Code
Location: `~/.claude/settings.json`
```json
{
"mcpServers": {
"qmd": {
"command": "qmd",
"args": ["mcp"]
}
}
}
```
#### Available MCP Tools
- `qmd_search`: Fast BM25 keyword search with optional collection filtering
- `qmd_vsearch`: Semantic vector search supporting collection filters
- `qmd_query`: Hybrid search combining retrieval and re-ranking
- `qmd_get`: Document retrieval by path or docid (includes fuzzy matching suggestions)
- `qmd_multi_get`: Batch document retrieval via glob patterns, lists, or docids
- `qmd_status`: Provides index health metrics and collection information
## Technical Architecture
### Search Pipeline
The hybrid `query` command uses Reciprocal Rank Fusion (RRF) to combine results from multiple search strategies:
- Query expansion using a local 1.7B parameter model
- Parallel full-text and vector index searches
- Position-aware score blending
- Re-ranking using a local reranker model
### Models Used
- embedding-gemma-300M (vector embeddings, ~300MB)
- qwen3-reranker-0.6b (re-ranking, ~640MB)
- Qwen3-1.7B (query expansion, ~2.2GB)
All models run locally via node-llama-cpp using GGUF format and are automatically downloaded on first use.
### Data Storage
The index lives in `~/.cache/qmd/index.sqlite`. The database includes tables for documents, full-text indexes, vector embeddings, and cached LLM responses.
## Installation & Setup
Requires Bun (≥1.0.0). macOS users need Homebrew SQLite for extension support.
```bash
bun install -g https://github.com/tobi/qmd
```
## Usage Examples
### Basic workflow
```bash
qmd collection add ~/notes --name notes --mask "**/*.md"
qmd context add qmd://notes "Personal Knowledge Base"
qmd embed
qmd query "pkm"
```
Add qmd mcp to claude: `claude mcp add qmd qmd mcp`
### Advanced retrieval
- Fetch by document path: `qmd get notes/meeting.md`
- Fetch by auto-generated ID: `qmd get "#abc123"`
- Retrieve multiple files: `qmd multi-get "journals/2025-05*.md"`
- Export for agents: `qmd search "API" --json --all`
## Score Interpretation
Results range from 0.0-1.0:
- Above 0.8: High relevance
- 0.5-0.8: Moderate relevance
- Below 0.2: Low relevance
## Tips
- Create embeddings using the CPU: `alias qmd='NODE_LLAMA_CPP_GPU=false qmd embed'`
- Exclude noise directories from a collection with an `ignore` list in `~/.config/qmd/index.yml`. This field is **not** shown in `qmd --help` or `qmd collection show`, but it is supported per collection:
```yaml
collections:
notes:
path: /path/to/vault
pattern: "**/*.md"
ignore:
- "**/.stversions/**" # Syncthing version archive
- "**/.obsidian/**"
- "**/.smart-env/**" # Smart Connections cache
```
qmd's `update` walker `scandir`s every subdirectory regardless of `pattern` (the pattern only filters results, it does not prune traversal). So an unreadable directory — e.g. a corrupt file inside a cloud-synced folder — crashes `qmd update` with an `EIO: i/o error, scandir ...`. The `ignore` patterns are passed to fastGlob's `ignore` option, which prunes those directories from the walk entirely — fixing the crash and noticeably speeding up indexing.
## References
- https://github.com/tobi/qmd
## Related
- [[Model Context Protocol (MCP)]]
- [[Obsidian]]
- [[Personal Knowledge Management (PKM)]]