org-qmd 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md ADDED
@@ -0,0 +1,529 @@
1
+ # Changelog
2
+
3
+ ## [Unreleased]
4
+
5
+ ### Added
6
+
7
+ - AST-aware chunking for code files via `web-tree-sitter`. Supported
8
+ languages: TypeScript/JavaScript, Python, Go, and Rust. Code files
9
+ are chunked at function, class, and import boundaries instead of
10
+ arbitrary text positions. Markdown and unknown file types are unchanged.
11
+ - `--chunk-strategy <auto|regex>` flag for `qmd embed` and `qmd query`.
12
+ Default is `regex` (existing behavior). Use `auto` to enable AST-aware
13
+ chunking for code files.
14
+ - `qmd status` now shows AST grammar availability.
15
+ - SDK: `chunkStrategy` option on `embed()` and `search()` methods.
16
+
17
+ ### Fixes
18
+
19
+ - Fix paths in nix flake
20
+ - Sync stale `bun.lock` (`better-sqlite3` 11.x → 12.x). CI and release
21
+ script now use `--frozen-lockfile` to prevent recurrence. #386
22
+ (thanks @Mic92)
23
+
24
+ ## [2.0.1] - 2026-03-10
25
+
26
+ ### Changes
27
+
28
+ - `qmd skill install` copies the packaged QMD skill into
29
+ `~/.claude/commands/` for one-command setup. #355 (thanks @nibzard)
30
+
31
+ ### Fixes
32
+
33
+ - Fix Qwen3-Embedding GGUF filename case — HuggingFace filenames are
34
+ case-sensitive, the lowercase variant returned 404. #349 (thanks @byheaven)
35
+ - Resolve symlinked global launcher path so `qmd` works correctly when
36
+ installed via `npm i -g`. #352 (thanks @nibzard)
37
+
38
+ ## [2.0.0] - 2026-03-10
39
+
40
+ QMD 2.0 declares a stable library API. The SDK is now the primary interface —
41
+ the MCP server is a clean consumer of it, and the source is organized into
42
+ `src/cli/` and `src/mcp/`. Also: Node 25 support and a runtime-aware bin wrapper
43
+ for bun installs.
44
+
45
+ ### Changes
46
+
47
+ - Stable SDK API with `QMDStore` interface — search, retrieval, collection/context
48
+ management, indexing, lifecycle
49
+ - Unified `search()`: pass `query` for auto-expansion or `queries` for
50
+ pre-expanded lex/vec/hyde — replaces the old query/search/structuredSearch split
51
+ - New `getDocumentBody()`, `getDefaultCollectionNames()`, `Maintenance` class
52
+ - MCP server rewritten as a clean SDK consumer — zero internal store access
53
+ - CLI and MCP organized into `src/cli/` and `src/mcp/` subdirectories
54
+ - Runtime-aware `bin/qmd` wrapper detects bun vs node to avoid ABI mismatches.
55
+ Closes #319
56
+ - `better-sqlite3` bumped to ^12.4.5 for Node 25 support. Closes #257
57
+ - Utility exports: `extractSnippet`, `addLineNumbers`, `DEFAULT_MULTI_GET_MAX_BYTES`
58
+
59
+ ### Fixes
60
+
61
+ - Remove unused `import { resolve }` in store.ts that shadowed local export
62
+
63
+ ## [1.1.6] - 2026-03-09
64
+
65
+ QMD can now be used as a library. `import { createStore } from '@tobilu/qmd'`
66
+ gives you the full search and indexing API — hybrid query, BM25, structured
67
+ search, collection/context management — without shelling out to the CLI.
68
+
69
+ ### Changes
70
+
71
+ - **SDK / library mode**: `createStore({ dbPath, config })` returns a
72
+ `QMDStore` with `query()`, `search()`, `structuredSearch()`, `get()`,
73
+ `multiGet()`, and collection/context management methods. Supports inline
74
+ config (no files needed) or a YAML config path.
75
+ - **Package exports**: `package.json` now declares `main`, `types`, and
76
+ `exports` so bundlers and TypeScript resolve `@tobilu/qmd` correctly.
77
+
78
+ ## [1.1.5] - 2026-03-07
79
+
80
+ Ambiguous queries like "performance" now produce dramatically better results
81
+ when the caller knows what they mean. The new `intent` parameter steers all
82
+ five pipeline stages — expansion, strong-signal bypass, chunk selection,
83
+ reranking, and snippet extraction — without searching on its own. Design and
84
+ original implementation by Ilya Grigorik (@vyalamar) in #180.
85
+
86
+ ### Changes
87
+
88
+ - **Intent parameter**: optional `intent` string disambiguates queries across
89
+ the entire search pipeline. Available via CLI (`--intent` flag or `intent:`
90
+ line in query documents), MCP (`intent` field on the query tool), and
91
+ programmatic API. Adapted from PR #180 (thanks @vyalamar).
92
+ - **Query expansion**: when intent is provided, the expansion LLM prompt
93
+ includes `Query intent: {intent}`, matching the finetune training data
94
+ format for better-aligned expansions.
95
+ - **Reranking**: intent is prepended to the rerank query so Qwen3-Reranker
96
+ scores with domain context.
97
+ - **Chunk selection**: intent terms scored at 0.5× weight alongside query
98
+ terms (1.0×) when selecting the best chunk per document for reranking.
99
+ - **Snippet extraction**: intent terms scored at 0.3× weight to nudge
100
+ snippets toward intent-relevant lines without overriding query anchoring.
101
+ - **Strong-signal bypass disabled with intent**: when intent is provided, the
102
+ BM25 strong-signal shortcut is skipped — the obvious keyword match may not
103
+ be what the caller wants.
104
+ - **MCP instructions**: callers are now guided to provide `intent` on every
105
+ search call for disambiguation.
106
+ - **Query document syntax**: `intent:` recognized as a line type. At most one
107
+ per document, cannot appear alone. Grammar updated in `docs/SYNTAX.md`.
108
+
109
+ ## [1.1.2] - 2026-03-07
110
+
111
+ 13 community PRs merged. GPU initialization replaced with node-llama-cpp's
112
+ built-in `autoAttempt` — deleting ~220 lines of manual fallback code and
113
+ fixing GPU issues reported across 10+ PRs in one shot. Reranking is faster
114
+ through chunk deduplication and a parallelism cap that prevents VRAM
115
+ exhaustion.
116
+
117
+ ### Changes
118
+
119
+ - **GPU init**: use node-llama-cpp's `build: "autoAttempt"` instead of manual
120
+ GPU backend detection. Automatically tries Metal/CUDA/Vulkan and falls back
121
+ gracefully. #310 (thanks @giladgd — the node-llama-cpp author)
122
+ - **Query `--explain`**: `qmd query --explain` exposes retrieval score traces
123
+ — backend scores, per-list RRF contributions, top-rank bonus, reranker
124
+ score, and final blended score. Works in JSON and CLI output. #242
125
+ (thanks @vyalamar)
126
+ - **Collection ignore patterns**: `ignore: ["Sessions/**", "*.tmp"]` in
127
+ collection config to exclude files from indexing. #304 (thanks @sebkouba)
128
+ - **Multilingual embeddings**: `QMD_EMBED_MODEL` env var lets you swap in
129
+ models like Qwen3-Embedding for non-English collections. #273 (thanks
130
+ @daocoding)
131
+ - **Configurable expansion context**: `QMD_EXPAND_CONTEXT_SIZE` env var
132
+ (default 2048) — previously used the model's full 40960-token window,
133
+ wasting VRAM. #313 (thanks @0xble)
134
+ - **`candidateLimit` exposed**: `-C` / `--candidate-limit` flag and MCP
135
+ parameter to tune how many candidates reach the reranker. #255 (thanks
136
+ @pandysp)
137
+ - **MCP multi-session**: HTTP transport now supports multiple concurrent
138
+ client sessions, each with its own server instance. #286 (thanks @joelev)
139
+
140
+ ### Fixes
141
+
142
+ - **Reranking performance**: cap parallel rerank contexts at 4 to prevent
143
+ VRAM exhaustion on high-core machines. Deduplicate identical chunk texts
144
+ before reranking — same content from different files now shares a single
145
+ reranker call. Cache scores by content hash instead of file path.
146
+ - Deactivate stale docs when all files are removed from a collection and
147
+ `qmd update` is run. #312 (thanks @0xble)
148
+ - Handle emoji-only filenames (`🐘.md` → `1f418.md`) instead of crashing.
149
+ #308 (thanks @debugerman)
150
+ - Skip unreadable files during indexing (e.g. iCloud-evicted files returning
151
+ EAGAIN) instead of crashing. #253 (thanks @jimmynail)
152
+ - Suppress progress bar escape sequences when stderr is not a TTY. #230
153
+ (thanks @dgilperez)
154
+ - Emit format-appropriate empty output (`[]` for JSON, CSV header for CSV,
155
+ etc.) instead of plain text "No results." #228 (thanks @amsminn)
156
+ - Correct Windows sqlite-vec package name (`sqlite-vec-windows-x64`) and add
157
+ `sqlite-vec-linux-arm64`. #225 (thanks @ilepn)
158
+ - Fix claude plugin setup CLI commands in README. #311 (thanks @gi11es)
159
+
160
+ ## [1.1.1] - 2026-03-06
161
+
162
+ ### Fixes
163
+
164
+ - Reranker: truncate documents exceeding the 2048-token context window
165
+ instead of silently producing garbage scores. Long chunks (e.g. from
166
+ PDF ingestion) now get a fair ranking.
167
+ - Nix: add python3 and cctools to build dependencies. #214 (thanks
168
+ @pcasaretto)
169
+
170
+ ## [1.1.0] - 2026-02-20
171
+
172
+ QMD now speaks in **query documents** — structured multi-line queries where every line is typed (`lex:`, `vec:`, `hyde:`), combining keyword precision with semantic recall. A single plain query still works exactly as before (it's treated as an implicit `expand:` and auto-expanded by the LLM). Lex now supports quoted phrases and negation (`"C++ performance" -sports -athlete`), making intent-aware disambiguation practical. The formal query grammar is documented in `docs/SYNTAX.md`.
173
+
174
+ The npm package now uses the standard `#!/usr/bin/env node` bin convention, replacing the custom bash wrapper. This fixes native module ABI mismatches when installed via bun and works on any platform with node >= 22 on PATH.
175
+
176
+ ### Changes
177
+
178
+ - **Query document format**: multi-line queries with typed sub-queries (`lex:`, `vec:`, `hyde:`). Plain queries remain the default (`expand:` implicit, but not written inside the document). First sub-query gets 2× fusion weight — put your strongest signal first. Formal grammar in `docs/SYNTAX.md`.
179
+ - **Lex syntax**: full BM25 operator support. `"exact phrase"` for verbatim matching; `-term` and `-"phrase"` for exclusions. Essential for disambiguation when a term is overloaded across domains (e.g. `performance -sports -athlete`).
180
+ - **`expand:` shortcut**: send a single plain query (or start the document with `expand:` on its only line) to auto-expand via the local LLM. Query documents themselves are limited to `lex`, `vec`, and `hyde` lines.
181
+ - **MCP `query` tool** (renamed from `structured_search`): rewrote the tool description to fully teach AI agents the query document format, lex syntax, and combination strategy. Includes worked examples with intent-aware lex.
182
+ - **HTTP `/query` endpoint** (renamed from `/search`; `/search` kept as silent alias).
183
+ - **`collections` array filter**: filter by multiple collections in a single query (`collections: ["notes", "brain"]`). Removed the single `collection` string param — array only.
184
+ - **Collection `include`/`exclude`**: `includeByDefault: false` hides a collection from all queries unless explicitly named via `collections`. CLI: `qmd collection exclude <name>` / `qmd collection include <name>`.
185
+ - **Collection `update-cmd`**: attach a shell command that runs before every `qmd update` (e.g. `git stash && git pull --rebase --ff-only && git stash pop`). CLI: `qmd collection update-cmd <name> '<cmd>'`.
186
+ - **`qmd status` tips**: shows actionable tips when collections lack context descriptions or update commands.
187
+ - **`qmd collection` subcommands**: `show`, `update-cmd`, `include`, `exclude`. Bare `qmd collection` now prints help.
188
+ - **Packaging**: replaced custom bash wrapper with standard `#!/usr/bin/env node` shebang on `dist/qmd.js`. Fixes native module ABI mismatches when installed via bun, and works on any platform where node >= 22 is on PATH.
189
+ - **Removed MCP tools** `search`, `vector_search`, `deep_search` — all superseded by `query`.
190
+ - **Removed** `qmd context check` command.
191
+ - **CLI timing**: each LLM step (expand, embed, rerank) prints elapsed time inline (`Expanding query... (4.2s)`).
192
+
193
+ ### Fixes
194
+
195
+ - `qmd collection list` shows `[excluded]` tag for collections with `includeByDefault: false`.
196
+ - Default searches now respect `includeByDefault` — excluded collections are skipped unless explicitly named.
197
+ - Fix main module detection when installed globally via npm/bun (symlink resolution).
198
+
199
+ ## [1.0.7] - 2026-02-18
200
+
201
+ ### Changes
202
+
203
+ - LLM: add LiquidAI LFM2-1.2B as an alternative base model for query
204
+ expansion fine-tuning. LFM2's hybrid architecture (convolutions + attention)
205
+ is 2x faster at decode/prefill vs standard transformers — good fit for
206
+ on-device inference.
207
+ - CLI: support multiple `-c` flags to search across several collections at
208
+ once (e.g. `qmd search -c notes -c journals "query"`). #191 (thanks
209
+ @openclaw)
210
+
211
+ ### Fixes
212
+
213
+ - Return empty JSON array `[]` instead of no output when `--json` search
214
+ finds no results.
215
+ - Resolve relative paths passed to `--index` so they don't produce malformed
216
+ config entries.
217
+ - Respect `XDG_CONFIG_HOME` for collection config path instead of always
218
+ using `~/.config`. #190 (thanks @openclaw)
219
+ - CLI: empty-collection hint now shows the correct `collection add` command.
220
+ #200 (thanks @vincentkoc)
221
+
222
+ ## [1.0.6] - 2026-02-16
223
+
224
+ ### Changes
225
+
226
+ - CLI: `qmd status` now shows models with full HuggingFace links instead of
227
+ static names in `--help`. Model info is derived from the actual configured
228
+ URIs so it stays accurate if models change.
229
+ - Release tooling: pre-push hook handles non-interactive shells (CI, editors)
230
+ gracefully — warnings auto-proceed instead of hanging on a tty prompt.
231
+ Annotated tags now resolve correctly for CI checks.
232
+
233
+ ## [1.0.5] - 2026-02-16
234
+
235
+ The npm package now ships compiled JavaScript instead of raw TypeScript,
236
+ removing the `tsx` runtime dependency. A new `/release` skill automates the
237
+ full release workflow with changelog validation and git hook enforcement.
238
+
239
+ ### Changes
240
+
241
+ - Build: compile TypeScript to `dist/` via `tsc` so the npm package no longer
242
+ requires `tsx` at runtime. The `qmd` shell wrapper now runs `dist/qmd.js`
243
+ directly.
244
+ - Release tooling: new `/release` skill that manages the full release
245
+ lifecycle — validates changelog, installs git hooks, previews release notes,
246
+ and cuts the release. Auto-populates `[Unreleased]` from git history when
247
+ empty.
248
+ - Release tooling: `scripts/extract-changelog.sh` extracts cumulative notes
249
+ for the full minor series (e.g. 1.0.0 through 1.0.5) for GitHub releases.
250
+ Includes `[Unreleased]` content in previews.
251
+ - Release tooling: `scripts/release.sh` renames `[Unreleased]` to a versioned
252
+ heading and inserts a fresh empty `[Unreleased]` section automatically.
253
+ - Release tooling: pre-push git hook blocks `v*` tag pushes unless
254
+ `package.json` version matches the tag, a changelog entry exists, and CI
255
+ passed on GitHub.
256
+ - Publish workflow: GitHub Actions now builds TypeScript, creates a GitHub
257
+ release with cumulative notes extracted from the changelog, and publishes
258
+ to npm with provenance.
259
+
260
+ ## [1.0.0] - 2026-02-15
261
+
262
+ QMD now runs on both Node.js and Bun, with up to 2.7x faster reranking
263
+ through parallel GPU contexts. GPU auto-detection replaces the unreliable
264
+ `gpu: "auto"` with explicit CUDA/Metal/Vulkan probing.
265
+
266
+ ### Changes
267
+
268
+ - Runtime: support Node.js (>=22) alongside Bun via a cross-runtime SQLite
269
+ abstraction layer (`src/db.ts`). `bun:sqlite` on Bun, `better-sqlite3` on
270
+ Node. The `qmd` wrapper auto-detects a suitable Node.js install via PATH,
271
+ then falls back to mise, asdf, nvm, and Homebrew locations.
272
+ - Performance: parallel embedding & reranking via multiple LlamaContext
273
+ instances — up to 2.7x faster on multi-core machines.
274
+ - Performance: flash attention for ~20% less VRAM per reranking context,
275
+ enabling more parallel contexts on GPU.
276
+ - Performance: right-sized reranker context (40960 → 2048 tokens, 17x less
277
+ memory) since chunks are capped at ~900 tokens.
278
+ - Performance: adaptive parallelism — context count computed from available
279
+ VRAM (GPU) or CPU math cores rather than hardcoded.
280
+ - GPU: probe for CUDA, Metal, Vulkan explicitly at startup instead of
281
+ relying on node-llama-cpp's `gpu: "auto"`. `qmd status` shows device info.
282
+ - Tests: reorganized into flat `test/` directory with vitest for Node.js and
283
+ bun test for Bun. New `eval-bm25` and `store.helpers.unit` suites.
284
+
285
+ ### Fixes
286
+
287
+ - Prevent VRAM waste from duplicate context creation during concurrent
288
+ `embedBatch` calls — initialization lock now covers the full path.
289
+ - Collection-aware FTS filtering so scoped keyword search actually restricts
290
+ results to the requested collection.
291
+
292
+ ## [0.9.0] - 2026-02-15
293
+
294
+ First published release on npm as `@tobilu/qmd`. MCP HTTP transport with
295
+ daemon mode cuts warm query latency from ~16s to ~10s by keeping models
296
+ loaded between requests.
297
+
298
+ ### Changes
299
+
300
+ - MCP: HTTP transport with daemon lifecycle — `qmd mcp --http --daemon`
301
+ starts a background server, `qmd mcp stop` shuts it down. Models stay warm
302
+ in VRAM between queries. #149 (thanks @igrigorik)
303
+ - Search: type-routed query expansion preserves lex/vec/hyde type info and
304
+ routes to the appropriate backend. Eliminates ~4 wasted backend calls per
305
+ query (10.0 → 6.0 calls, 1278ms → 549ms). #149 (thanks @igrigorik)
306
+ - Search: unified pipeline — extracted `hybridQuery()` and
307
+ `vectorSearchQuery()` to `store.ts` so CLI and MCP share identical logic.
308
+ Fixes a class of bugs where results differed between the two. #149 (thanks
309
+ @igrigorik)
310
+ - MCP: dynamic instructions generated at startup from actual index state —
311
+ LLMs see collection names, doc counts, and content descriptions. #149
312
+ (thanks @igrigorik)
313
+ - MCP: tool renames (vsearch → vector_search, query → deep_search) with
314
+ rewritten descriptions for better tool selection. #149 (thanks @igrigorik)
315
+ - Integration: Claude Code plugin with inline status checks and MCP
316
+ integration. #99 (thanks @galligan)
317
+
318
+ ### Fixes
319
+
320
+ - BM25 score normalization — formula was inverted (`1/(1+|x|)` instead of
321
+ `|x|/(1+|x|)`), so strong matches scored *lowest*. Broke `--min-score`
322
+ filtering and made the "strong signal" short-circuit dead code. #76 (thanks
323
+ @dgilperez)
324
+ - Normalize Unicode paths to NFC for macOS compatibility. #82 (thanks
325
+ @c-stoeckl)
326
+ - Handle dense content (code) that tokenizes beyond expected chunk size.
327
+ - Proper cleanup of Metal GPU resources on process exit.
328
+ - SQLite-vec readiness verification after extension load.
329
+ - Reactivate deactivated documents on re-index instead of creating duplicates.
330
+ - Bun UTF-8 path corruption workaround for non-ASCII filenames.
331
+ - Disable following symlinks in glob.scan to avoid infinite loops.
332
+
333
+ ## [0.8.0] - 2026-01-28
334
+
335
+ Fine-tuned query expansion model trained with GRPO replaces the stock Qwen3
336
+ 0.6B. The training pipeline scores expansions on named entity preservation,
337
+ format compliance, and diversity — producing noticeably better lexical
338
+ variations and HyDE documents.
339
+
340
+ ### Changes
341
+
342
+ - LLM: deploy GRPO-trained (Group Relative Policy Optimization) query
343
+ expansion model, hosted on HuggingFace and auto-downloaded on first use.
344
+ Better preservation of proper nouns and technical terms in expansions.
345
+ - LLM: `/only:lex` mode for single-type expansions — useful when you know
346
+ which search backend will help.
347
+ - LLM: HyDE output moved to first position so vector search can start
348
+ embedding while other expansions generate.
349
+ - LLM: session lifecycle management via `withLLMSession()` pattern — ensures
350
+ cleanup even on failure, similar to database transactions.
351
+ - Integration: org-mode title extraction support. #50 (thanks @sh54)
352
+ - Integration: SQLite extension loading in Nix devshell. #48 (thanks @sh54)
353
+ - Integration: AI agent discovery via skills.sh. #64 (thanks @Algiras)
354
+
355
+ ### Fixes
356
+
357
+ - Use sequential embedding on CPU-only systems — parallel contexts caused a
358
+ race condition where contexts competed for CPU cores, making things slower.
359
+ #54 (thanks @freeman-jiang)
360
+ - Fix `collectionName` column in vector search SQL (was still using old
361
+ `collectionId` from before YAML migration). #61 (thanks @jdvmi00)
362
+ - Fix Qwen3 sampling params to prevent repetition loops — stock
363
+ temperature/top-p caused occasional infinite repeat patterns.
364
+ - Add `--index` option to CLI argument parser (was documented but not wired
365
+ up). #84 (thanks @Tritlo)
366
+ - Fix DisposedError during slow batch embedding. #41 (thanks @wuhup)
367
+
368
+ ## [0.7.0] - 2026-01-09
369
+
370
+ First community contributions. The project gained external contributors,
371
+ surfacing bugs that only appear in diverse environments — Homebrew sqlite-vec
372
+ paths, case-sensitive model filenames, and sqlite-vec JOIN incompatibilities.
373
+
374
+ ### Changes
375
+
376
+ - Indexing: native `realpathSync()` replaces `readlink -f` subprocess spawn
377
+ per file. On a 5000-file collection this eliminates 5000 shell spawns,
378
+ ~15% faster. #8 (thanks @burke)
379
+ - Indexing: single-pass tokenization — chunking algorithm tokenized each
380
+ document twice (count then split); now tokenizes once and reuses. #9
381
+ (thanks @burke)
382
+
383
+ ### Fixes
384
+
385
+ - Fix `vsearch` and `query` hanging — sqlite-vec's virtual table doesn't
386
+ support the JOIN pattern used; rewrote to subquery. #23 (thanks @mbrendan)
387
+ - Fix MCP server exiting immediately after startup — process had no active
388
+ handles keeping the event loop alive. #29 (thanks @mostlydev)
389
+ - Fix collection filter SQL to properly restrict vector search results.
390
+ - Support non-ASCII filenames in collection filter.
391
+ - Skip empty files during indexing instead of crashing on zero-length content.
392
+ - Fix case sensitivity in Qwen3 model filename resolution. #15 (thanks
393
+ @gavrix)
394
+ - Fix sqlite-vec loading on macOS with Homebrew (`BREW_PREFIX` detection).
395
+ #42 (thanks @komsit37)
396
+ - Fix Nix flake to use correct `src/qmd.ts` path. #7 (thanks @burke)
397
+ - Fix docid lookup with quotes support in get command. #36 (thanks
398
+ @JoshuaLelon)
399
+ - Fix query expansion model size in documentation. #38 (thanks @odysseus0)
400
+
401
+ ## [0.6.0] - 2025-12-28
402
+
403
+ Replaced Ollama HTTP API with node-llama-cpp for all LLM operations. Ollama
404
+ adds convenience but also a running server dependency. node-llama-cpp loads
405
+ GGUF models directly in-process — zero external dependencies. Models
406
+ auto-download from HuggingFace on first use.
407
+
408
+ ### Changes
409
+
410
+ - LLM: structured query expansion via JSON schema grammar constraints.
411
+ Model produces typed expansions — **lexical** (BM25 keywords), **vector**
412
+ (semantic rephrasings), **HyDE** (hypothetical document excerpts) — so each
413
+ routes to the right backend instead of sending everything everywhere.
414
+ - LLM: lazy model loading with 2-minute inactivity auto-unload. Keeps memory
415
+ low when idle while avoiding ~3s model load on every query.
416
+ - Search: conditional query expansion — when BM25 returns strong results, the
417
+ expensive LLM expansion is skipped entirely.
418
+ - Search: multi-chunk reranking — documents with multiple relevant chunks
419
+ scored by aggregating across all chunks rather than best single chunk.
420
+ - Search: cosine distance for vector search (was L2).
421
+ - Search: embeddinggemma nomic-style prompt formatting.
422
+ - Testing: evaluation harness with synthetic test documents and Hit@K metrics
423
+ for BM25, vector, and hybrid RRF.
424
+
425
+ ## [0.5.0] - 2025-12-13
426
+
427
+ Collections and contexts moved from SQLite tables to YAML at
428
+ `~/.config/qmd/index.yml`. SQLite was overkill for config — you can't share
429
+ it, and it's opaque. YAML is human-readable and version-controllable. The
430
+ migration was extensive (35+ commits) because every part of the system that
431
+ touched collections or contexts had to be updated.
432
+
433
+ ### Changes
434
+
435
+ - Config: YAML-based collections and contexts replace SQLite tables.
436
+ `collections` and `path_contexts` tables dropped from schema. Collections
437
+ support an optional `update:` command (e.g., `git pull`) before re-index.
438
+ - CLI: `qmd collection add/list/remove/rename` commands with `--name` and
439
+ `--mask` glob pattern support.
440
+ - CLI: `qmd ls` virtual file tree — list collections, files in a collection,
441
+ or files under a path prefix.
442
+ - CLI: `qmd context add/list/check/rm` with hierarchical context inheritance.
443
+ A query to `qmd://notes/2024/jan/` inherits context from `notes/`,
444
+ `notes/2024/`, and `notes/2024/jan/`.
445
+ - CLI: `qmd context add / "text"` for global context across all collections.
446
+ - CLI: `qmd context check` audit command to find paths without context.
447
+ - Paths: `qmd://` virtual URI scheme for portable document references.
448
+ `qmd://notes/ideas.md` works regardless of where the collection lives on
449
+ disk. Works in `get`, `multi-get`, `ls`, and context commands.
450
+ - CLI: document IDs (docid) — first 6 chars of content hash for stable
451
+ references. Shown as `#abc123` in search results, usable with `get` and
452
+ `multi-get`.
453
+ - CLI: `--line-numbers` flag for get command output.
454
+
455
+ ## [0.4.0] - 2025-12-10
456
+
457
+ MCP server for AI agent integration. Without it, agents had to shell out to
458
+ `qmd search` and parse CLI output. The monolithic `qmd.ts` (1840 lines) was
459
+ split into focused modules with the project's first test suite (215 tests).
460
+
461
+ ### Changes
462
+
463
+ - MCP: stdio server with tools for search, vector search, hybrid query,
464
+ document retrieval, and status. Runs over stdio transport for Claude
465
+ Desktop and MCP clients.
466
+ - MCP: spec-compliant with June 2025 MCP specification — removed non-spec
467
+ `mimeType`, added `isError: true` to errors, `structuredContent` for
468
+ machine-readable results, proper URI encoding.
469
+ - MCP: simplified tool naming (`qmd_search` → `search`) since MCP already
470
+ namespaces by server.
471
+ - Architecture: extract `store.ts` (1221 LOC), `llm.ts` (539 LOC),
472
+ `formatter.ts` (359 LOC), `mcp.ts` (503 LOC) from monolithic `qmd.ts`.
473
+ - Testing: 215 tests (store: 96, llm: 60, mcp: 59) with mocked Ollama for
474
+ fast, deterministic runs. Before this: zero tests.
475
+
476
+ ## [0.3.0] - 2025-12-08
477
+
478
+ Document chunking for vector search. A 5000-word document about many topics
479
+ gets a single embedding that averages everything together, matching poorly for
480
+ specific queries. Chunking produces one embedding per ~900-token section with
481
+ focused semantic signal.
482
+
483
+ ### Changes
484
+
485
+ - Search: markdown-aware chunking — prefers heading boundaries, then paragraph
486
+ breaks, then sentence boundaries. 15% overlap between chunks ensures
487
+ cross-boundary queries still match.
488
+ - Search: multi-chunk scoring bonus (+0.02 per additional chunk, capped at
489
+ +0.1 for 5+ chunks). Documents relevant in multiple sections rank higher.
490
+ - CLI: display paths show collection-relative paths and extracted titles
491
+ (from H1 headings or YAML frontmatter) instead of raw filesystem paths.
492
+ - CLI: `--all` flag returns all matches (use with `--min-score` to filter).
493
+ - CLI: byte-based progress bar with ETA for `embed` command.
494
+ - CLI: human-readable time formatting ("15m 4s" instead of "904.2s").
495
+ - CLI: documents >64KB truncated with warning during embedding.
496
+
497
+ ## [0.2.0] - 2025-12-08
498
+
499
+ ### Changes
500
+
501
+ - CLI: `--json`, `--csv`, `--files`, `--md`, `--xml` output format flags.
502
+ `--json` for programmatic access, `--files` for piping, `--md`/`--xml` for
503
+ LLM consumption, `--csv` for spreadsheets.
504
+ - CLI: `qmd status` shows index health — document count, size, embedding
505
+ coverage, time since last update.
506
+ - Search: weighted RRF — original query gets 2x weight relative to expanded
507
+ queries since the user's actual words are a more reliable signal.
508
+
509
+ ## [0.1.0] - 2025-12-07
510
+
511
+ Initial implementation. Built in a single day for searching personal markdown
512
+ notes, journals, and meeting transcripts.
513
+
514
+ ### Changes
515
+
516
+ - Search: SQLite FTS5 with BM25 ranking. Chose SQLite over Elasticsearch
517
+ because QMD is a personal tool — single binary, no server dependencies.
518
+ - Search: sqlite-vec for vector similarity. Same rationale: in-process, no
519
+ external vector database.
520
+ - Search: Reciprocal Rank Fusion to combine BM25 and vector results. RRF is
521
+ parameter-free and handles missing signals gracefully.
522
+ - LLM: Ollama for embeddings, reranking, and query expansion. Later replaced
523
+ with node-llama-cpp in 0.6.0.
524
+ - CLI: `qmd add`, `qmd embed`, `qmd search`, `qmd vsearch`, `qmd query`,
525
+ `qmd get`. ~1800 lines of TypeScript in a single `qmd.ts` file.
526
+
527
+ [Unreleased]: https://github.com/tobi/qmd/compare/v1.0.0...HEAD
528
+ [1.0.0]: https://github.com/tobi/qmd/releases/tag/v1.0.0
529
+ [0.9.0]: https://github.com/tobi/qmd/compare/v0.8.0...v0.9.0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2024-2026 Tobi Lutke
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.