Update dependency @tobilu/qmd to v2.8.3 - #38
Open
renovate[bot] wants to merge 1 commit into
Open
Conversation
renovate
Bot
force-pushed
the
renovate/tobilu-qmd-2.x-lockfile
branch
from
August 26, 2026 21:29
b94f000 to
68152cd
Compare
renovate
Bot
force-pushed
the
renovate/tobilu-qmd-2.x-lockfile
branch
from
August 31, 2026 17:47
68152cd to
e111914
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
This PR contains the following updates:
2.5.3→2.8.3Release Notes
tobi/qmd (@tobilu/qmd)
v2.8.3Compare Source
Security
qmd updateno longer runs a project-local.qmd/index.yml'supdate:commands without approval (#886). That file arrives with a
git cloneand isadopted automatically for any command run inside the tree, so cloning a
repository and running
qmd updateexecuted shell commands chosen by whoeverwrote it. On a terminal QMD now lists the commands and asks; with nobody to
ask it skips them and keeps indexing. Approvals are recorded per config file
and per command set in
<config dir>/trusted.json, so editing a command — ora
git pullthat rewrites one — asks again. Newqmd trust,qmd trust listandqmd trust revokemanage approvals, andQMD_TRUST_UPDATE_HOOKS=1opts unattended runs back in. Commands in your own~/.config/qmd/*.yml, including anythingqmd collection update-cmdwrites,are unaffected.
The same project-local trust gate now covers collection
pathvalues thatresolve outside the project and non-default
models.embed/models.rerank/
models.generateURIs (#889). In-project paths still index unattended;out-of-project directories are skipped until
qmd trust, and custom modelURIs are not loaded or downloaded.
QMD_TRUST_LOCAL_CONFIG=1opts unattendedruns back in (and
QMD_TRUST_UPDATE_HOOKS=1still does).qmd collection addrecords trust as it writes, the same wayupdate-cmddoes.Indexing no longer follows file symlinks or glob
..// absolute patternsout of the collection directory.
fast-globalready skipped symlinkeddirectories, but a file symlink (or a mask like
../**/*.md) still resolvedvia
realpathand ingested the target.qmd://filesystem resolution usesthe same containment check, so
qmd://collection/../../../etc/passwdnolonger produces a path outside the collection.
qmd mcp --httpnow validates theOriginandHostheaders on everyrequest and answers
403when they name anything but a loopback address(#881). Binding to localhost is no defence against the user's own browser:
a page can re-point its hostname at
127.0.0.1(DNS rebinding) and readthe indexed corpus through
POST /queryorPOST /mcp. Requests with noOrigin(curl, MCP clients, editors) are unaffected. Extend the allowlistswith
QMD_ALLOWED_ORIGINS/QMD_ALLOWED_HOSTS, or setQMD_ALLOWED_ORIGINS=*behind your own authenticating proxy. A wildcardbind (
--host 0.0.0.0) skips the host check and warns at startup.Changed
Dependencies:
node-llama-cpp3.18.1 → 3.20.0 (llama.cpp b8390 → b10361, 2026-08-11). Also safe patch/minors:picomatch4.0.4 → 4.0.5,web-tree-sitter0.26.8 → 0.26.12,tsx4.21.0 → 4.23.12,vitest3.2.4 → 3.2.7. No zod/vitest major;@modelcontextprotocol/serverstays 2.0.0 (no 2.x patch).flake.nixFOD hashes are not updated here.generateand query expansion now awaitLlamaContextSequence.dispose()before disposing the parent context. node-llama-cpp 3.20 made sequence dispose async; the library's context-onDispose path does not wait.MCP server now speaks protocol revision 2026-07-28 via the official
TypeScript SDK 2.x (
@modelcontextprotocol/server). HTTP is sessionless(no
Mcp-Session-Id, no initialize handshake, no idle-session TTL / #816reaper). Clients send version and capabilities in
_meta;server/discoveris implemented; Streamable HTTP POST requires
Mcp-Method/Mcp-Name(mismatch →
-32020);tools/listis deterministic and carriesttlMs/cacheScope. 2025-era stdio clients still work (serveStdiodual-speak);2025-era HTTP
initializeis answered per-request without minting asession. Existing tools (
query/get/multi_get/status), stdioEOF shutdown, and named-index daemon PIDs are unchanged. No release.
qmd pull(and implicit model downloads inembed/query) no longer printnode-llama-cpp's download progress bar. The bar redraws every few kilobytes
and flooded agent transcripts with thousands of tokens (#776). Pass
qmd pull --progressto show it on an interactive terminal.--full-pathno longer degrades silently when a result cannot be resolved ondisk (#785). A fallback there means the file moved or was deleted since the
last index, so
search,query,getandmulti-getnow print a notice tostderr naming how many results fell back and suggesting
qmd update; stdoutstays machine-readable.
search/querynow decide per result whether to show the docid under--full-path, matchingmulti-getandget: a result that resolved showsits on-disk path and no docid, one that did not keeps its
qmd://URI andits docid, so it is still addressable. Previously the docid was dropped for
every row whenever the flag was set, leaving unresolved rows with neither a
usable path nor an identifier.
search --format csvalways emits thedocidcolumn, empty for rows thatresolved to an on-disk path. Under
--full-paththe header previouslydropped the column entirely — which also disagreed with the empty-result
header, always printed with
docid. Column positions are now stable acrossruns and formats.
Fixed
Concurrent first-open of a cold index no longer fails with
table documents_fts already existson Bun/macOS. FTS5CREATE VIRTUAL TABLE IF NOT EXISTSis not atomic across WALconnections: two processes can both see a missing table on their
schema snapshot and the loser throws. Table create and legacy-schema
repair now use the same
BEGIN IMMEDIATE+ double-check as the FTSsync triggers, and treat a concurrent "already exists" as success
when the table is present.
Nix flake
qmd-node-modulesFOD hashes updated for x86_64-linux andaarch64-darwin after the MCP SDK 2.0 bump.
nix build/ Nix GHA wasfailing with a fixed-output hash mismatch.
CJK FTS rebuild no longer skips leftover
fts5(name, body, content='documents')tables when
fts_cjk_normalized_versionis already stamped, and schemarepair now checks live FTS columns (
PRAGMA table_info) as well assqlite_master.sql. The MCP HTTP test helper still seeds that legacytable;
startMcpHttpServer/createStoreon it must not throwno such column: T.name(#792 regression).qmd collection add --globis no longer silently ignored. parseArgs ranwith
strict: false, so OpenClaw's--glob memory.md(and any other--glob) fell through, the default**/*.mdwas used, and a secondcollection on the same path collided as a duplicate instead of indexing
the requested mask (#536).
--globis now an alias for--mask.The
bin/qmdtrampoline now execsprocess.execPathinstead ofre-resolving
nodefrom PATH. Native addons (better-sqlite3) arecompiled for the Node that installed qmd; a version manager (nvm, fnm,
mise) selecting a different major in the working directory used to spawn
that other binary and fail with
NODE_MODULE_VERSION/ERR_DLOPEN_FAILED(#577 leftover; #319).
bun bin/qmdstill resolvesnodefrom PATH soNode-ABI addons are not loaded into bun.
qmd update/qmd collection addno longer swallow unreadable filessilently (#460).
readFileSyncfailures (ETIMEDOUT on APFS compressedfiles, EAGAIN, EACCES, …) still skip the file so the rest of the collection
indexes, but the CLI now warns with the path and error code and reports
the skip count. The SDK
update()result includesskipped.The architecture diagram no longer draws Vec expansions into BM25 search
(#680).
lexexpansions are FTS-only;vecandhydeexpansions arevector-only. The original query still goes to both backends.
qmd benchno longer runs to a wall of 0.00 when the fixture collection ismissing or empty (#716). It errors up front with the same "Collection not
found" / index hint as
qmd search -c, and if every backend still scoreszero it warns on stderr to check
qmd ls.qmd cleanupnow reclaims the content and FTS space left behind after awrong-directory
qmd update. Deactivating files (the next update in theright directory) only tombstoned the
documentsrows; cleanup deleted thoserows and vacuumed, but never dropped the unreferenced
contenthashes andnever ran FTS5
optimize, sodocuments_fts_datakept the old bodies(#550). Cleanup now deletes inactive docs, then orphaned content, then
compact FTS, then vacuum.
--dry-runreports the content hashes too.Concurrent
querycalls withrerank: trueon a cold MCP server no longerrace
ensureRerankContexts(). Embed already serialized context creation;rerank did not, so two overlapping first queries both saw an empty pool,
both created ranking contexts, and the inactivity timer disposed the loser
(
Object is disposed, #682). Callers now await the in-flight create.Embedding-context pool size no longer assumes every GGUF costs 150 MB of
VRAM (the nomic-embed figure). Larger models such as Qwen3-Embedding-0.6B
are ~1190 MB per 2048-token context; opening 8 of those exhausted an 8 GB
card so
qmd queryfailed withFailed to create any rerank contexteventhough the reranker itself was fine. The pool is now sized from the weight
file, and 1 GB is reserved for the reranker (#799). Default
embeddinggemma/nomic throughput is unchanged.
QMD_EMBED_PARALLELISMstilloverrides.
Multi-collection
-c A -c B(and SDK/MCPcollections: [A, B]) no longersearches globally then post-filters. A large unrelated collection could fill
the FTS/ANN top-k so the requested collections vanished, yielding false-empty
results even though each collection matched on its own.
searchFTS/searchVecnow search each requested collection, then merge by score(#775). Single-collection exact-scan (#791, #803) is unchanged.
Query expansion no longer consumes caller
intent, and a cached expansionwhose sub-queries all miss is dropped instead of replaying forever (#818).
Intent still steers reranking and snippet/chunk selection; it just no longer
enters the expansion prompt or cache key, where the model copied meta-language
("so I can compare spend settings") into lex/vec terms that matched nothing.
Files whose names differ only in the characters the legacy slug collapsed to
-(spaces, underscores) no longer evict each other from the index (#717).The handalized-path migration now skips any row whose path is still owned by
a file in the current scan, so it only adopts genuinely stale pre-2.6 rows.
qmd getandqmd ls <prefix>also match_and%in paths literallyinstead of as SQL
LIKEwildcards, soqmd get 2026_06_16.mdno longerreturns a sibling
2026-06-16.md.CLI
multi-getand SDK/MCPmulti_getnow share one comma-list resolver.Collection-prefixed paths (
qmd/docs/SYNTAX.md) work in both transports,unanchored
LIKE '%name'no longer silently fetches a different documentfor a filename fragment (
NTAX.md≠SYNTAX.md), and ambiguous namesacross collections error with the candidate list instead of
LIMIT 1(#759).The Nix flake wrapper now seeds the same pre-import env as
bin/qmd.Nix installs exec
bun src/cli/qmd.tsdirectly, so they previously skippedthe launcher:
qmd mcpcould leak llama/ggml native logs onto JSON-RPCstdio, and Darwin CLI exits dumped a ggml Metal residency-set stack trace
after an otherwise successful query. The wrapper now quiets those logs for
mcpand setsGGML_METAL_NO_RESIDENCY=1on Darwin unlessQMD_METAL_KEEP_RESIDENCY=1(#723).Rerank context creation no longer swallows the real failure. A VRAM OOM or
corrupt model previously produced only
Reranker unavailable — skipping reranking(and a dead identical retry whose comment claimed it disabledflash attention, which ranking contexts never supported). The warning now
includes the underlying message so the two cases are distinguishable (#782).
The Nix flake package now ships
skills/next tosrc/in$out/lib/qmd/.findPackageRoot()walks up from the wrappedsrc/cli/qmd.tslooking for asibling
skills/directory; without it,qmd skill showandqmd skills listalways failed with "QMD skill not found" on Nix-installed binaries (#722).
/releasestep 1 no longer points at a missing script.skills/release/scripts/release-context.shnow exists: it silently installs git hooks and prints version info, working-tree
status, commits and files since the last tag,
[Unreleased], and the previouschangelog entry. The skill's process list also drops the duplicate step 7 and
checks dependency updates before cutting the release (#796).
store.searchVec()(and SDKsearchVector()) now embed the query with thestore's pinned embed model instead of the global
QMD_EMBED_MODEL. A storecreated with a non-default
models.embedpreviously failed withDimension mismatch ... Expected N ... received Mand loaded the wrong(often much larger) model at query time. Hybrid/precomputed/session search
paths were unaffected and stay unchanged (#690).
qmd collection add --mask "a.md,*.txt"now indexes the union of eachpattern. The comma-separated form was documented and commonly guessed, but
the joined string was passed to fast-glob as one literal glob, so it
matched zero files with no error. Brace form
{a.md,*.txt}is unchanged.The same split applies on
qmd updatefor stored comma-list masks (#557).NixOS / immutable-root installs no longer crash
qmd embedwith EACCESwhen node-llama-cpp tries to compile llama.cpp into a read-only
node_modules. The flake wrapper puts Nix's glibc and libstdc++ onLD_LIBRARY_PATHso prebuilt binaries candlopenthem, andgetLlama()usesbuild: "never"when the llama directory is notwritable (#574).
CJK FTS rebuild no longer raises "database is busy" when flushing insert
batches. The streaming
.iterate()cursor stayed open acrossBEGINon the same connection; the scan now uses keyset-paginatedLIMITbatches so each SELECT finalizes before the insert transactionstarts (#797).
Quoted FTS phrases containing dotted tokens (e.g.
"1.0.21") now match theindexed document. The porter unicode61 tokenizer stores dotted strings as
adjacent parts, but phrase sanitization stripped the dots into a single
token (
1021) that could never hit. Dotted tokens inside quotes are splitinto adjacent phrase terms, matching the bare-term rewrite from #563 (#757).
scripts/build.mjsno longer passesshell: truetospawnSyncon Windows.With the default Node install path (
C:\Program Files\nodejs\node.exe),cmd.exesplit the unquotedprocess.execPathat the space, thetscspawn failed, and
preparecould still report success with nodist/—leaving
bin/qmdat "not built". The helper always receives a real binarypath plus an args array, so no shell is needed. A spawn error now prints
the missing binary path instead of failing silently. (#681)
Case-sensitive collections no longer collapse distinct document identities that
differ only by path casing. The implicit
COLLATE NOCASElegacy migration wasunsafe for filesystems that contain both
README.mdandreadme.md; case-onlylegacy migrations must now be explicit and operator-reviewed (#801).
cleanupOrphanedVectorsnow runs its orphan count and both DELETEs in asingle immediate transaction. An interruption between the two DELETEs
(crash,
SQLITE_BUSY) could desyncvectors_vecfromcontent_vectors,leaving stale metadata rows that make a later reactivation of the same
content hash look already-embedded — so
qmd embedskips it and thedocument becomes silently unsearchable by vector, with no orphan left to
clean up (#766).
qmd embedno longer splits a UTF-16 surrogate pair (emoji, etc.) across achunk boundary. A chunk ending or starting mid-pair produced an unpaired
surrogate in the chunk text, which some remote embedding APIs reject as
invalid JSON — permanently failing that chunk on every retry, since the
boundary calculation is deterministic. This covers both the character-based
chunker and
chunkDocumentByTokens's recursive re-splitting forastral-plane-dense content, which could previously drive the char budget
low enough to reproduce the same split (#777).
insertContextlooks upstore_collectionsby name. #754 retargeted thequery from the dropped
collectionstable but leftWHERE id = ?, andstore_collectionshasname TEXT PRIMARY KEYwith noidcolumn — thecall threw
no such column: id. MatchesdeleteContext/updateStoreContext(#853).qmd collection addwith no path argument now errors with usage instead ofsilently indexing the current working directory (#684). Pass
.to indexCWD, matching the documented examples.
qmd statusreports orphaned embedding chunks,qmd updatehints when theyexceed 10% of vectors, and
qmd cleanup --dry-runpreviews what would beremoved. Incremental update still does not auto-prune vectors (a transient
empty mount would otherwise force a full re-embed) (#768).
qmd --index <name> mcp --http --daemonnow scopes PID/log files per index(
mcp-<name>.pid) and passes the resolved database path to the child, so anamed-index daemon no longer collides with the default
mcp.pidor opensthe default store (#772).
Opening a store no longer throws
SQLiteError: no such column: T.namewhendocuments_ftsis still the legacyfts5(name, body, content='documents')schema.
CREATE VIRTUAL TABLE IF NOT EXISTSleft that table in place, andthe CJK FTS rebuild's
DELETE FROM documents_ftscompiled againstdocuments.name, which does not exist (#792).Rerank cache keys now include the resolved
models.rerankURI, so swappingthe configured reranker no longer serves the previous model's cached scores
(#764).
vsearch -c <collection>no longer returns empty results for smallcollections crowded out of the global ANN candidate pool.
searchVecnowexact-scans the collection's vectors with
vec_distance_cosinewhen theset is within 20k rows (ANN + post-filter cannot see collections that never
enter global top-k, and sqlite-vec caps
kat 4096 so a larger multiplieralone is not enough). Larger collections still use capped ANN over-fetch
(#791, #803).
multi-get --format filesnow emits the docid as its own CSV field(
#docid,path,...) instead of prepending it into the path field with aspace (
#docid path,...), matchingsearch --format filesand keepingnaive comma-splitting usable (#760).
qmd embednow takes an exclusive process lock (.qmd-embed.locknext tothe index DB) so concurrent invocations no longer race on
vectors_vecand fail with
UNIQUE constraint failed: vectors_vec.hash_seq. A secondembed exits early with
Another embed process is already running. Skipping.Stale locks from crashed processes are recovered via PID identity checks
(#825).
windows prepare fix #778 keeps dist build #824
qmd mcp(stdio) now shuts down gracefully when stdin reaches EOF insteadof orphaning to PID 1 when the parent MCP client dies (#751): the server
closes its transport, gives in-flight request handlers a bounded window to
settle, closes the store (which disposes its llama.cpp instance), and lets
the process drain via
process.exitCode(no forcedprocess.exit(), whichhas caused exit-time native crashes before).
qmd --versionno longer reports an unrelated repository's commit (#787).The commit was discovered at runtime with
git -C <installDir> rev-parse,and
git -Cwalks up, so any install nested inside another checkoutreported that checkout's HEAD — a global npm install under a git-managed
prefix such as Homebrew's
/opt/homebrewclaimed Homebrew's commit asqmd's. Identical tarballs reported different "commits" depending only on
where they were installed, which is why one issue can collect three distinct
hashes for the same published build.
scripts/build.mjsnow stamps thecommit it built from into
dist/cli/build-info.json(suffixed-dirtywhenbuilt from a modified tree), and the runtime prefers that. Source checkouts
still resolve their own HEAD, but only after confirming the enclosing
repository is qmd's; anything else reports no commit rather than a
misleading one. The lookup also no longer interpolates the install path into
a shell string, so a path containing a space stops silently dropping the
commit, and
--versionfrom a build runs no subprocess at all.qmd doctorno longer false-positives.etagHTTP sidecars (written byqmd pullnext to each download) as invalid GGUF models. The model-cachecheck now only inspects real
.gguffiles, so a sidecar that happens tosort before the blob no longer poisons the report. #812
qmd mcp stopandqmd mcp --http --daemonnow verify that a pidfile PID still belongs to a qmd process before signalling it or refusing to start. Recycled PIDs (common after reboot) are treated as stale: the pidfile is unlinked instead of SIGTERM'ing an unrelated process or blocking daemon start with a false "Already running" error (#806).qmd collection addnow rejects missing paths and regular files beforecreating collection configuration or index state. The error reports both the
received and resolved path so malformed shell arguments can be corrected.
Claude Code plugin: scope the plugin
sourceto./skillsso installscopy just the skills (~50 KB) instead of the entire repository. Previously a
canonical install materialized ~230 MB / 9,000+ items into
~/.claude/plugins/cache/— including a full npm dependency installtriggered by the repo-root
package.json. Both skills (qmdandrelease)still ship, unchanged. (#790)
Claude Code plugin: releases now bump the plugin version in
.claude-plugin/marketplace.jsonin lockstep withpackage.json. Theplugin cache is keyed on this version, and it had been stuck at
0.1.0since February — so installed plugins never received skill updates
(users who installed in February are still being served that snapshot
today, despite the qmd skill nearly tripling in size since). Also bumps
the plugin to
2.6.3as a one-time catch-up so existing installs pickup the current skill on their next
claude plugin update. (#789)Changed
--full-pathno longer degrades silently when a result cannot be resolved ondisk (#785). A fallback there means the file moved or was deleted since the
last index, so
search,query,getandmulti-getnow print a notice tostderr naming how many results fell back and suggesting
qmd update; stdoutstays machine-readable.
search/querynow decide per result whether to show the docid under--full-path, matchingmulti-getandget: a result that resolved showsits on-disk path and no docid, one that did not keeps its
qmd://URI andits docid, so it is still addressable. Previously the docid was dropped for
every row whenever the flag was set, leaving unresolved rows with neither a
usable path nor an identifier.
search --format csvalways emits thedocidcolumn, empty for rows thatresolved to an on-disk path. Under
--full-paththe header previouslydropped the column entirely — which also disagreed with the empty-result
header, always printed with
docid. Column positions are now stable acrossruns and formats.
Configuration
📅 Schedule: (UTC)
🚦 Automerge: Enabled.
♻ Rebasing: Whenever PR is behind base branch, or you tick the rebase/retry checkbox.
🔕 Ignore: Close this PR and you won't be reminded about this update again.
This PR was generated by Mend Renovate. View the repository job log.