Skip to content

Commit ddbd6bd

Browse files
authored
Merge pull request tobi#656 from tobi/fix/gpu-status-warning
Fix GPU status guidance and benchmark warnings
2 parents cdf3bc0 + ad8a371 commit ddbd6bd

12 files changed

Lines changed: 399 additions & 148 deletions

File tree

CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,11 @@
88

99
### Fixes
1010

11+
- 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.
12+
- 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.
13+
- 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.
14+
- 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.
15+
- 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.
1116
- 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.
1217
- Snippet line numbers: `qmd_query` (MCP), HTTP `/query`, and `qmd query`
1318
(CLI JSON output and snippet headers) now return absolute source-file

package.json

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,10 @@
2525
"scripts": {
2626
"prepare": "[ -d .git ] && ./scripts/install-hooks.sh || true",
2727
"build": "tsc -p tsconfig.build.json && printf '#!/usr/bin/env node\n' | cat - dist/cli/qmd.js > dist/cli/qmd.tmp && mv dist/cli/qmd.tmp dist/cli/qmd.js && chmod +x dist/cli/qmd.js",
28-
"test": "vitest run --reporter=verbose test/",
28+
"test": "bun run test:unit",
29+
"test:node": "node ./node_modules/vitest/vitest.mjs run --reporter=verbose",
30+
"test:bun": "bun test --preload ./src/test-preload.ts",
31+
"test:unit": "bun run test:node -- test/ && bun run test:bun -- test/",
2932
"qmd": "tsx src/cli/qmd.ts",
3033
"index": "tsx src/cli/qmd.ts index",
3134
"vector": "tsx src/cli/qmd.ts vector",

skills/qmd/SKILL.md

Lines changed: 136 additions & 88 deletions
Original file line numberDiff line numberDiff line change
@@ -1,138 +1,161 @@
11
---
22
name: qmd
3-
description: Search markdown knowledge bases, notes, and documentation using QMD. Use when users ask to search notes, find documents, or look up information.
3+
description: Search local markdown knowledge bases, notes, docs, and wikis with QMD. Use when users ask to find notes, retrieve documents, inspect a wiki, answer from indexed markdown, or set up QMD access.
44
license: MIT
55
compatibility: Requires qmd CLI or MCP server. Install via `npm install -g @tobilu/qmd`.
66
metadata:
77
author: tobi
8-
version: "2.0.0"
8+
version: "2.1.0"
99
allowed-tools: Bash(qmd:*), mcp__qmd__*
1010
---
1111

12-
# QMD - Quick Markdown Search
12+
# QMD - Query Markdown Documents
1313

14-
Local search engine for markdown content.
14+
QMD is a local search and retrieval engine for markdown collections: notes, docs,
15+
wikis, transcripts, and project knowledge bases. Use it before generic web search
16+
when the user is asking about something that may already live in their indexed
17+
local markdown.
1518

16-
## Status
19+
## Status Check
1720

18-
!`qmd status 2>/dev/null || echo "Not installed: npm install -g @tobilu/qmd"`
21+
Start by checking what QMD can see:
1922

20-
## MCP: `query`
23+
```bash
24+
qmd collection list
25+
qmd ls
26+
```
2127

22-
```json
23-
{
24-
"searches": [
25-
{ "type": "lex", "query": "CAP theorem consistency" },
26-
{ "type": "vec", "query": "tradeoff between consistency and availability" }
27-
],
28-
"collections": ["docs"],
29-
"limit": 10
30-
}
28+
For health details:
29+
30+
```bash
31+
qmd status
3132
```
3233

33-
### Query Types
34+
If QMD is missing:
3435

35-
| Type | Method | Input |
36-
|------|--------|-------|
37-
| `lex` | BM25 | Keywords — exact terms, names, code |
38-
| `vec` | Vector | Question — natural language |
39-
| `hyde` | Vector | Answer — hypothetical result (50-100 words) |
36+
```bash
37+
npm install -g @tobilu/qmd
38+
```
4039

41-
### Writing Good Queries
40+
## Retrieval Workflow
4241

43-
**lex (keyword)**
44-
- 2-5 terms, no filler words
45-
- Exact phrase: `"connection pool"` (quoted)
46-
- Exclude terms: `performance -sports` (minus prefix)
47-
- Code identifiers work: `handleError async`
42+
1. **Discover collections** with `qmd collection list` or `qmd ls`.
43+
2. **Search first**, usually with a small result count.
44+
3. **Retrieve source documents** with `qmd get` or `qmd multi-get`.
45+
4. **Answer from the retrieved text**, citing file paths or docids.
46+
5. **If results are weak**, rewrite the query using a different search mode.
4847

49-
**vec (semantic)**
50-
- Full natural language question
51-
- Be specific: `"how does the rate limiter handle burst traffic"`
52-
- Include context: `"in the payment service, how are refunds processed"`
48+
Do not answer from search-result snippets alone when the user needs substance.
49+
Fetch the document.
5350

54-
**hyde (hypothetical document)**
55-
- Write 50-100 words of what the *answer* looks like
56-
- Use the vocabulary you expect in the result
51+
## Search Modes
5752

58-
**expand (auto-expand)**
59-
- Use a single-line query (implicit) or `expand: question` on its own line
60-
- Lets the local LLM generate lex/vec/hyde variations
61-
- Do not mix `expand:` with other typed lines — it's either a standalone expand query or a full query document
53+
### Fast lexical search
6254

63-
### Intent (Disambiguation)
55+
Use BM25 when you know names, exact terms, titles, identifiers, or code symbols:
6456

65-
When a query term is ambiguous, add `intent` to steer results:
57+
```bash
58+
qmd search "cockpit OKR Goodhart" -n 10
59+
qmd search '"AI Before Headcount"' -c concepts -n 5
60+
```
6661

67-
```json
68-
{
69-
"searches": [
70-
{ "type": "lex", "query": "performance" }
71-
],
72-
"intent": "web page load times and Core Web Vitals"
73-
}
62+
Good `lex` queries are short: 2-6 discriminative terms, quoted phrases when exact,
63+
and no filler words.
64+
65+
### Hybrid query search
66+
67+
Use `qmd query` when semantic recall, query expansion, vector search, or reranking
68+
matters more than speed:
69+
70+
```bash
71+
qmd query "decision quality depends on surfacing assumptions and context" -n 10
72+
qmd query --json --explain "metrics as cockpit instruments but not OKRs"
7473
```
7574

76-
Intent affects expansion, reranking, chunk selection, and snippet extraction. It does not search on its own — it's a steering signal that disambiguates queries like "performance" (web-perf vs team health vs fitness).
75+
`qmd query` may initialize local models. If models/GPU are unavailable, slow, or
76+
crashing, fall back to `qmd search` and use better lexical terms.
77+
78+
### Structured queries
7779

78-
### Combining Types
80+
For subtle wiki/doc searches, structured queries are usually strongest:
7981

80-
| Goal | Approach |
81-
|------|----------|
82-
| Know exact terms | `lex` only |
83-
| Don't know vocabulary | Use a single-line query (implicit `expand:`) or `vec` |
84-
| Best recall | `lex` + `vec` |
85-
| Complex topic | `lex` + `vec` + `hyde` |
86-
| Ambiguous query | Add `intent` to any combination above |
82+
```bash
83+
qmd query $'intent: Find the concept note about metrics as instruments without letting OKRs replace judgment.\nlex: cockpit instruments OKR Goodhart metrics judgment\nvec: data informed not metric driven product judgment\nhyde: A concept note says metrics are useful like cockpit instruments, but leaders should remain data-informed rather than metric-driven because OKRs and dashboards can Goodhart product judgment.'
84+
```
8785

88-
First query gets 2x weight in fusion — put your best guess first.
86+
Use this pattern when the user's wording is indirect:
8987

90-
### Lex Query Syntax
88+
- `intent:` disambiguates the target.
89+
- `lex:` anchors exact names, phrases, aliases, and rare terms.
90+
- `vec:` adds the semantic paraphrase.
91+
- `hyde:` describes the document that would answer the query.
9192

92-
| Syntax | Meaning | Example |
93-
|--------|---------|---------|
94-
| `term` | Prefix match | `perf` matches "performance" |
95-
| `"phrase"` | Exact phrase | `"rate limiter"` |
96-
| `-term` | Exclude | `performance -sports` |
93+
Put the best query first; early searches receive more weight in fusion.
9794

98-
Note: `-term` only works in lex queries, not vec/hyde.
95+
## MCP Tool: `query`
9996

100-
### Collection Filtering
97+
When using the MCP server, prefer structured searches:
10198

10299
```json
103-
{ "collections": ["docs"] } // Single
104-
{ "collections": ["docs", "notes"] } // Multiple (OR)
100+
{
101+
"searches": [
102+
{ "type": "lex", "query": "cockpit OKR Goodhart" },
103+
{ "type": "vec", "query": "data informed not metric driven product judgment" },
104+
{ "type": "hyde", "query": "A concept note explains that metrics are useful as instruments, but leaders should not let OKRs or dashboards replace judgment." }
105+
],
106+
"intent": "Find the concept note about using metrics as instruments without becoming metric-driven.",
107+
"collections": ["concepts"],
108+
"limit": 10
109+
}
105110
```
106111

107-
Omit to search all collections.
112+
### Query Types
113+
114+
- `lex` — BM25 keyword search. Best for exact terms, names, titles, and code.
115+
- `vec` — vector semantic search. Best for natural-language concepts.
116+
- `hyde` — vector search using a hypothetical answer/document passage.
117+
118+
## Retrieval Commands
108119

109-
## Other MCP Tools
120+
```bash
121+
qmd get "#abc123" # retrieve by docid
122+
qmd get qmd://concepts/ai-before-headcount.md --full
123+
qmd multi-get 'concepts/{ai-before-headcount.md,data-informed-not-metric-driven.md}' --md
124+
qmd multi-get 'sources/podcast-2025-*.md' -l 80
125+
```
110126

111-
| Tool | Use |
112-
|------|-----|
113-
| `get` | Retrieve doc by path or `#docid` |
114-
| `multi_get` | Retrieve multiple by glob/list |
115-
| `status` | Collections and health |
127+
Use `multi-get` when comparing several hits or gathering context across pages.
128+
Use `--full` when the exact source matters.
116129

117-
## CLI
130+
## Collection Filtering
118131

119132
```bash
120-
qmd query "question" # Auto-expand + rerank
121-
qmd query $'lex: X\nvec: Y' # Structured
122-
qmd query $'expand: question' # Explicit expand
123-
qmd query --json --explain "q" # Show score traces (RRF + rerank blend)
124-
qmd search "keywords" # BM25 only (no LLM)
125-
qmd get "#abc123" # By docid
126-
qmd multi-get "journals/2026-*.md" -l 40 # Batch pull snippets by glob
127-
qmd multi-get notes/foo.md,notes/bar.md # Comma-separated list, preserves order
133+
qmd search "headcount autonomous agents" -c concepts -n 10
134+
qmd query "merchant support product reality" -c concepts -c sources -n 10
128135
```
129136

130-
## HTTP API
137+
Omit `-c` / `collections` to search everything. Add collection filters when a
138+
broad query drifts into the wrong corpus.
139+
140+
## Query Craft
141+
142+
Good QMD searches mix three things:
143+
144+
1. **Title/alias anchors:** exact page titles, named entities, phrases.
145+
2. **Semantic paraphrase:** how a human would describe the idea.
146+
3. **Negative space:** enough intent to avoid nearby-but-wrong concepts.
147+
148+
Examples:
131149

132150
```bash
133-
curl -X POST http://localhost:8181/query \
134-
-H "Content-Type: application/json" \
135-
-d '{"searches": [{"type": "lex", "query": "test"}]}'
151+
# Exact-ish title lookup
152+
qmd search '"arm the rebels" merchants tools big companies' -c concepts
153+
154+
# Semantic concept lookup
155+
qmd query $'intent: Find the customer proximity concept, not generic customer delight.\nlex: support pseudonymous merchant customer interviews\nvec: founder stays close to merchant reality through support and product use'
156+
157+
# Source lookup
158+
qmd search "six-week cadence WhatsApp merchant relationships Shawn Ryan" -c sources -n 10
136159
```
137160

138161
## Setup
@@ -142,3 +165,28 @@ npm install -g @tobilu/qmd
142165
qmd collection add ~/notes --name notes
143166
qmd embed
144167
```
168+
169+
Only add collections or generate embeddings when the user asked for setup or
170+
index maintenance. Searching and retrieving are safe; collection/index mutation is
171+
not a casual first step.
172+
173+
## MCP Setup
174+
175+
See `references/mcp-setup.md` for Claude Code, Claude Desktop, OpenClaw, and HTTP
176+
server configuration.
177+
178+
## Pitfalls
179+
180+
- **Do not stop at snippets.** Fetch documents before making claims.
181+
- **Do not overuse semantic search.** If you know exact titles or terms, BM25 is
182+
faster and often better.
183+
- **Do not mutate indexes casually.** `qmd collection add`, `qmd update`, and
184+
`qmd embed` change local state and can be expensive.
185+
- **Model-backed commands can be environment-sensitive.** If `qmd query`,
186+
`qmd vsearch`, or reranking fails because local models/GPU are unavailable,
187+
use `qmd search` and stronger lexical/structured terms.
188+
- **Ambiguous user wording needs intent.** Add `intent:` rather than hoping query
189+
expansion guesses the right domain.
190+
- **Collection names matter.** Search `concepts` for synthesized wiki pages,
191+
`sources` for transcripts/raw source pages, and docs collections for code/project
192+
documentation.

0 commit comments

Comments
 (0)