2025-12-08 08:16:16 +08:00
# QMD - Quick Markdown Search
2025-12-09 01:54:57 +08:00
An on-device search engine for everything you need to remember. Index your markdown notes, meeting transcripts, documentation, and knowledge bases. Search with keywords or natural language. Ideal for your agentic flows.
2025-12-21 06:03:41 +08:00
QMD combines BM25 full-text search, vector semantic search, and LLM re-ranking—all running locally via node-llama-cpp with GGUF models.
2025-12-09 01:54:57 +08:00
## Quick Start
```sh
2025-12-09 03:59:56 +08:00
# Install globally
bun install -g https://github.com/tobi/qmd
2025-12-09 01:54:57 +08:00
Add path normalization, output format tests, and fix test isolation
- Add support for collection/path.md format in get command (checks if
first component is a known collection before treating as filesystem path)
- Add comprehensive output format tests verifying qmd:// URIs, docid,
and context in JSON, CSV, MD, XML, files, and CLI formats
- Add path normalization tests for various input formats:
qmd://, //, qmd:////, collection/path, and path:line suffix
- Add isolated test environments (createIsolatedTestEnv) to prevent
YAML config conflicts between test suites
- Add test fixture files test1.md and test2.md for path tests
- Update runQmd helper to accept custom configDir parameter
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-21 02:45:18 +08:00
# Create collections for your notes, docs, and meeting transcripts
qmd collection add ~/notes --name notes
qmd collection add ~/Documents/meetings --name meetings
qmd collection add ~/work/docs --name docs
2025-12-09 01:54:57 +08:00
# Add context to help with search results
Add path normalization, output format tests, and fix test isolation
- Add support for collection/path.md format in get command (checks if
first component is a known collection before treating as filesystem path)
- Add comprehensive output format tests verifying qmd:// URIs, docid,
and context in JSON, CSV, MD, XML, files, and CLI formats
- Add path normalization tests for various input formats:
qmd://, //, qmd:////, collection/path, and path:line suffix
- Add isolated test environments (createIsolatedTestEnv) to prevent
YAML config conflicts between test suites
- Add test fixture files test1.md and test2.md for path tests
- Update runQmd helper to accept custom configDir parameter
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-21 02:45:18 +08:00
qmd context add qmd://notes "Personal notes and ideas"
qmd context add qmd://meetings "Meeting transcripts and notes"
qmd context add qmd://docs "Work documentation"
2025-12-09 01:54:57 +08:00
# Generate embeddings for semantic search
qmd embed
# Search across everything
qmd search "project timeline" # Fast keyword search
qmd vsearch "how to deploy" # Semantic search
qmd query "quarterly planning process" # Hybrid + reranking (best quality)
# Get a specific document
qmd get "meetings/2024-01-15.md"
Add path normalization, output format tests, and fix test isolation
- Add support for collection/path.md format in get command (checks if
first component is a known collection before treating as filesystem path)
- Add comprehensive output format tests verifying qmd:// URIs, docid,
and context in JSON, CSV, MD, XML, files, and CLI formats
- Add path normalization tests for various input formats:
qmd://, //, qmd:////, collection/path, and path:line suffix
- Add isolated test environments (createIsolatedTestEnv) to prevent
YAML config conflicts between test suites
- Add test fixture files test1.md and test2.md for path tests
- Update runQmd helper to accept custom configDir parameter
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-21 02:45:18 +08:00
# Get a document by docid (shown in search results)
qmd get "#abc123"
Refactor: extract store, LLM, and formatter modules with comprehensive tests
- Extract store.ts: database operations, search, document retrieval
- createStore() factory pattern for clean DB lifecycle management
- Unified DocumentResult type with optional body loading
- Snippet extraction with diff-style headers (@@ -line,count @@)
- Extract llm.ts: LLM abstraction layer with Ollama implementation
- Clean interface for embed, generate, rerank operations
- High-level rerankerLogprobsCheck with logprob-based scoring
- Query expansion support
- Extract formatter.ts: output formatting utilities
- Support for CLI, JSON, CSV, MD, XML formats
- MCP-specific CSV formatting
- Extract mcp.ts: MCP server using createStore() pattern
- Single DB connection for server lifetime (fixes closed DB errors)
- URL-decode resource paths for proper space/special char handling
- Add comprehensive test suites (215 tests total)
- store.test.ts: 96 tests covering all store operations
- llm.test.ts: 60 tests for LLM abstraction
- mcp.test.ts: 59 tests for MCP endpoints and resources
- All tests use mocked Ollama (errors on unmocked calls)
- Add bun run inspector script for MCP debugging
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-10 05:33:32 +08:00
# Get multiple documents by glob pattern
qmd multi-get "journals/2025-05*.md"
# Search within a specific collection
qmd search "API" -c notes
2025-12-09 01:54:57 +08:00
# Export all matches for an agent
qmd search "API" --all --files --min-score 0.3
```
### Using with AI Agents
QMD's `--json` and `--files` output formats are designed for agentic workflows:
```sh
# Get structured results for an LLM
qmd search "authentication" --json -n 10
# List all relevant files above a threshold
qmd query "error handling" --all --files --min-score 0.4
# Retrieve full document content
qmd get "docs/api-reference.md" --full
```
2025-12-08 08:16:16 +08:00
2025-12-09 03:59:56 +08:00
### MCP Server
Although the tool works perfectly fine when you just tell your agent to use it on the command line, it also exposes an MCP (Model Context Protocol) server for tighter integration.
**Tools exposed:**
Refactor: extract store, LLM, and formatter modules with comprehensive tests
- Extract store.ts: database operations, search, document retrieval
- createStore() factory pattern for clean DB lifecycle management
- Unified DocumentResult type with optional body loading
- Snippet extraction with diff-style headers (@@ -line,count @@)
- Extract llm.ts: LLM abstraction layer with Ollama implementation
- Clean interface for embed, generate, rerank operations
- High-level rerankerLogprobsCheck with logprob-based scoring
- Query expansion support
- Extract formatter.ts: output formatting utilities
- Support for CLI, JSON, CSV, MD, XML formats
- MCP-specific CSV formatting
- Extract mcp.ts: MCP server using createStore() pattern
- Single DB connection for server lifetime (fixes closed DB errors)
- URL-decode resource paths for proper space/special char handling
- Add comprehensive test suites (215 tests total)
- store.test.ts: 96 tests covering all store operations
- llm.test.ts: 60 tests for LLM abstraction
- mcp.test.ts: 59 tests for MCP endpoints and resources
- All tests use mocked Ollama (errors on unmocked calls)
- Add bun run inspector script for MCP debugging
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-10 05:33:32 +08:00
- `qmd_search` - Fast BM25 keyword search (supports collection filter)
- `qmd_vsearch` - Semantic vector search (supports collection filter)
- `qmd_query` - Hybrid search with reranking (supports collection filter)
Add path normalization, output format tests, and fix test isolation
- Add support for collection/path.md format in get command (checks if
first component is a known collection before treating as filesystem path)
- Add comprehensive output format tests verifying qmd:// URIs, docid,
and context in JSON, CSV, MD, XML, files, and CLI formats
- Add path normalization tests for various input formats:
qmd://, //, qmd:////, collection/path, and path:line suffix
- Add isolated test environments (createIsolatedTestEnv) to prevent
YAML config conflicts between test suites
- Add test fixture files test1.md and test2.md for path tests
- Update runQmd helper to accept custom configDir parameter
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-21 02:45:18 +08:00
- `qmd_get` - Retrieve document by path or docid (with fuzzy matching suggestions)
- `qmd_multi_get` - Retrieve multiple documents by glob pattern, list, or docids
2025-12-09 03:59:56 +08:00
- `qmd_status` - Index health and collection info
**Claude Desktop configuration** (`~/Library/Application Support/Claude/claude_desktop_config.json`):
```json
{
"mcpServers": {
"qmd": {
"command": "qmd",
"args": ["mcp"]
}
}
}
```
**Claude Code configuration** (`~/.claude/settings.json`):
```json
{
"mcpServers": {
"qmd": {
"command": "qmd",
"args": ["mcp"]
}
}
}
```
2025-12-08 08:16:16 +08:00
## Architecture
```
┌─────────────────────────────────────────────────────────────────────────────┐
2025-12-08 22:31:20 +08:00
│ QMD Hybrid Search Pipeline │
2025-12-08 08:16:16 +08:00
└─────────────────────────────────────────────────────────────────────────────┘
┌─────────────────┐
│ User Query │
└────────┬────────┘
│
┌──────────────┴──────────────┐
▼ ▼
┌────────────────┐ ┌────────────────┐
2025-12-08 22:31:20 +08:00
│ Query Expansion│ │ Original Query│
2025-12-21 06:03:41 +08:00
│ (Qwen3-0.6B) │ │ (× 2 weight) │
2025-12-08 08:16:16 +08:00
└───────┬────────┘ └───────┬────────┘
│ │
2025-12-08 22:31:20 +08:00
│ 2 alternative queries │
2025-12-08 08:16:16 +08:00
└──────────────┬──────────────┘
│
2025-12-08 22:31:20 +08:00
┌───────────────────────┼───────────────────────┐
▼ ▼ ▼
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
│ Original Query │ │ Expanded Query 1│ │ Expanded Query 2│
└────────┬────────┘ └────────┬────────┘ └────────┬────────┘
│ │ │
┌───────┴───────┐ ┌───────┴───────┐ ┌───────┴───────┐
▼ ▼ ▼ ▼ ▼ ▼
┌───────┐ ┌───────┐ ┌───────┐ ┌───────┐ ┌───────┐ ┌───────┐
│ BM25 │ │Vector │ │ BM25 │ │Vector │ │ BM25 │ │Vector │
│(FTS5) │ │Search │ │(FTS5) │ │Search │ │(FTS5) │ │Search │
└───┬───┘ └───┬───┘ └───┬───┘ └───┬───┘ └───┬───┘ └───┬───┘
│ │ │ │ │ │
└───────┬───────┘ └──────┬──────┘ └──────┬──────┘
│ │ │
└────────────────────────┼───────────────────────┘
│
▼
2025-12-08 08:16:16 +08:00
┌───────────────────────┐
│ RRF Fusion + Bonus │
2025-12-08 22:31:20 +08:00
│ Original query: × 2 │
│ Top-rank bonus: +0.05│
2025-12-08 08:16:16 +08:00
│ Top 30 Kept │
└───────────┬───────────┘
│
▼
┌───────────────────────┐
│ LLM Re-ranking │
│ (qwen3-reranker) │
│ Yes/No + logprobs │
└───────────┬───────────┘
│
▼
┌───────────────────────┐
│ Position-Aware Blend │
2025-12-08 22:31:20 +08:00
│ Top 1-3: 75% RRF │
│ Top 4-10: 60% RRF │
│ Top 11+: 40% RRF │
2025-12-08 08:16:16 +08:00
└───────────────────────┘
```
## Score Normalization & Fusion
### Search Backends
| Backend | Raw Score | Conversion | Range |
|---------|-----------|------------|-------|
| **FTS (BM25)** | SQLite FTS5 BM25 | `Math.abs(score)` | 0 to ~25+ |
| **Vector** | Cosine distance | `1 / (1 + distance)` | 0.0 to 1.0 |
| **Reranker** | LLM 0-10 rating | `score / 10` | 0.0 to 1.0 |
### Fusion Strategy
The `query` command uses **Reciprocal Rank Fusion (RRF)** with position-aware blending:
1. **Query Expansion** : Original query (× 2 for weighting) + 1 LLM variation
2. **Parallel Retrieval** : Each query searches both FTS and vector indexes
3. **RRF Fusion** : Combine all result lists using `score = Σ(1/(k+rank+1))` where k=60
4. **Top-Rank Bonus** : Documents ranking #1 in any list get +0.05, #2 -3 get +0.02
5. **Top-K Selection** : Take top 30 candidates for reranking
6. **Re-ranking** : LLM scores each document (yes/no with logprobs confidence)
7. **Position-Aware Blending** :
- RRF rank 1-3: 75% retrieval, 25% reranker (preserves exact matches)
- RRF rank 4-10: 60% retrieval, 40% reranker
- RRF rank 11+: 40% retrieval, 60% reranker (trust reranker more)
**Why this approach**: Pure RRF can dilute exact matches when expanded queries don't match. The top-rank bonus preserves documents that score #1 for the original query. Position-aware blending prevents the reranker from destroying high-confidence retrieval results.
### Score Interpretation
| Score | Meaning |
|-------|---------|
| 0.8 - 1.0 | Highly relevant |
| 0.5 - 0.8 | Moderately relevant |
| 0.2 - 0.5 | Somewhat relevant |
| 0.0 - 0.2 | Low relevance |
## Requirements
### System Requirements
- **Bun** >= 1.0.0
- **macOS**: Homebrew SQLite (for extension support)
```sh
brew install sqlite
```
2025-12-21 06:03:41 +08:00
### GGUF Models (via node-llama-cpp)
2025-12-08 08:16:16 +08:00
2025-12-21 06:03:41 +08:00
QMD uses three local GGUF models (auto-downloaded on first use):
2025-12-08 08:16:16 +08:00
| Model | Purpose | Size |
|-------|---------|------|
2025-12-21 06:03:41 +08:00
| `embeddinggemma-300M-Q8_0` | Vector embeddings | ~300MB |
| `qwen3-reranker-0.6b-q8_0` | Re-ranking | ~640MB |
| `Qwen3-0.6B-Q8_0` | Query expansion | ~640MB |
2025-12-08 08:16:16 +08:00
2025-12-21 06:03:41 +08:00
Models are downloaded from HuggingFace and cached in `~/.cache/qmd/models/` .
2025-12-08 08:16:16 +08:00
## Installation
```sh
bun install
```
## Usage
Add path normalization, output format tests, and fix test isolation
- Add support for collection/path.md format in get command (checks if
first component is a known collection before treating as filesystem path)
- Add comprehensive output format tests verifying qmd:// URIs, docid,
and context in JSON, CSV, MD, XML, files, and CLI formats
- Add path normalization tests for various input formats:
qmd://, //, qmd:////, collection/path, and path:line suffix
- Add isolated test environments (createIsolatedTestEnv) to prevent
YAML config conflicts between test suites
- Add test fixture files test1.md and test2.md for path tests
- Update runQmd helper to accept custom configDir parameter
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-21 02:45:18 +08:00
### Collection Management
2025-12-08 08:16:16 +08:00
```sh
Add path normalization, output format tests, and fix test isolation
- Add support for collection/path.md format in get command (checks if
first component is a known collection before treating as filesystem path)
- Add comprehensive output format tests verifying qmd:// URIs, docid,
and context in JSON, CSV, MD, XML, files, and CLI formats
- Add path normalization tests for various input formats:
qmd://, //, qmd:////, collection/path, and path:line suffix
- Add isolated test environments (createIsolatedTestEnv) to prevent
YAML config conflicts between test suites
- Add test fixture files test1.md and test2.md for path tests
- Update runQmd helper to accept custom configDir parameter
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-21 02:45:18 +08:00
# Create a collection from current directory
qmd collection add . --name myproject
# Create a collection with explicit path and custom glob mask
qmd collection add ~/Documents/notes --name notes --mask "**/*.md"
# List all collections
qmd collection list
# Remove a collection
qmd collection remove myproject
2025-12-08 08:16:16 +08:00
Add path normalization, output format tests, and fix test isolation
- Add support for collection/path.md format in get command (checks if
first component is a known collection before treating as filesystem path)
- Add comprehensive output format tests verifying qmd:// URIs, docid,
and context in JSON, CSV, MD, XML, files, and CLI formats
- Add path normalization tests for various input formats:
qmd://, //, qmd:////, collection/path, and path:line suffix
- Add isolated test environments (createIsolatedTestEnv) to prevent
YAML config conflicts between test suites
- Add test fixture files test1.md and test2.md for path tests
- Update runQmd helper to accept custom configDir parameter
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-21 02:45:18 +08:00
# Rename a collection
qmd collection rename myproject my-project
2025-12-08 08:16:16 +08:00
Add path normalization, output format tests, and fix test isolation
- Add support for collection/path.md format in get command (checks if
first component is a known collection before treating as filesystem path)
- Add comprehensive output format tests verifying qmd:// URIs, docid,
and context in JSON, CSV, MD, XML, files, and CLI formats
- Add path normalization tests for various input formats:
qmd://, //, qmd:////, collection/path, and path:line suffix
- Add isolated test environments (createIsolatedTestEnv) to prevent
YAML config conflicts between test suites
- Add test fixture files test1.md and test2.md for path tests
- Update runQmd helper to accept custom configDir parameter
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-21 02:45:18 +08:00
# List files in a collection
qmd ls notes
qmd ls notes/subfolder
2025-12-08 08:16:16 +08:00
```
### Generate Vector Embeddings
```sh
2025-12-21 06:03:41 +08:00
# Embed all indexed documents (800 tokens/chunk, 15% overlap)
2025-12-08 08:16:16 +08:00
qmd embed
2025-12-08 22:31:20 +08:00
# Force re-embed everything
qmd embed -f
```
Add path normalization, output format tests, and fix test isolation
- Add support for collection/path.md format in get command (checks if
first component is a known collection before treating as filesystem path)
- Add comprehensive output format tests verifying qmd:// URIs, docid,
and context in JSON, CSV, MD, XML, files, and CLI formats
- Add path normalization tests for various input formats:
qmd://, //, qmd:////, collection/path, and path:line suffix
- Add isolated test environments (createIsolatedTestEnv) to prevent
YAML config conflicts between test suites
- Add test fixture files test1.md and test2.md for path tests
- Update runQmd helper to accept custom configDir parameter
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-21 02:45:18 +08:00
### Context Management
Context adds descriptive metadata to collections and paths, helping search understand your content.
2025-12-08 22:31:20 +08:00
```sh
Add path normalization, output format tests, and fix test isolation
- Add support for collection/path.md format in get command (checks if
first component is a known collection before treating as filesystem path)
- Add comprehensive output format tests verifying qmd:// URIs, docid,
and context in JSON, CSV, MD, XML, files, and CLI formats
- Add path normalization tests for various input formats:
qmd://, //, qmd:////, collection/path, and path:line suffix
- Add isolated test environments (createIsolatedTestEnv) to prevent
YAML config conflicts between test suites
- Add test fixture files test1.md and test2.md for path tests
- Update runQmd helper to accept custom configDir parameter
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-21 02:45:18 +08:00
# Add context to a collection (using qmd:// virtual paths)
qmd context add qmd://notes "Personal notes and ideas"
qmd context add qmd://docs/api "API documentation"
# Add context from within a collection directory
cd ~/notes & & qmd context add "Personal notes and ideas"
cd ~/notes/work & & qmd context add "Work-related notes"
# Add global context (applies to all collections)
qmd context add / "Knowledge base for my projects"
# List all contexts
qmd context list
# Remove context
qmd context rm qmd://notes/old
2025-12-08 08:16:16 +08:00
```
### Search Commands
```
┌──────────────────────────────────────────────────────────────────┐
│ Search Modes │
├──────────┬───────────────────────────────────────────────────────┤
│ search │ BM25 full-text search only │
│ vsearch │ Vector semantic search only │
│ query │ Hybrid: FTS + Vector + Query Expansion + Re-ranking │
└──────────┴───────────────────────────────────────────────────────┘
```
```sh
# Full-text search (fast, keyword-based)
qmd search "authentication flow"
# Vector search (semantic similarity)
qmd vsearch "how to login"
# Hybrid search with re-ranking (best quality)
qmd query "user authentication"
```
### Options
```sh
Refactor: extract store, LLM, and formatter modules with comprehensive tests
- Extract store.ts: database operations, search, document retrieval
- createStore() factory pattern for clean DB lifecycle management
- Unified DocumentResult type with optional body loading
- Snippet extraction with diff-style headers (@@ -line,count @@)
- Extract llm.ts: LLM abstraction layer with Ollama implementation
- Clean interface for embed, generate, rerank operations
- High-level rerankerLogprobsCheck with logprob-based scoring
- Query expansion support
- Extract formatter.ts: output formatting utilities
- Support for CLI, JSON, CSV, MD, XML formats
- MCP-specific CSV formatting
- Extract mcp.ts: MCP server using createStore() pattern
- Single DB connection for server lifetime (fixes closed DB errors)
- URL-decode resource paths for proper space/special char handling
- Add comprehensive test suites (215 tests total)
- store.test.ts: 96 tests covering all store operations
- llm.test.ts: 60 tests for LLM abstraction
- mcp.test.ts: 59 tests for MCP endpoints and resources
- All tests use mocked Ollama (errors on unmocked calls)
- Add bun run inspector script for MCP debugging
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-10 05:33:32 +08:00
# Search options
2025-12-08 22:31:20 +08:00
-n < num > # Number of results (default: 5, or 20 for --files/--json)
Refactor: extract store, LLM, and formatter modules with comprehensive tests
- Extract store.ts: database operations, search, document retrieval
- createStore() factory pattern for clean DB lifecycle management
- Unified DocumentResult type with optional body loading
- Snippet extraction with diff-style headers (@@ -line,count @@)
- Extract llm.ts: LLM abstraction layer with Ollama implementation
- Clean interface for embed, generate, rerank operations
- High-level rerankerLogprobsCheck with logprob-based scoring
- Query expansion support
- Extract formatter.ts: output formatting utilities
- Support for CLI, JSON, CSV, MD, XML formats
- MCP-specific CSV formatting
- Extract mcp.ts: MCP server using createStore() pattern
- Single DB connection for server lifetime (fixes closed DB errors)
- URL-decode resource paths for proper space/special char handling
- Add comprehensive test suites (215 tests total)
- store.test.ts: 96 tests covering all store operations
- llm.test.ts: 60 tests for LLM abstraction
- mcp.test.ts: 59 tests for MCP endpoints and resources
- All tests use mocked Ollama (errors on unmocked calls)
- Add bun run inspector script for MCP debugging
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-10 05:33:32 +08:00
-c, --collection # Restrict search to a specific collection
2025-12-09 01:54:57 +08:00
--all # Return all matches (use with --min-score to filter)
2025-12-08 08:16:16 +08:00
--min-score < num > # Minimum score threshold (default: 0)
--full # Show full document content
Add path normalization, output format tests, and fix test isolation
- Add support for collection/path.md format in get command (checks if
first component is a known collection before treating as filesystem path)
- Add comprehensive output format tests verifying qmd:// URIs, docid,
and context in JSON, CSV, MD, XML, files, and CLI formats
- Add path normalization tests for various input formats:
qmd://, //, qmd:////, collection/path, and path:line suffix
- Add isolated test environments (createIsolatedTestEnv) to prevent
YAML config conflicts between test suites
- Add test fixture files test1.md and test2.md for path tests
- Update runQmd helper to accept custom configDir parameter
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-21 02:45:18 +08:00
--line-numbers # Add line numbers to output
Refactor: extract store, LLM, and formatter modules with comprehensive tests
- Extract store.ts: database operations, search, document retrieval
- createStore() factory pattern for clean DB lifecycle management
- Unified DocumentResult type with optional body loading
- Snippet extraction with diff-style headers (@@ -line,count @@)
- Extract llm.ts: LLM abstraction layer with Ollama implementation
- Clean interface for embed, generate, rerank operations
- High-level rerankerLogprobsCheck with logprob-based scoring
- Query expansion support
- Extract formatter.ts: output formatting utilities
- Support for CLI, JSON, CSV, MD, XML formats
- MCP-specific CSV formatting
- Extract mcp.ts: MCP server using createStore() pattern
- Single DB connection for server lifetime (fixes closed DB errors)
- URL-decode resource paths for proper space/special char handling
- Add comprehensive test suites (215 tests total)
- store.test.ts: 96 tests covering all store operations
- llm.test.ts: 60 tests for LLM abstraction
- mcp.test.ts: 59 tests for MCP endpoints and resources
- All tests use mocked Ollama (errors on unmocked calls)
- Add bun run inspector script for MCP debugging
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-10 05:33:32 +08:00
--index < name > # Use named index
# Output formats (for search and multi-get)
Add path normalization, output format tests, and fix test isolation
- Add support for collection/path.md format in get command (checks if
first component is a known collection before treating as filesystem path)
- Add comprehensive output format tests verifying qmd:// URIs, docid,
and context in JSON, CSV, MD, XML, files, and CLI formats
- Add path normalization tests for various input formats:
qmd://, //, qmd:////, collection/path, and path:line suffix
- Add isolated test environments (createIsolatedTestEnv) to prevent
YAML config conflicts between test suites
- Add test fixture files test1.md and test2.md for path tests
- Update runQmd helper to accept custom configDir parameter
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-21 02:45:18 +08:00
--files # Output: docid,score,filepath,context
--json # JSON output with snippets
Refactor: extract store, LLM, and formatter modules with comprehensive tests
- Extract store.ts: database operations, search, document retrieval
- createStore() factory pattern for clean DB lifecycle management
- Unified DocumentResult type with optional body loading
- Snippet extraction with diff-style headers (@@ -line,count @@)
- Extract llm.ts: LLM abstraction layer with Ollama implementation
- Clean interface for embed, generate, rerank operations
- High-level rerankerLogprobsCheck with logprob-based scoring
- Query expansion support
- Extract formatter.ts: output formatting utilities
- Support for CLI, JSON, CSV, MD, XML formats
- MCP-specific CSV formatting
- Extract mcp.ts: MCP server using createStore() pattern
- Single DB connection for server lifetime (fixes closed DB errors)
- URL-decode resource paths for proper space/special char handling
- Add comprehensive test suites (215 tests total)
- store.test.ts: 96 tests covering all store operations
- llm.test.ts: 60 tests for LLM abstraction
- mcp.test.ts: 59 tests for MCP endpoints and resources
- All tests use mocked Ollama (errors on unmocked calls)
- Add bun run inspector script for MCP debugging
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-10 05:33:32 +08:00
--csv # CSV output
2025-12-08 22:31:20 +08:00
--md # Markdown output
--xml # XML output
Refactor: extract store, LLM, and formatter modules with comprehensive tests
- Extract store.ts: database operations, search, document retrieval
- createStore() factory pattern for clean DB lifecycle management
- Unified DocumentResult type with optional body loading
- Snippet extraction with diff-style headers (@@ -line,count @@)
- Extract llm.ts: LLM abstraction layer with Ollama implementation
- Clean interface for embed, generate, rerank operations
- High-level rerankerLogprobsCheck with logprob-based scoring
- Query expansion support
- Extract formatter.ts: output formatting utilities
- Support for CLI, JSON, CSV, MD, XML formats
- MCP-specific CSV formatting
- Extract mcp.ts: MCP server using createStore() pattern
- Single DB connection for server lifetime (fixes closed DB errors)
- URL-decode resource paths for proper space/special char handling
- Add comprehensive test suites (215 tests total)
- store.test.ts: 96 tests covering all store operations
- llm.test.ts: 60 tests for LLM abstraction
- mcp.test.ts: 59 tests for MCP endpoints and resources
- All tests use mocked Ollama (errors on unmocked calls)
- Add bun run inspector script for MCP debugging
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-10 05:33:32 +08:00
Add path normalization, output format tests, and fix test isolation
- Add support for collection/path.md format in get command (checks if
first component is a known collection before treating as filesystem path)
- Add comprehensive output format tests verifying qmd:// URIs, docid,
and context in JSON, CSV, MD, XML, files, and CLI formats
- Add path normalization tests for various input formats:
qmd://, //, qmd:////, collection/path, and path:line suffix
- Add isolated test environments (createIsolatedTestEnv) to prevent
YAML config conflicts between test suites
- Add test fixture files test1.md and test2.md for path tests
- Update runQmd helper to accept custom configDir parameter
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-21 02:45:18 +08:00
# Get options
qmd get < file > [:line] # Get document, optionally starting at line
-l < num > # Maximum lines to return
--from < num > # Start from line number
Refactor: extract store, LLM, and formatter modules with comprehensive tests
- Extract store.ts: database operations, search, document retrieval
- createStore() factory pattern for clean DB lifecycle management
- Unified DocumentResult type with optional body loading
- Snippet extraction with diff-style headers (@@ -line,count @@)
- Extract llm.ts: LLM abstraction layer with Ollama implementation
- Clean interface for embed, generate, rerank operations
- High-level rerankerLogprobsCheck with logprob-based scoring
- Query expansion support
- Extract formatter.ts: output formatting utilities
- Support for CLI, JSON, CSV, MD, XML formats
- MCP-specific CSV formatting
- Extract mcp.ts: MCP server using createStore() pattern
- Single DB connection for server lifetime (fixes closed DB errors)
- URL-decode resource paths for proper space/special char handling
- Add comprehensive test suites (215 tests total)
- store.test.ts: 96 tests covering all store operations
- llm.test.ts: 60 tests for LLM abstraction
- mcp.test.ts: 59 tests for MCP endpoints and resources
- All tests use mocked Ollama (errors on unmocked calls)
- Add bun run inspector script for MCP debugging
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-10 05:33:32 +08:00
# Multi-get options
-l < num > # Maximum lines per file
--max-bytes < num > # Skip files larger than N bytes (default: 10KB)
2025-12-08 08:16:16 +08:00
```
### Output Format
Default output is colorized CLI format (respects `NO_COLOR` env):
```
Add path normalization, output format tests, and fix test isolation
- Add support for collection/path.md format in get command (checks if
first component is a known collection before treating as filesystem path)
- Add comprehensive output format tests verifying qmd:// URIs, docid,
and context in JSON, CSV, MD, XML, files, and CLI formats
- Add path normalization tests for various input formats:
qmd://, //, qmd:////, collection/path, and path:line suffix
- Add isolated test environments (createIsolatedTestEnv) to prevent
YAML config conflicts between test suites
- Add test fixture files test1.md and test2.md for path tests
- Update runQmd helper to accept custom configDir parameter
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-21 02:45:18 +08:00
docs/guide.md:42 #a1b2c3
2025-12-09 01:54:57 +08:00
Title: Software Craftsmanship
Context: Work documentation
Score: 93%
This section covers the **craftsmanship** of building
quality software with attention to detail.
See also: engineering principles
Add path normalization, output format tests, and fix test isolation
- Add support for collection/path.md format in get command (checks if
first component is a known collection before treating as filesystem path)
- Add comprehensive output format tests verifying qmd:// URIs, docid,
and context in JSON, CSV, MD, XML, files, and CLI formats
- Add path normalization tests for various input formats:
qmd://, //, qmd:////, collection/path, and path:line suffix
- Add isolated test environments (createIsolatedTestEnv) to prevent
YAML config conflicts between test suites
- Add test fixture files test1.md and test2.md for path tests
- Update runQmd helper to accept custom configDir parameter
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-21 02:45:18 +08:00
notes/meeting.md:15 #d4e5f6
2025-12-09 01:54:57 +08:00
Title: Q4 Planning
Context: Personal notes and ideas
Score: 67%
Discussion about code quality and craftsmanship
in the development process.
2025-12-08 08:16:16 +08:00
```
Add path normalization, output format tests, and fix test isolation
- Add support for collection/path.md format in get command (checks if
first component is a known collection before treating as filesystem path)
- Add comprehensive output format tests verifying qmd:// URIs, docid,
and context in JSON, CSV, MD, XML, files, and CLI formats
- Add path normalization tests for various input formats:
qmd://, //, qmd:////, collection/path, and path:line suffix
- Add isolated test environments (createIsolatedTestEnv) to prevent
YAML config conflicts between test suites
- Add test fixture files test1.md and test2.md for path tests
- Update runQmd helper to accept custom configDir parameter
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-21 02:45:18 +08:00
- **Path**: Collection-relative path (e.g., `docs/guide.md` )
- **Docid**: Short hash identifier (e.g., `#a1b2c3` ) - use with `qmd get #a1b2c3`
2025-12-09 01:54:57 +08:00
- **Title**: Extracted from document (first heading or filename)
Add path normalization, output format tests, and fix test isolation
- Add support for collection/path.md format in get command (checks if
first component is a known collection before treating as filesystem path)
- Add comprehensive output format tests verifying qmd:// URIs, docid,
and context in JSON, CSV, MD, XML, files, and CLI formats
- Add path normalization tests for various input formats:
qmd://, //, qmd:////, collection/path, and path:line suffix
- Add isolated test environments (createIsolatedTestEnv) to prevent
YAML config conflicts between test suites
- Add test fixture files test1.md and test2.md for path tests
- Update runQmd helper to accept custom configDir parameter
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-21 02:45:18 +08:00
- **Context**: Path context if configured via `qmd context add`
2025-12-08 08:16:16 +08:00
- **Score**: Color-coded (green >70%, yellow >40%, dim otherwise)
- **Snippet**: Context around match with query terms highlighted
### Examples
```sh
# Get 10 results with minimum score 0.3
qmd query -n 10 --min-score 0.3 "API design patterns"
# Output as markdown for LLM context
2025-12-08 22:31:20 +08:00
qmd search --md --full "error handling"
# JSON output for scripting
qmd query --json "quarterly reports"
2025-12-08 08:16:16 +08:00
# Use separate index for different knowledge base
qmd --index work search "quarterly reports"
```
Add path normalization, output format tests, and fix test isolation
- Add support for collection/path.md format in get command (checks if
first component is a known collection before treating as filesystem path)
- Add comprehensive output format tests verifying qmd:// URIs, docid,
and context in JSON, CSV, MD, XML, files, and CLI formats
- Add path normalization tests for various input formats:
qmd://, //, qmd:////, collection/path, and path:line suffix
- Add isolated test environments (createIsolatedTestEnv) to prevent
YAML config conflicts between test suites
- Add test fixture files test1.md and test2.md for path tests
- Update runQmd helper to accept custom configDir parameter
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-21 02:45:18 +08:00
### Index Maintenance
2025-12-08 08:16:16 +08:00
```sh
2025-12-08 22:31:20 +08:00
# Show index status and collections with contexts
qmd status
2025-12-08 08:16:16 +08:00
2025-12-08 22:31:20 +08:00
# Re-index all collections
Add path normalization, output format tests, and fix test isolation
- Add support for collection/path.md format in get command (checks if
first component is a known collection before treating as filesystem path)
- Add comprehensive output format tests verifying qmd:// URIs, docid,
and context in JSON, CSV, MD, XML, files, and CLI formats
- Add path normalization tests for various input formats:
qmd://, //, qmd:////, collection/path, and path:line suffix
- Add isolated test environments (createIsolatedTestEnv) to prevent
YAML config conflicts between test suites
- Add test fixture files test1.md and test2.md for path tests
- Update runQmd helper to accept custom configDir parameter
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-21 02:45:18 +08:00
qmd update
# Re-index with git pull first (for remote repos)
qmd update --pull
# Get document by filepath (with fuzzy matching suggestions)
qmd get notes/meeting.md
# Get document by docid (from search results)
qmd get "#abc123"
2025-12-08 08:16:16 +08:00
Add path normalization, output format tests, and fix test isolation
- Add support for collection/path.md format in get command (checks if
first component is a known collection before treating as filesystem path)
- Add comprehensive output format tests verifying qmd:// URIs, docid,
and context in JSON, CSV, MD, XML, files, and CLI formats
- Add path normalization tests for various input formats:
qmd://, //, qmd:////, collection/path, and path:line suffix
- Add isolated test environments (createIsolatedTestEnv) to prevent
YAML config conflicts between test suites
- Add test fixture files test1.md and test2.md for path tests
- Update runQmd helper to accept custom configDir parameter
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-21 02:45:18 +08:00
# Get document starting at line 50, max 100 lines
qmd get notes/meeting.md:50 -l 100
2025-12-08 22:31:20 +08:00
Refactor: extract store, LLM, and formatter modules with comprehensive tests
- Extract store.ts: database operations, search, document retrieval
- createStore() factory pattern for clean DB lifecycle management
- Unified DocumentResult type with optional body loading
- Snippet extraction with diff-style headers (@@ -line,count @@)
- Extract llm.ts: LLM abstraction layer with Ollama implementation
- Clean interface for embed, generate, rerank operations
- High-level rerankerLogprobsCheck with logprob-based scoring
- Query expansion support
- Extract formatter.ts: output formatting utilities
- Support for CLI, JSON, CSV, MD, XML formats
- MCP-specific CSV formatting
- Extract mcp.ts: MCP server using createStore() pattern
- Single DB connection for server lifetime (fixes closed DB errors)
- URL-decode resource paths for proper space/special char handling
- Add comprehensive test suites (215 tests total)
- store.test.ts: 96 tests covering all store operations
- llm.test.ts: 60 tests for LLM abstraction
- mcp.test.ts: 59 tests for MCP endpoints and resources
- All tests use mocked Ollama (errors on unmocked calls)
- Add bun run inspector script for MCP debugging
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-10 05:33:32 +08:00
# Get multiple documents by glob pattern
qmd multi-get "journals/2025-05*.md"
Add path normalization, output format tests, and fix test isolation
- Add support for collection/path.md format in get command (checks if
first component is a known collection before treating as filesystem path)
- Add comprehensive output format tests verifying qmd:// URIs, docid,
and context in JSON, CSV, MD, XML, files, and CLI formats
- Add path normalization tests for various input formats:
qmd://, //, qmd:////, collection/path, and path:line suffix
- Add isolated test environments (createIsolatedTestEnv) to prevent
YAML config conflicts between test suites
- Add test fixture files test1.md and test2.md for path tests
- Update runQmd helper to accept custom configDir parameter
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-21 02:45:18 +08:00
# Get multiple documents by comma-separated list (supports docids)
qmd multi-get "doc1.md, doc2.md, #abc123 "
Refactor: extract store, LLM, and formatter modules with comprehensive tests
- Extract store.ts: database operations, search, document retrieval
- createStore() factory pattern for clean DB lifecycle management
- Unified DocumentResult type with optional body loading
- Snippet extraction with diff-style headers (@@ -line,count @@)
- Extract llm.ts: LLM abstraction layer with Ollama implementation
- Clean interface for embed, generate, rerank operations
- High-level rerankerLogprobsCheck with logprob-based scoring
- Query expansion support
- Extract formatter.ts: output formatting utilities
- Support for CLI, JSON, CSV, MD, XML formats
- MCP-specific CSV formatting
- Extract mcp.ts: MCP server using createStore() pattern
- Single DB connection for server lifetime (fixes closed DB errors)
- URL-decode resource paths for proper space/special char handling
- Add comprehensive test suites (215 tests total)
- store.test.ts: 96 tests covering all store operations
- llm.test.ts: 60 tests for LLM abstraction
- mcp.test.ts: 59 tests for MCP endpoints and resources
- All tests use mocked Ollama (errors on unmocked calls)
- Add bun run inspector script for MCP debugging
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-10 05:33:32 +08:00
# Limit multi-get to files under 20KB
qmd multi-get "docs/*.md" --max-bytes 20480
# Output multi-get as JSON for agent processing
qmd multi-get "docs/*.md" --json
2025-12-08 22:31:20 +08:00
# Clean up cache and orphaned data
qmd cleanup
2025-12-08 08:16:16 +08:00
```
## Data Storage
Index stored in: `~/.cache/qmd/index.sqlite`
### Schema
```sql
Add path normalization, output format tests, and fix test isolation
- Add support for collection/path.md format in get command (checks if
first component is a known collection before treating as filesystem path)
- Add comprehensive output format tests verifying qmd:// URIs, docid,
and context in JSON, CSV, MD, XML, files, and CLI formats
- Add path normalization tests for various input formats:
qmd://, //, qmd:////, collection/path, and path:line suffix
- Add isolated test environments (createIsolatedTestEnv) to prevent
YAML config conflicts between test suites
- Add test fixture files test1.md and test2.md for path tests
- Update runQmd helper to accept custom configDir parameter
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-21 02:45:18 +08:00
collections -- Indexed directories with name and glob patterns
path_contexts -- Context descriptions by virtual path (qmd://...)
documents -- Markdown content with metadata and docid (6-char hash)
2025-12-08 08:16:16 +08:00
documents_fts -- FTS5 full-text index
2025-12-21 06:03:41 +08:00
content_vectors -- Embedding chunks (hash, seq, pos, 800 tokens each)
2025-12-08 22:31:20 +08:00
vectors_vec -- sqlite-vec vector index (hash_seq key)
2025-12-21 06:03:41 +08:00
llm_cache -- Cached LLM responses (query expansion, rerank scores)
2025-12-08 08:16:16 +08:00
```
## Environment Variables
| Variable | Default | Description |
|----------|---------|-------------|
| `XDG_CACHE_HOME` | `~/.cache` | Cache directory location |
## How It Works
### Indexing Flow
```
Add path normalization, output format tests, and fix test isolation
- Add support for collection/path.md format in get command (checks if
first component is a known collection before treating as filesystem path)
- Add comprehensive output format tests verifying qmd:// URIs, docid,
and context in JSON, CSV, MD, XML, files, and CLI formats
- Add path normalization tests for various input formats:
qmd://, //, qmd:////, collection/path, and path:line suffix
- Add isolated test environments (createIsolatedTestEnv) to prevent
YAML config conflicts between test suites
- Add test fixture files test1.md and test2.md for path tests
- Update runQmd helper to accept custom configDir parameter
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-21 02:45:18 +08:00
Collection ──► Glob Pattern ──► Markdown Files ──► Parse Title ──► Hash Content
│ │ │
│ │ ▼
│ │ Generate docid
│ │ (6-char hash)
│ │ │
└──────────────────────────────────────────────────►└──► Store in SQLite
│
▼
FTS5 Index
2025-12-08 08:16:16 +08:00
```
### Embedding Flow
2025-12-21 06:03:41 +08:00
Documents are chunked into 800-token pieces with 15% overlap:
2025-12-08 22:31:20 +08:00
2025-12-08 08:16:16 +08:00
```
2025-12-21 06:03:41 +08:00
Document ──► Chunk (800 tokens) ──► Format each chunk ──► node-llama-cpp ──► Store Vectors
│ "title | text" embedBatch()
2025-12-08 22:31:20 +08:00
│
└─► Chunks stored with:
- hash: document hash
- seq: chunk sequence (0, 1, 2...)
- pos: character position in original
2025-12-08 08:16:16 +08:00
```
### Query Flow (Hybrid)
```
2025-12-08 22:31:20 +08:00
Query ──► LLM Expansion ──► [Original, Variant 1, Variant 2]
│
┌─────────┴─────────┐
▼ ▼
For each query: FTS (BM25)
│ │
▼ ▼
Vector Search Ranked List
│
▼
Ranked List
│
└─────────┬─────────┘
▼
RRF Fusion (k=60)
Original query × 2 weight
Top-rank bonus: +0.05/#1, +0.02/#2-3
│
▼
Top 30 candidates
│
▼
LLM Re-ranking
(yes/no + logprob confidence)
│
▼
Position-Aware Blend
Rank 1-3: 75% RRF / 25% reranker
Rank 4-10: 60% RRF / 40% reranker
Rank 11+: 40% RRF / 60% reranker
│
▼
Final Results
2025-12-08 08:16:16 +08:00
```
## Model Configuration
2025-12-21 06:03:41 +08:00
Models are configured in `src/llm.ts` as HuggingFace URIs:
2025-12-08 08:16:16 +08:00
```typescript
2025-12-21 06:03:41 +08:00
const DEFAULT_EMBED_MODEL = "hf:ggml-org/embeddinggemma-300M-GGUF/embeddinggemma-300M-Q8_0.gguf";
const DEFAULT_RERANK_MODEL = "hf:ggml-org/Qwen3-Reranker-0.6B-Q8_0-GGUF/qwen3-reranker-0.6b-q8_0.gguf";
const DEFAULT_GENERATE_MODEL = "hf:ggml-org/Qwen3-0.6B-GGUF/Qwen3-0.6B-Q8_0.gguf";
2025-12-08 08:16:16 +08:00
```
### EmbeddingGemma Prompt Format
```
// For queries
"task: search result | query: {query}"
// For documents
"title: {title} | text: {content}"
```
### Qwen3-Reranker
2025-12-21 06:03:41 +08:00
Uses node-llama-cpp's `createRankingContext()` and `rankAndSort()` API for cross-encoder reranking. Returns documents sorted by relevance score (0.0 - 1.0).
2025-12-08 08:16:16 +08:00
### Qwen3 (Query Expansion)
2025-12-21 06:03:41 +08:00
Used for generating query variations via `LlamaChatSession` .
2025-12-08 08:16:16 +08:00
## License
MIT