v2.5.3
mudler/LocalAIv2.5.3May 29, 2026by github-actions[bot]
AI Summary
This release focuses on CLI enhancements for the qmd tool, improving line-numbered retrieval, path handling, and output formatting, while also fixing execution issues on Windows and memory handling on macOS.
Key Highlights
- qmd get now supports ':from:count' suffix for reading specific line ranges.
- Line numbers are now printed by default in qmd get and multi-get output.
- New --full-path flag replaces qmd:// URIs with actual filesystem paths.
- New --format flag provides a unified way to select output formats.
- Fix for macOS Metal backtrace dumping during process exit.
New Features
- Line-numbered retrieval with :from:count suffix support
- Default line-numbered CLI output
- Filesystem path resolution via --full-path
- Unified output formatting with --format flag
- MCP tool updates for line numbers and full paths
- Launcher improvements for Windows execution
Full Release Notes
## [2.5.3] - 2026-05-28 ### Features - `qmd get` now accepts a `:from:count` suffix on a path or docid (e.g. `qmd get "#abc123:120:40"` reads 40 lines starting at line 120). Explicit `--from`/`-l` flags still override the suffix. The MCP `get` tool accepts the same suffix. - `qmd get` and `qmd multi-get` are now **line-numbered by default** and print the document's `#docid` and `qmd://` path in the output header. Disable line numbers with `--no-line-numbers`. The MCP `get`/`multi_get` tools default `lineNumbers` to `true` to match. - `qmd multi-get` now includes the `#docid` in every output format (`--md`, `--json`, `--csv`, `--xml`, `--files`, and the default CLI view), consistent with `qmd search`. - `qmd get` and `qmd multi-get` accept `--full-path`, which replaces the `qmd://` path + `#docid` with the document's on-disk filesystem path (handy for piping into `Read`/`Edit`/an editor). Falls back to the canonical `qmd://` + docid header when the file no longer exists on disk. - `qmd search` / `qmd query` now show a clearer hit identifier: the default CLI view (and the new `**file:**` line in `--md` output) always prints the full `qmd://collection/path` URI so you can pipe it straight back into `qmd get`. - `qmd search` / `qmd query` accept `--full-path` with the same semantics as `qmd get`: the result label becomes the file's on-disk path — `./`-prefixed relative path when the file lives in a subfolder of `$PWD`, absolute realpath otherwise — and the per-result `#docid` is dropped because the path is the identifier. The leading `./` is intentional so the output is unambiguously a filesystem path. Applies to all output formats. - `qmd get` and `qmd multi-get` now also use the `./`-prefixed convention when `--full-path` renders a path under `$PWD`, matching `search`/`query`. - New `--format <kind>` flag selects the output format (`cli` | `json` | `csv` | `md` | `xml` | `files`) for `search`, `query`, and `multi-get`. The legacy boolean aliases (`--json`/`--csv`/`--md`/`--xml`/`--files`) still work but are no longer in `--help`; prefer `--format`. ### Fixes - Launcher: source-mode runner selection now prefers Node + tsx over Bun when both `package-lock.json` and `bun.lock` are present in the package root, mirroring the dist-mode "npm priority" rule. Fixes pnpm-global installs that copy the entire working tree (including `.git` and `bun.lock`) into the install dir and previously routed through Bun, causing ABI mismatches with the Node-built `better-sqlite3` / `sqlite-vec` native modules. - Darwin Metal: llama-using commands (`query`, `vsearch`, `embed`) no longer dump a multi-kB GGML/Metal backtrace at process exit even when output succeeded. The libggml-metal static `ggml_metal_device` destructor asserts `[rsets->data count] == 0` during `__cxa_finalize_ranges`, but the buffer-free path never calls the symmetric `ggml_metal_device_rsets_rm` to remove released rsets from the device collection (upstream ggml-org/llama.cpp#22593, one-line fix open as PR #22595). The assertion only fires when `process.exit()` skips Node's `beforeExit` hook, which is what node-llama-cpp uses to auto-dispose Metal contexts. Primary fix: `finishSuccessfulCliCommand` now sets `process.exitCode = 0` and returns instead of calling `process.exit(0)`, so `beforeExit` fires and the native binding cleans up before libc's static destructor runs. Defense-in-depth: the launcher (`bin/qmd`) and the npm test driver (`scripts/test-all.mjs` + the `test:bun` / `test:unit` package.json scripts) also set `GGML_METAL_NO_RESIDENCY=1` on darwin before spawning node/bun, covering error paths and tests that still terminate via `process.exit()`. The env var must be set before node/bun start — libggml-metal reads it via libc `getenv` at module-load time, and Bun does not propagate `process.env` mutations to libc `setenv` — so it lives in the launcher rather than in test-preload. Residency sets give no measurable speedup for QMD's short-lived CLI workflow (benchmarked on M3 Pro). Opt back in with `QMD_METAL_KEEP_RESIDENCY=1` for long-lived qmd processes (e.g. the MCP daemon may benefit on hot reload) or to triage the upstream fix. `qmd doctor` reports the mitigation state. Minimal reproduction: `scripts/repro-metal-rsets-crash.mjs`. ### Docs - qmd skill: emphasize reading line ranges with `get`'s built-in `:from:count` suffix / `--from`/`-l` flags instead of piping through `sed`/`head`/`tail`; cite the docid and line numbers now present in retrieval output; and author structured `intent:`/`lex:`/`vec:`/`hyde:` queries yourself rather than relying on built-in query expansion. ## [2.5.2] - 2026-05-22 ### Fixes - Launcher: Rewrite `bin/qmd` as a Node-based shebang polyglot to fix global npm installation execution failures on Windows (#668 / #452), while supporting seamless fallback to Bun in Node-less environments. ## [2.5.1] - 2026-05-20 ### Changes - Release: publish from GitHub Actions via npm Trusted Publishing/OIDC instead of a long-lived `NPM_TOKEN` secret. ## [2.5.0] - 2026-05-19 ### Changes - Dependencies: update core SQLite/config/chunking packages (`better-sqlite3`, `yaml`, `web-tree-sitter`, `tree-sitter-go`, and `tree-sitter-python`) while keeping incompatible `zod`, `tsx`, and `vitest` majors pinned. - Agent skills: add `qmd skills list|get|path` to serve version-matched runtime skill instructions from the installed CLI, and make `qmd skill install` write a stable discovery stub so installed agent skills do not go stale after QMD upgrades. - CLI: add `qmd doctor` for index/runtime diagnostics, including SQLite/sqlite-vec versions, embedding fingerprint freshness, mixed-fingerprint detection, safe legacy fingerprint adoption, and content-hash sampling. ### Fixes - Launcher: prefer runnable TypeScript source in git checkouts even when ignored `dist/` artifacts exist, while packaged installs continue to run `dist/`. - GPU: keep node-llama-cpp's documented `gpu: "auto"` initialization as the primary path, then perform no-build packaged CUDA/Vulkan/Metal probes only if auto falls back to CPU. - CLI: move GPU/CPU runtime diagnostics out of `qmd status`; use `qmd doctor` for device probing and related environment guidance. - CLI: point unexpected command/setup failures toward `qmd doctor` so diagnostics are the default next step when QMD behaves incorrectly. - Doctor: explicitly warn when `content_vectors` contains multiple non-empty embedding fingerprint names, with the per-fingerprint document/chunk breakdown. - Embed: make the TTY progress line label byte-based input progress explicitly, show embedded chunks as a count, and shorten the displayed model name. - Embed: retain per-chunk failure details, retry failed chunks after later successful embeds and again when no other chunks remain, clear recovered errors, and cap retries to avoid endless loops. - Tests: expand the container smoke harness to cover npm-global, npx-style, and Bun-global install scenarios, always checking auto and `QMD_FORCE_CPU=1` doctor modes, with opt-in tiny `qmd embed` and GPU probe runs for supported container runtimes. - Embedding: fingerprint vector metadata using the active embedding model and formatting/chunking parameters so stale vectors are treated as pending after search semantics change. Legacy `content_vectors` columns are migrated lazily on first vector-health/write use to preserve fast QMD startup. - Skill: expand the packaged QMD skill with retrieval-first workflows, structured query examples, wiki/source collection guidance, and safe fallbacks when model-backed search is unavailable. - Tests: make `bun run test` execute the local unit suite under both Node/Vitest and Bun (`test:node` + `test:bun`) so runtime-specific regressions are caught before CI. - Model config: centralize embedding/rerank/generation model resolution so `qmd embed`, `status`, `query`, `vsearch`, `pull`, SDK vector search, and `bench` use the same active `.qmd/index.yaml` model hints and environment fallbacks. - GPU/status: `qmd status` now uses the same embedding model identity as `qmd embed` when computing pending embeddings, so URI-backed embeddings are not incorrectly reported as pending under the legacy `embeddinggemma` alias. - GPU status: `qmd status` now always shows GPU mode/configuration without unsafe native probing, and CPU-fallback warnings point to `QMD_STATUS_DEVICE_PROBE=1 qmd status` for an actual backend probe. The no-GPU warning is emitted once per process instead of once per LLM instance during benchmarks. - GPU: add `QMD_FORCE_CPU=1` / `--no-gpu` to bypass CUDA/Vulkan/Metal probing entirely, and route native llama.cpp stdout noise to stderr so JSON output stays parseable during search/query commands. - Snippet line numbers: `qmd_query` (MCP), HTTP `/query`, and `qmd query` (CLI JSON output and snippet headers) now return absolute source-file line numbers instead of chunk-local ones, so the `line` field can be passed back to `qmd_get` as `fromLine` without a separate lookup. Snippet selection remains scoped to the best matching chunk (preserves #149). - CLI: `qmd query --full` now emits the full document body in all output formats (json, csv, md, xml), restoring the documented behavior of the flag. Previously it returned only the best matching chunk (~3.6KB max per result). Output payload for `--full` queries is now proportional to total document size. - macOS Metal: `qmd query --json` now flushes successful JSON output and uses a safe immediate-exit path on Darwin to avoid ggml Metal finalizer aborts; other commands still dispose LLM contexts/models before the llama runtime. #368 - Embedding: require complete chunk coverage before treating a document as embedded, remove partial vectors when chunk/session failures leave a document incomplete, and keep `qmd status` pending counts honest after interrupted long embed runs. #637 #378 - Embedding: `qmd embed -c <collection>` now scopes pending-doc selection to the requested collection instead of embedding global pending work. Scoped `--force` clears only collection-owned vectors, preserves shared hashes referenced by sibling collections, and drops `vectors_vec` only when the scoped clear empties all vectors. - Hybrid search: weight RRF lists by query type so original FTS and original vector evidence get the intended 2x boost, instead of accidentally boosting the first lexical expansion. #591 - MCP: seed llama.cpp/GGML quiet env vars before launching `qmd mcp` so native logs cannot pollute stdio JSON-RPC framing. #593 - CLI: remove CommonJS `require()` calls from ESM index path normalization so `qmd --index <path>` no longer crashes with `ERR_AMBIGUOUS_MODULE_SYNTAX` on Node 22+. #634 - Windows CUDA: serialize llama.cpp embedding/reranking contexts by default to avoid intermittent `ggml-cuda.cu:98` crashes in `qmd query`; set `QMD_EMBED_PARALLELISM` to opt back into parallel contexts if your driver is stable. #519 - MCP: make `qmd mcp --index <name>` use the selected index for both foreground and daemon HTTP servers instead of falling back to the default store. #343 - Embedding: respect `QMD_EMBED_MODEL` consistently for vector indexing and vector-backed search, with default-model fallback when unset. - Config: use one home-directory resolver for YAML config and the default SQLite cache path, avoiding Windows CLI/MCP split-brain when `HOME` is unset. - GPU: respect explicit `QMD_LLAMA_GPU=metal|vulkan|cuda` backend overrides instead of always using auto GPU selection. #529 - Fix: preserve original filename case in `handelize()`. The previous `.toLowerCase()` call made indexed paths unreachable on case-sensitive filesystems (Linux). `qmd update` automatically migrates legacy lowercase paths without re-embedding. - CLI: make `qmd status` skip native `node-llama-cpp` device probing by default so status stays safe on machines with broken or unsupported GPU drivers. Set `QMD_STATUS_DEVICE_PROBE=1` to opt in. - CLI: lazy-load `node-llama-cpp` so lightweight commands such as `qmd status` do not import native ML dependencies or trigger llama.cpp builds on ARM/no-GPU machines. #491 - Store: keep content rows referenced by inactive documents during orphan cleanup so `qmd update` preserves soft-deleted tombstones for removed files. #585 - Packaging: install AST grammar WASM packages as required dependencies so Bun global installs include TypeScript/TSX/JavaScript grammars, and add a `smoke:package-grammars` verification command. #595 - Launcher: add wrapper smoke coverage for scoped package, npm/npx, Homebrew/Linuxbrew, Bun global symlink layouts, and `$BUN_INSTALL` false-positive runtime selection regressions. #351 #353 #354 #356 #358 #359