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.
- package/.claude-plugin/marketplace.json +29 -0
- package/.env.example +85 -0
- package/.gitattributes +3 -0
- package/.github/workflows/release.yml +77 -0
- package/AI-SETUP.md +466 -0
- package/LICENSE +22 -0
- package/README.md +78 -0
- package/bun.lock +637 -0
- package/docs/README-zh.md +78 -0
- package/docs/refactor-checklist.md +54 -0
- package/docs/setup-openclaw.md +139 -0
- package/example-index.yml +33 -0
- package/finetune/BALANCED_DISTRIBUTION.md +157 -0
- package/finetune/DATA_IMPROVEMENTS.md +218 -0
- package/finetune/Justfile +43 -0
- package/finetune/Modelfile +16 -0
- package/finetune/README.md +299 -0
- package/finetune/SCORING.md +286 -0
- package/finetune/configs/accelerate_multi_gpu.yaml +17 -0
- package/finetune/configs/grpo.yaml +49 -0
- package/finetune/configs/sft.yaml +42 -0
- package/finetune/configs/sft_local.yaml +40 -0
- package/finetune/convert_gguf.py +221 -0
- package/finetune/data/best_glm_prompt.txt +17 -0
- package/finetune/data/gepa_generated.prompts.json +32 -0
- package/finetune/data/qmd_expansion_balanced_deduped.jsonl +413 -0
- package/finetune/data/qmd_expansion_diverse_addon.jsonl +386 -0
- package/finetune/data/qmd_expansion_handcrafted.jsonl +65 -0
- package/finetune/data/qmd_expansion_handcrafted_only.jsonl +336 -0
- package/finetune/data/qmd_expansion_locations.jsonl +64 -0
- package/finetune/data/qmd_expansion_people.jsonl +46 -0
- package/finetune/data/qmd_expansion_short_nontech.jsonl +200 -0
- package/finetune/data/qmd_expansion_v2.jsonl +1498 -0
- package/finetune/data/qmd_only_sampled.jsonl +399 -0
- package/finetune/dataset/analyze_data.py +369 -0
- package/finetune/dataset/clean_data.py +906 -0
- package/finetune/dataset/generate_balanced.py +823 -0
- package/finetune/dataset/generate_data.py +714 -0
- package/finetune/dataset/generate_data_offline.py +206 -0
- package/finetune/dataset/generate_diverse.py +441 -0
- package/finetune/dataset/generate_ollama.py +326 -0
- package/finetune/dataset/prepare_data.py +197 -0
- package/finetune/dataset/schema.py +73 -0
- package/finetune/dataset/score_data.py +115 -0
- package/finetune/dataset/validate_schema.py +104 -0
- package/finetune/eval.py +196 -0
- package/finetune/evals/queries.txt +56 -0
- package/finetune/gepa/__init__.py +1 -0
- package/finetune/gepa/best_prompt.txt +31 -0
- package/finetune/gepa/best_prompt_glm.txt +1 -0
- package/finetune/gepa/dspy_gepa.py +204 -0
- package/finetune/gepa/example.py +117 -0
- package/finetune/gepa/generate.py +129 -0
- package/finetune/gepa/gepa_outputs.jsonl +10 -0
- package/finetune/gepa/gepa_outputs_glm.jsonl +20 -0
- package/finetune/gepa/model.json +19 -0
- package/finetune/gepa/optimizer.py +70 -0
- package/finetune/gepa/score.py +84 -0
- package/finetune/jobs/eval.py +490 -0
- package/finetune/jobs/eval_common.py +354 -0
- package/finetune/jobs/eval_verbose.py +113 -0
- package/finetune/jobs/grpo.py +141 -0
- package/finetune/jobs/quantize.py +244 -0
- package/finetune/jobs/sft.py +121 -0
- package/finetune/pyproject.toml +23 -0
- package/finetune/reward.py +610 -0
- package/finetune/train.py +611 -0
- package/finetune/uv.lock +4070 -0
- package/flake.lock +61 -0
- package/flake.nix +83 -0
- package/migrate-schema.ts +162 -0
- package/package.json +56 -0
- package/skills/qmdr/SKILL.md +172 -0
- package/skills/qmdr/references/mcp-setup.md +88 -0
- package/src/app/commands/collection.ts +55 -0
- package/src/app/commands/context.ts +82 -0
- package/src/app/commands/document.ts +46 -0
- package/src/app/commands/maintenance.ts +60 -0
- package/src/app/commands/search.ts +45 -0
- package/src/app/ports/llm.ts +13 -0
- package/src/app/services/llm-service.ts +145 -0
- package/src/cli.test.ts +963 -0
- package/src/collections.ts +390 -0
- package/src/eval.test.ts +412 -0
- package/src/formatter.ts +427 -0
- package/src/llm.test.ts +559 -0
- package/src/llm.ts +1990 -0
- package/src/mcp.test.ts +889 -0
- package/src/mcp.ts +626 -0
- package/src/qmd.ts +3330 -0
- package/src/store/collections.ts +7 -0
- package/src/store/context.ts +10 -0
- package/src/store/db.ts +5 -0
- package/src/store/documents.ts +26 -0
- package/src/store/maintenance.ts +15 -0
- package/src/store/path.ts +13 -0
- package/src/store/search.ts +10 -0
- package/src/store-paths.test.ts +395 -0
- package/src/store.test.ts +2483 -0
- package/src/store.ts +2813 -0
- package/test/eval-harness.ts +223 -0
- 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,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.
|