qmdr 1.0.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.
Files changed (102) hide show
  1. package/.claude-plugin/marketplace.json +29 -0
  2. package/.env.example +85 -0
  3. package/.gitattributes +3 -0
  4. package/.github/workflows/release.yml +77 -0
  5. package/AI-SETUP.md +466 -0
  6. package/LICENSE +22 -0
  7. package/README.md +78 -0
  8. package/bun.lock +637 -0
  9. package/docs/README-zh.md +78 -0
  10. package/docs/refactor-checklist.md +54 -0
  11. package/docs/setup-openclaw.md +139 -0
  12. package/example-index.yml +33 -0
  13. package/finetune/BALANCED_DISTRIBUTION.md +157 -0
  14. package/finetune/DATA_IMPROVEMENTS.md +218 -0
  15. package/finetune/Justfile +43 -0
  16. package/finetune/Modelfile +16 -0
  17. package/finetune/README.md +299 -0
  18. package/finetune/SCORING.md +286 -0
  19. package/finetune/configs/accelerate_multi_gpu.yaml +17 -0
  20. package/finetune/configs/grpo.yaml +49 -0
  21. package/finetune/configs/sft.yaml +42 -0
  22. package/finetune/configs/sft_local.yaml +40 -0
  23. package/finetune/convert_gguf.py +221 -0
  24. package/finetune/data/best_glm_prompt.txt +17 -0
  25. package/finetune/data/gepa_generated.prompts.json +32 -0
  26. package/finetune/data/qmd_expansion_balanced_deduped.jsonl +413 -0
  27. package/finetune/data/qmd_expansion_diverse_addon.jsonl +386 -0
  28. package/finetune/data/qmd_expansion_handcrafted.jsonl +65 -0
  29. package/finetune/data/qmd_expansion_handcrafted_only.jsonl +336 -0
  30. package/finetune/data/qmd_expansion_locations.jsonl +64 -0
  31. package/finetune/data/qmd_expansion_people.jsonl +46 -0
  32. package/finetune/data/qmd_expansion_short_nontech.jsonl +200 -0
  33. package/finetune/data/qmd_expansion_v2.jsonl +1498 -0
  34. package/finetune/data/qmd_only_sampled.jsonl +399 -0
  35. package/finetune/dataset/analyze_data.py +369 -0
  36. package/finetune/dataset/clean_data.py +906 -0
  37. package/finetune/dataset/generate_balanced.py +823 -0
  38. package/finetune/dataset/generate_data.py +714 -0
  39. package/finetune/dataset/generate_data_offline.py +206 -0
  40. package/finetune/dataset/generate_diverse.py +441 -0
  41. package/finetune/dataset/generate_ollama.py +326 -0
  42. package/finetune/dataset/prepare_data.py +197 -0
  43. package/finetune/dataset/schema.py +73 -0
  44. package/finetune/dataset/score_data.py +115 -0
  45. package/finetune/dataset/validate_schema.py +104 -0
  46. package/finetune/eval.py +196 -0
  47. package/finetune/evals/queries.txt +56 -0
  48. package/finetune/gepa/__init__.py +1 -0
  49. package/finetune/gepa/best_prompt.txt +31 -0
  50. package/finetune/gepa/best_prompt_glm.txt +1 -0
  51. package/finetune/gepa/dspy_gepa.py +204 -0
  52. package/finetune/gepa/example.py +117 -0
  53. package/finetune/gepa/generate.py +129 -0
  54. package/finetune/gepa/gepa_outputs.jsonl +10 -0
  55. package/finetune/gepa/gepa_outputs_glm.jsonl +20 -0
  56. package/finetune/gepa/model.json +19 -0
  57. package/finetune/gepa/optimizer.py +70 -0
  58. package/finetune/gepa/score.py +84 -0
  59. package/finetune/jobs/eval.py +490 -0
  60. package/finetune/jobs/eval_common.py +354 -0
  61. package/finetune/jobs/eval_verbose.py +113 -0
  62. package/finetune/jobs/grpo.py +141 -0
  63. package/finetune/jobs/quantize.py +244 -0
  64. package/finetune/jobs/sft.py +121 -0
  65. package/finetune/pyproject.toml +23 -0
  66. package/finetune/reward.py +610 -0
  67. package/finetune/train.py +611 -0
  68. package/finetune/uv.lock +4070 -0
  69. package/flake.lock +61 -0
  70. package/flake.nix +83 -0
  71. package/migrate-schema.ts +162 -0
  72. package/package.json +56 -0
  73. package/skills/qmdr/SKILL.md +172 -0
  74. package/skills/qmdr/references/mcp-setup.md +88 -0
  75. package/src/app/commands/collection.ts +55 -0
  76. package/src/app/commands/context.ts +82 -0
  77. package/src/app/commands/document.ts +46 -0
  78. package/src/app/commands/maintenance.ts +60 -0
  79. package/src/app/commands/search.ts +45 -0
  80. package/src/app/ports/llm.ts +13 -0
  81. package/src/app/services/llm-service.ts +145 -0
  82. package/src/cli.test.ts +963 -0
  83. package/src/collections.ts +390 -0
  84. package/src/eval.test.ts +412 -0
  85. package/src/formatter.ts +427 -0
  86. package/src/llm.test.ts +559 -0
  87. package/src/llm.ts +1990 -0
  88. package/src/mcp.test.ts +889 -0
  89. package/src/mcp.ts +626 -0
  90. package/src/qmd.ts +3330 -0
  91. package/src/store/collections.ts +7 -0
  92. package/src/store/context.ts +10 -0
  93. package/src/store/db.ts +5 -0
  94. package/src/store/documents.ts +26 -0
  95. package/src/store/maintenance.ts +15 -0
  96. package/src/store/path.ts +13 -0
  97. package/src/store/search.ts +10 -0
  98. package/src/store-paths.test.ts +395 -0
  99. package/src/store.test.ts +2483 -0
  100. package/src/store.ts +2813 -0
  101. package/test/eval-harness.ts +223 -0
  102. package/tsconfig.json +29 -0
@@ -0,0 +1,29 @@
1
+ {
2
+ "name": "qmdr",
3
+ "owner": {
4
+ "name": "uf-hy",
5
+ "email": "uf-hy@users.noreply.github.com"
6
+ },
7
+ "plugins": [
8
+ {
9
+ "name": "qmdr",
10
+ "source": "./",
11
+ "description": "Search personal markdown files with hybrid BM25 + vector + cloud LLM reranking.",
12
+ "version": "1.0.0",
13
+ "author": {
14
+ "name": "uf-hy",
15
+ "email": "uf-hy@users.noreply.github.com"
16
+ },
17
+ "repository": "https://github.com/uf-hy/qmdr",
18
+ "license": "MIT",
19
+ "keywords": ["markdown", "search", "qmd", "memory", "reranking", "remote"],
20
+ "skills": ["./skills/"],
21
+ "mcpServers": {
22
+ "qmd": {
23
+ "command": "qmd",
24
+ "args": ["mcp"]
25
+ }
26
+ }
27
+ }
28
+ ]
29
+ }
package/.env.example ADDED
@@ -0,0 +1,85 @@
1
+ # QMDR Environment Variables
2
+ # Copy to .env, fill in your API keys, then `source .env`
3
+ #
4
+ # 💡 Three config modes (pick one):
5
+ #
6
+ # Mode A: SiliconFlow only (simplest, one key)
7
+ # → Embedding / Query Expansion / Rerank all via SiliconFlow
8
+ #
9
+ # Mode B: SiliconFlow + Gemini (recommended)
10
+ # → Embedding / Expansion via SiliconFlow, Rerank via Gemini
11
+ #
12
+ # Mode C: OpenAI-compatible API only
13
+ # → OpenAI, Azure, Volcengine, any relay proxy
14
+ #
15
+ # 💡 三种配置方式(任选其一):
16
+ #
17
+ # 方式一:只用 SiliconFlow(最简,一个 Key)
18
+ # 方式二:SiliconFlow + Gemini(推荐,各取所长)
19
+ # 方式三:只用 OpenAI 兼容 API(火山引擎、中转站等)
20
+
21
+ # ============================================================
22
+ # SiliconFlow
23
+ # China: https://cloud.siliconflow.cn (free tier)
24
+ # International: https://cloud.siliconflow.com (free tier)
25
+ # ============================================================
26
+
27
+ QMD_SILICONFLOW_API_KEY=sk-your-siliconflow-key-here
28
+
29
+ # International users: uncomment to use the global endpoint
30
+ # QMD_SILICONFLOW_BASE_URL=https://api.siliconflow.com/v1
31
+
32
+ # ============================================================
33
+ # Gemini (https://ai.google.dev — free tier: 15 RPM / 1M tokens/day)
34
+ # ============================================================
35
+
36
+ # QMD_GEMINI_API_KEY=your-gemini-key-here
37
+ # QMD_GEMINI_MODEL=gemini-2.5-flash
38
+ # QMD_GEMINI_BASE_URL=https://generativelanguage.googleapis.com
39
+
40
+ # ============================================================
41
+ # OpenAI-compatible API
42
+ # Supports: OpenAI, Azure, Volcengine, relay proxies, etc.
43
+ # ============================================================
44
+
45
+ # QMD_OPENAI_API_KEY=your-key-here
46
+ # QMD_OPENAI_BASE_URL=https://api.openai.com/v1
47
+ # QMD_OPENAI_MODEL=gpt-4o-mini
48
+ # QMD_OPENAI_EMBED_MODEL=text-embedding-3-small
49
+
50
+ # ============================================================
51
+ # Provider routing (auto-detected from keys, usually not needed)
52
+ # ============================================================
53
+
54
+ # QMD_EMBED_PROVIDER=siliconflow # siliconflow / openai
55
+ # QMD_QUERY_EXPANSION_PROVIDER=siliconflow # siliconflow / gemini / openai
56
+ # QMD_RERANK_PROVIDER=gemini # siliconflow / gemini / openai
57
+ # QMD_RERANK_MODE=llm # llm (chat model) / rerank (dedicated rerank API)
58
+
59
+ # ============================================================
60
+ # Model overrides (sensible defaults provided)
61
+ # ============================================================
62
+
63
+ # SiliconFlow models
64
+ # QMD_SILICONFLOW_EMBED_MODEL=Qwen/Qwen3-Embedding-8B
65
+ # QMD_SILICONFLOW_QUERY_EXPANSION_MODEL=zai-org/GLM-4.5-Air
66
+ # QMD_SILICONFLOW_RERANK_MODEL=BAAI/bge-reranker-v2-m3 # when QMD_RERANK_MODE=rerank
67
+ # QMD_LLM_RERANK_MODEL=zai-org/GLM-4.5-Air # when QMD_RERANK_MODE=llm
68
+
69
+ # ============================================================
70
+ # Performance tuning (sensible defaults provided)
71
+ # ============================================================
72
+
73
+ # QMD_CHUNK_SIZE_TOKENS=200 # Tokens per chunk (default: 200)
74
+ # QMD_CHUNK_OVERLAP_TOKENS=40 # Overlap between chunks (default: 40)
75
+ # QMD_EMBED_BATCH_SIZE=32 # Embedding batch size (default: 32)
76
+ # QMD_RERANK_DOC_LIMIT=40 # Max docs for reranking (default: 40)
77
+ # QMD_RERANK_CHUNKS_PER_DOC=3 # Chunks per doc for reranking (default: 3)
78
+
79
+ # ============================================================
80
+ # Paths (auto-detected, override if needed)
81
+ # ============================================================
82
+
83
+ # QMD_CONFIG_DIR=~/.config/qmd # Config directory (index.yml location)
84
+ # XDG_CACHE_HOME=~/.cache # Cache directory (database at $XDG_CACHE_HOME/qmd/index.sqlite)
85
+ # QMD_SQLITE_VEC_PATH= # sqlite-vec native extension path (auto-detected)
package/.gitattributes ADDED
@@ -0,0 +1,3 @@
1
+
2
+ # Use bd merge for beads JSONL files
3
+ .beads/issues.jsonl merge=beads
@@ -0,0 +1,77 @@
1
+ name: Release
2
+
3
+ on:
4
+ push:
5
+ tags:
6
+ - 'v*'
7
+
8
+ permissions:
9
+ contents: write
10
+
11
+ jobs:
12
+ build:
13
+ strategy:
14
+ matrix:
15
+ include:
16
+ - os: macos-latest
17
+ target: darwin-arm64
18
+ artifact: qmd-darwin-arm64
19
+ - os: macos-13
20
+ target: darwin-x64
21
+ artifact: qmd-darwin-x64
22
+ - os: ubuntu-latest
23
+ target: linux-x64
24
+ artifact: qmd-linux-x64
25
+ - os: ubuntu-latest
26
+ target: linux-arm64
27
+ artifact: qmd-linux-arm64
28
+
29
+ runs-on: ${{ matrix.os }}
30
+
31
+ steps:
32
+ - uses: actions/checkout@v4
33
+
34
+ - uses: oven-sh/setup-bun@v2
35
+ with:
36
+ bun-version: latest
37
+
38
+ - name: Install dependencies
39
+ run: bun install
40
+
41
+ - name: Build binary
42
+ run: |
43
+ if [ "${{ matrix.target }}" = "linux-arm64" ]; then
44
+ bun build --compile --target=bun-linux-arm64 src/qmd.ts --outfile ${{ matrix.artifact }}
45
+ else
46
+ bun build --compile src/qmd.ts --outfile ${{ matrix.artifact }}
47
+ fi
48
+
49
+ - name: Test binary
50
+ if: matrix.target != 'linux-arm64'
51
+ run: |
52
+ ./${{ matrix.artifact }} --help
53
+ ./${{ matrix.artifact }} status 2>/dev/null || true
54
+ echo "✅ Binary runs successfully"
55
+
56
+ - uses: actions/upload-artifact@v4
57
+ with:
58
+ name: ${{ matrix.artifact }}
59
+ path: ${{ matrix.artifact }}
60
+
61
+ release:
62
+ needs: build
63
+ runs-on: ubuntu-latest
64
+ steps:
65
+ - uses: actions/download-artifact@v4
66
+ with:
67
+ merge-multiple: true
68
+
69
+ - name: Make binaries executable
70
+ run: chmod +x qmd-*
71
+
72
+ - name: Create Release
73
+ uses: softprops/action-gh-release@v2
74
+ with:
75
+ files: qmd-*
76
+ generate_release_notes: true
77
+ draft: false
package/AI-SETUP.md ADDED
@@ -0,0 +1,466 @@
1
+ # QMDR - AI Setup Guide
2
+
3
+ > **For AI coding agents.** Humans: just paste this file's URL to your AI and let it handle the rest.
4
+
5
+ QMDR is a fork of [tobi/qmd](https://github.com/tobi/qmd) — a hybrid search engine for markdown files (BM25 + vector + LLM reranking). QMDR replaces local GGUF models with cloud APIs, so there's no GPU needed and reranking quality is much higher.
6
+
7
+ ---
8
+
9
+ ## Phase 0: Detect Environment
10
+
11
+ Before starting, determine the following:
12
+
13
+ ### 1. Which AI client is the user using?
14
+
15
+ | Client | Integration | Config file for usage tips |
16
+ |--------|------------|---------------------------|
17
+ | **OpenClaw** | Native memory backend | `TOOLS.md` in workspace |
18
+ | **Claude Code** | Skill (SKILL.md) | `CLAUDE.md` in project root |
19
+ | **OpenCode** | Skill (SKILL.md) | `AGENTS.md` in project root |
20
+ | **Other** | CLI only | N/A |
21
+
22
+ ### 2. What region is the user in?
23
+
24
+ Detect via system locale, timezone, or ask directly. This affects:
25
+ - **China** → Use `https://cloud.siliconflow.cn` for registration, `https://api.siliconflow.cn/v1` as API endpoint. Bun install may need mirror.
26
+ - **International** → Use `https://cloud.siliconflow.com` for registration, `https://api.siliconflow.com/v1` as API endpoint.
27
+
28
+ ### 3. Interaction style
29
+
30
+ | Client | How to present choices |
31
+ |--------|----------------------|
32
+ | **OpenClaw** | Use inline buttons (`buttons` parameter in message tool) |
33
+ | **Claude Code / OpenCode** | Numbered list — ask user to reply with number |
34
+ | **Other** | Y/N or numbered input |
35
+
36
+ ---
37
+
38
+ ## Phase 1: Quick Install or Step-by-Step?
39
+
40
+ Ask the user:
41
+
42
+ > **Do you want one-click install or step-by-step setup?**
43
+ >
44
+ > **One-click:** Provide your API keys and I'll handle everything — install Bun (if missing), install QMDR, configure all providers, verify with doctor.
45
+ >
46
+ > **Step-by-step:** I'll walk you through each decision.
47
+
48
+ ### One-click install flow
49
+
50
+ Collect upfront:
51
+ 1. SiliconFlow API key (required for embedding)
52
+ 2. Gemini API key (recommended for reranking) — or skip to use SiliconFlow for everything
53
+ 3. Any custom OpenAI-compatible endpoint (optional)
54
+
55
+ Then execute Phase 2 → 3 → 4 → 5 → 6 → 7 automatically, using defaults for all choices.
56
+
57
+ ### Step-by-step flow
58
+
59
+ Continue to Phase 2.
60
+
61
+ ---
62
+
63
+ ## Phase 2: Install QMDR
64
+
65
+ ### Check for Bun
66
+
67
+ ```bash
68
+ bun --version 2>/dev/null || echo "NOT_INSTALLED"
69
+ ```
70
+
71
+ **If Bun is installed:** skip to "Install QMDR" below.
72
+
73
+ **If Bun is NOT installed:** ask the user:
74
+
75
+ > Bun is required to run QMDR. Install it?
76
+ >
77
+ > 1. **Yes, install Bun** (recommended)
78
+ > 2. **No, download pre-built binary instead**
79
+
80
+ #### Install Bun
81
+
82
+ ```bash
83
+ # International
84
+ curl -fsSL https://bun.sh/install | bash
85
+
86
+ # China (if above fails or is slow)
87
+ curl -fsSL https://bun.sh/install | BUN_INSTALL_MIRROR=https://npmmirror.com/mirrors/bun bash
88
+ ```
89
+
90
+ After install, verify: `bun --version`
91
+
92
+ #### Install QMDR (two paths)
93
+
94
+ **Path A: Via Bun (recommended)**
95
+ ```bash
96
+ bun install -g github:uf-hy/qmdr
97
+ qmd --help # verify
98
+ ```
99
+
100
+ **Path B: Pre-built binary (no Bun needed)**
101
+ ```bash
102
+ # macOS arm64
103
+ curl -L https://github.com/uf-hy/qmdr/releases/latest/download/qmd-darwin-arm64 -o /usr/local/bin/qmd
104
+ chmod +x /usr/local/bin/qmd
105
+
106
+ # Linux x64
107
+ curl -L https://github.com/uf-hy/qmdr/releases/latest/download/qmd-linux-x64 -o /usr/local/bin/qmd
108
+ chmod +x /usr/local/bin/qmd
109
+ ```
110
+
111
+ ⚠️ Binary users: `sqlite-vec` native extension must be discoverable. macOS: `brew install sqlite`. Or set `QMD_SQLITE_VEC_PATH=/path/to/vec0.dylib`.
112
+
113
+ ---
114
+
115
+ ## Phase 3: Configure Embedding (SiliconFlow)
116
+
117
+ SiliconFlow provides the embedding model. Ask:
118
+
119
+ > **Do you have a SiliconFlow API key?**
120
+ >
121
+ > 1. **Yes** — I'll enter my key
122
+ > 2. **No** — show me how to get one
123
+ > 3. **Custom provider** — I want to use a different OpenAI-compatible endpoint
124
+
125
+ ### Option 1: User has key
126
+
127
+ ```bash
128
+ export QMD_SILICONFLOW_API_KEY=sk-user-provided-key
129
+ ```
130
+
131
+ ### Option 2: Guide to get key
132
+
133
+ **China users:**
134
+ > Register at https://cloud.siliconflow.cn (no affiliate link, the author was too lazy to set one up)
135
+ > 1. Sign up with phone number or email
136
+ > 2. Go to API Keys page → Create new key
137
+ > 3. Free tier includes embedding models
138
+
139
+ **International users:**
140
+ > Register at https://cloud.siliconflow.com (no affiliate link)
141
+ > 1. Sign up with email
142
+ > 2. Go to API Keys page → Create new key
143
+ > 3. Free tier includes embedding models
144
+
145
+ After user provides key:
146
+ ```bash
147
+ export QMD_SILICONFLOW_API_KEY=sk-user-provided-key
148
+ ```
149
+
150
+ **International users — additional API endpoint config:**
151
+ ```bash
152
+ export QMD_SILICONFLOW_BASE_URL=https://api.siliconflow.com/v1
153
+ ```
154
+ (China users don't need this — the default `https://api.siliconflow.cn/v1` works)
155
+
156
+ ### Option 3: Custom provider
157
+
158
+ Ask for:
159
+ 1. API endpoint URL (must be OpenAI-compatible)
160
+ 2. API key
161
+
162
+ ```bash
163
+ export QMD_OPENAI_API_KEY=user-key
164
+ export QMD_OPENAI_BASE_URL=https://their-endpoint.com/v1
165
+ export QMD_EMBED_PROVIDER=openai
166
+ ```
167
+
168
+ Test connectivity:
169
+ ```bash
170
+ curl -s "$QMD_OPENAI_BASE_URL/models" -H "Authorization: Bearer $QMD_OPENAI_API_KEY" | head -5
171
+ ```
172
+
173
+ ### Configure embedding model
174
+
175
+ Default: `Qwen/Qwen3-Embedding-8B` (on SiliconFlow, free)
176
+
177
+ Ask:
178
+ > Keep the default embedding model (`Qwen/Qwen3-Embedding-8B`), or choose your own?
179
+ >
180
+ > If you don't know which to pick, the default is good.
181
+
182
+ If user wants to change:
183
+ ```bash
184
+ export QMD_SILICONFLOW_EMBED_MODEL=their-chosen-model
185
+ # or for custom provider:
186
+ export QMD_OPENAI_EMBED_MODEL=their-chosen-model
187
+ ```
188
+
189
+ ### Configure embedding dimensions
190
+
191
+ > Do you know the output dimensions of your embedding model?
192
+ >
193
+ > 1. **Use default** (auto-detect from model — recommended)
194
+ > 2. **I know the dimensions** — let me enter it
195
+ > 3. **I don't know** — please look it up for me
196
+
197
+ If option 3: search the web for "{model_name} embedding dimensions" and inform the user.
198
+
199
+ Note: If dimensions change after initial indexing, user must run `qmd embed -f` to rebuild.
200
+
201
+ ### Configure chunk size
202
+
203
+ Default: `200` tokens per chunk, `40` tokens overlap.
204
+
205
+ > Chunk size controls how documents are split for embedding.
206
+ >
207
+ > - **Default: 200 tokens** (recommended for most use cases)
208
+ > - Larger chunks = more context per result, but less precise
209
+ > - Smaller chunks = more precise, but may lose context
210
+
211
+ ```bash
212
+ # Only if user wants to change defaults:
213
+ export QMD_CHUNK_SIZE_TOKENS=200 # default
214
+ export QMD_CHUNK_OVERLAP_TOKENS=40 # default
215
+ ```
216
+
217
+ ---
218
+
219
+ ## Phase 4: Configure Query Expansion
220
+
221
+ Query expansion rewrites the user's search query into multiple variations (keyword + semantic + hypothetical) to improve recall.
222
+
223
+ Default: `GLM-4.5-Air` on SiliconFlow (~¥1/month, fast, good quality).
224
+
225
+ Ask:
226
+ > Use the default query expansion model (`GLM-4.5-Air` on SiliconFlow), or use your own?
227
+ >
228
+ > 1. **Default** (GLM-4.5-Air on SiliconFlow — recommended)
229
+ > 2. **Use the reranking provider's model** (configured in next step)
230
+ > 3. **Custom** — I want to specify a model
231
+
232
+ If option 2: will be configured after Phase 5.
233
+
234
+ If option 3:
235
+ ```bash
236
+ export QMD_QUERY_EXPANSION_PROVIDER=openai # or gemini
237
+ # For OpenAI-compatible:
238
+ export QMD_OPENAI_MODEL=their-model-name
239
+ # For Gemini:
240
+ export QMD_GEMINI_API_KEY=their-key
241
+ ```
242
+
243
+ ---
244
+
245
+ ## Phase 5: Configure Reranking
246
+
247
+ Reranking uses a large language model to judge which search results are truly relevant. This is where QMDR's quality advantage comes from — cloud LLMs are much better at this than the original QMD's 0.6B local model.
248
+
249
+ **Default: Gemini 2.5 Flash** with thinking budget set to 0 (fast, high quality, generous free tier).
250
+
251
+ > **Do you have a Gemini API key?**
252
+ >
253
+ > 1. **Yes** — I'll enter my key
254
+ > 2. **No** — show me how to get one
255
+ > 3. **Skip Gemini** — use SiliconFlow or my own model for reranking
256
+
257
+ ### Option 1: User has Gemini key
258
+
259
+ ```bash
260
+ export QMD_GEMINI_API_KEY=user-key
261
+ export QMD_RERANK_PROVIDER=gemini
262
+ ```
263
+
264
+ ### Option 2: Guide to get Gemini key
265
+
266
+ > Get a free Gemini API key at https://ai.google.dev
267
+ > 1. Sign in with Google account
268
+ > 2. Click "Get API key" → Create key
269
+ > 3. Free tier: 15 RPM / 1M tokens per day (more than enough for reranking)
270
+
271
+ Note for China users: Gemini API may require a proxy. If the user has a proxy:
272
+ ```bash
273
+ export QMD_GEMINI_BASE_URL=https://their-proxy-endpoint
274
+ ```
275
+
276
+ If no proxy available, recommend Option 3 instead.
277
+
278
+ ### Option 3: Alternative reranking
279
+
280
+ **Using SiliconFlow LLM rerank (no extra key needed):**
281
+ ```bash
282
+ export QMD_RERANK_PROVIDER=siliconflow
283
+ export QMD_RERANK_MODE=llm
284
+ ```
285
+
286
+ **Using a dedicated rerank model API (e.g. BAAI/bge-reranker):**
287
+ ```bash
288
+ export QMD_RERANK_PROVIDER=siliconflow
289
+ export QMD_RERANK_MODE=rerank
290
+ export QMD_SILICONFLOW_RERANK_MODEL=BAAI/bge-reranker-v2-m3
291
+ ```
292
+
293
+ **Using OpenAI-compatible endpoint:**
294
+ ```bash
295
+ export QMD_RERANK_PROVIDER=openai
296
+ export QMD_RERANK_MODE=llm
297
+ export QMD_OPENAI_API_KEY=their-key
298
+ export QMD_OPENAI_BASE_URL=https://their-endpoint/v1
299
+ ```
300
+
301
+ For Claude Code / OpenCode users: you can reuse whichever model API you're already paying for.
302
+
303
+ ### Model selection
304
+
305
+ Default reranking model: `gemini-2.5-flash` with `thinkingBudget: 0` (no reasoning overhead, pure relevance judgment).
306
+
307
+ > Keep the default reranking model (`gemini-2.5-flash`), or change it?
308
+
309
+ If user wants to change:
310
+ ```bash
311
+ export QMD_GEMINI_MODEL=their-model # for Gemini provider
312
+ export QMD_LLM_RERANK_MODEL=their-model # for SiliconFlow/OpenAI LLM rerank
313
+ ```
314
+
315
+ ---
316
+
317
+ ## Phase 6: Doctor Verification
318
+
319
+ Run the diagnostic:
320
+
321
+ ```bash
322
+ qmd doctor
323
+ ```
324
+
325
+ **Read the output carefully.** Check for:
326
+
327
+ | Status | Meaning | Action |
328
+ |--------|---------|--------|
329
+ | ✅ | Provider working | Good |
330
+ | ❌ | Provider failed | Fix config or key |
331
+ | Speed > 5s | Model is slow | Suggest switching to a faster/non-thinking model |
332
+
333
+ If any provider shows errors, go back to the relevant Phase and fix.
334
+
335
+ If speed > 5s for reranking or query expansion:
336
+ > Your {component} is taking {time}s — this may slow down searches. Consider switching to a faster model (non-thinking models like `gemini-2.5-flash` with thinkingBudget=0 are recommended).
337
+
338
+ Optional quality check:
339
+ ```bash
340
+ qmd doctor --bench
341
+ ```
342
+ This runs test queries and evaluates expansion quality.
343
+
344
+ ---
345
+
346
+ ## Phase 7: Client Integration
347
+
348
+ ### OpenClaw
349
+
350
+ QMDR is a **native memory backend** for OpenClaw — no MCP needed. OpenClaw spawns QMDR directly.
351
+
352
+ **→ See [docs/setup-openclaw.md](docs/setup-openclaw.md) for detailed configuration.**
353
+
354
+ After setup, add this to `TOOLS.md` in the workspace:
355
+
356
+ ```markdown
357
+ ## Memory Search (QMDR)
358
+
359
+ - **Always use natural language** for memory_search queries — not keyword concatenation
360
+ - ✅ Good: "what did we discuss about the server migration last week"
361
+ - ❌ Bad: "server migration discussion last week"
362
+ - The hybrid pipeline (query expansion + vector + rerank) is optimized for natural language
363
+ - `memory_search` is an internal OpenClaw tool, never a shell command
364
+ ```
365
+
366
+ ### Claude Code
367
+
368
+ Install the QMDR skill:
369
+
370
+ ```bash
371
+ mkdir -p ~/.claude/skills/qmdr
372
+ curl -sL https://raw.githubusercontent.com/uf-hy/qmdr/main/skills/qmdr/SKILL.md \
373
+ -o ~/.claude/skills/qmdr/SKILL.md
374
+ ```
375
+
376
+ After setup, add this to `CLAUDE.md` in the project root:
377
+
378
+ ```markdown
379
+ ## Memory Search (QMDR)
380
+
381
+ - Use `qmd query "natural language question"` for best results
382
+ - Always use natural language — not keyword concatenation
383
+ - ✅ Good: `qmd query "what authentication method did we decide on"`
384
+ - ❌ Bad: `qmd query "authentication method decision"`
385
+ - Use `qmd search` for fast keyword-only lookups
386
+ - Use `qmd get "#docid"` to retrieve full documents from search results
387
+ ```
388
+
389
+ ### OpenCode
390
+
391
+ Install the QMDR skill:
392
+
393
+ ```bash
394
+ mkdir -p ~/.config/opencode/skills/qmdr
395
+ curl -sL https://raw.githubusercontent.com/uf-hy/qmdr/main/skills/qmdr/SKILL.md \
396
+ -o ~/.config/opencode/skills/qmdr/SKILL.md
397
+ ```
398
+
399
+ After setup, add this to `AGENTS.md` in the project root:
400
+
401
+ ```markdown
402
+ ## Memory Search (QMDR)
403
+
404
+ - Use `qmd query "natural language question"` for best results
405
+ - Always use natural language — not keyword concatenation
406
+ - ✅ Good: `qmd query "what authentication method did we decide on"`
407
+ - ❌ Bad: `qmd query "authentication method decision"`
408
+ - Use `qmd search` for fast keyword-only lookups
409
+ - Use `qmd get "#docid"` to retrieve full documents from search results
410
+ ```
411
+
412
+ ---
413
+
414
+ ## Environment Variables Reference
415
+
416
+ | Variable | Default | Purpose |
417
+ |----------|---------|---------||
418
+ | **API Keys** | | |
419
+ | `QMD_SILICONFLOW_API_KEY` | — | SiliconFlow |
420
+ | `QMD_GEMINI_API_KEY` | — | Google Gemini |
421
+ | `QMD_OPENAI_API_KEY` | — | OpenAI-compatible |
422
+ | **Provider routing** | | |
423
+ | `QMD_EMBED_PROVIDER` | auto | `siliconflow` / `openai` |
424
+ | `QMD_QUERY_EXPANSION_PROVIDER` | auto | `siliconflow` / `gemini` / `openai` |
425
+ | `QMD_RERANK_PROVIDER` | auto | `siliconflow` / `gemini` / `openai` |
426
+ | `QMD_RERANK_MODE` | `llm` | `llm` (chat model) / `rerank` (dedicated rerank API) |
427
+ | **Custom endpoints** | | |
428
+ | `QMD_SILICONFLOW_BASE_URL` | `https://api.siliconflow.cn/v1` | SiliconFlow endpoint (international: use `api.siliconflow.com`) |
429
+ | `QMD_GEMINI_BASE_URL` | Google default | Custom Gemini endpoint |
430
+ | `QMD_OPENAI_BASE_URL` | `api.openai.com/v1` | Custom OpenAI endpoint |
431
+ | **Model overrides** | | |
432
+ | `QMD_SILICONFLOW_EMBED_MODEL` | `Qwen/Qwen3-Embedding-8B` | Embedding model |
433
+ | `QMD_SILICONFLOW_QUERY_EXPANSION_MODEL` | `zai-org/GLM-4.5-Air` | Query expansion |
434
+ | `QMD_SILICONFLOW_RERANK_MODEL` | `BAAI/bge-reranker-v2-m3` | Dedicated rerank model |
435
+ | `QMD_LLM_RERANK_MODEL` | `zai-org/GLM-4.5-Air` | LLM rerank model |
436
+ | `QMD_GEMINI_MODEL` | `gemini-2.5-flash` | Gemini model (thinkingBudget=0 by default) |
437
+ | `QMD_OPENAI_MODEL` | `gpt-4o-mini` | OpenAI chat model |
438
+ | `QMD_OPENAI_EMBED_MODEL` | `text-embedding-3-small` | OpenAI embed model |
439
+ | **Tuning** | | |
440
+ | `QMD_CHUNK_SIZE_TOKENS` | `200` | Tokens per chunk |
441
+ | `QMD_CHUNK_OVERLAP_TOKENS` | `40` | Overlap between chunks |
442
+ | `QMD_EMBED_BATCH_SIZE` | `32` | Embedding batch size |
443
+ | `QMD_RERANK_DOC_LIMIT` | `40` | Max docs for reranking |
444
+ | `QMD_RERANK_CHUNKS_PER_DOC` | `3` | Chunks per doc for reranking |
445
+ | **Paths** | | |
446
+ | `QMD_SQLITE_VEC_PATH` | auto | sqlite-vec native extension path |
447
+
448
+ **If you change the embedding model, run `qmd embed -f` to rebuild the vector index.**
449
+
450
+ ## Troubleshooting
451
+
452
+ | Problem | Fix |
453
+ |---------|-----|
454
+ | `qmd: command not found` | `bun link`, ensure `~/.bun/bin` in PATH |
455
+ | sqlite-vec load error | macOS: `brew install sqlite`; or set `QMD_SQLITE_VEC_PATH` |
456
+ | sqlite-vec `/$bunfs/root/` error | Switch to source mode (bun install) instead of compiled binary |
457
+ | Dimension mismatch | `qmd embed -f` to rebuild with current model |
458
+ | Slow queries (>5s) | Run `qmd doctor` — switch to non-thinking models |
459
+ | `Script not found "query"` | Don't use `"bun /path/to/qmd.ts"` as command; use direct path with shebang |
460
+
461
+ ## Links
462
+
463
+ - Original project: https://github.com/tobi/qmd
464
+ - SiliconFlow (China): https://cloud.siliconflow.cn
465
+ - SiliconFlow (International): https://cloud.siliconflow.com
466
+ - Gemini API: https://ai.google.dev
package/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 QMDR Contributors
4
+ Based on QMD by Tobias Lütke (https://github.com/tobi/qmd)
5
+
6
+ Permission is hereby granted, free of charge, to any person obtaining a copy
7
+ of this software and associated documentation files (the "Software"), to deal
8
+ in the Software without restriction, including without limitation the rights
9
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10
+ copies of the Software, and to permit persons to whom the Software is
11
+ furnished to do so, subject to the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be included in all
14
+ copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22
+ SOFTWARE.