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 +529 -0
- package/LICENSE +21 -0
- package/README.md +917 -0
- package/bin/qmd +32 -0
- package/dist/ast.d.ts +64 -0
- package/dist/ast.js +324 -0
- package/dist/cli/formatter.d.ts +120 -0
- package/dist/cli/formatter.js +350 -0
- package/dist/cli/qmd.d.ts +1 -0
- package/dist/cli/qmd.js +2820 -0
- package/dist/collections.d.ts +146 -0
- package/dist/collections.js +385 -0
- package/dist/db.d.ts +41 -0
- package/dist/db.js +75 -0
- package/dist/embedded-skills.d.ts +6 -0
- package/dist/embedded-skills.js +14 -0
- package/dist/index.d.ts +226 -0
- package/dist/index.js +234 -0
- package/dist/llm.d.ts +406 -0
- package/dist/llm.js +1174 -0
- package/dist/maintenance.d.ts +23 -0
- package/dist/maintenance.js +37 -0
- package/dist/mcp/server.d.ts +21 -0
- package/dist/mcp/server.js +653 -0
- package/dist/store.d.ts +993 -0
- package/dist/store.js +3806 -0
- package/package.json +101 -0
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.
|