Commit Graph

268 Commits

Author SHA1 Message Date
Tobi Lutke
1765b6870d
docs: write changelog for 1.1.0
Query document format, lex phrase/negation syntax, standard node
shebang, collection management commands, and formal SYNTAX.md spec.
2026-02-22 11:09:36 -04:00
Tobi Lutke
c7e8ea02a5
test: restructure container smoke tests for interactive use
Replaces the inner test script with an outer driver that runs individual
podman/docker commands against a pre-built image. Tests sqlite-vec
loading and store unit tests under both node and bun runtimes.

Supports --build (image only), --shell (interactive), and -- CMD
(arbitrary command) for debugging install issues in isolation.
2026-02-22 11:09:36 -04:00
Tobi Lutke
0b57711d32
refactor: replace bash wrapper with standard #!/usr/bin/env node shebang
The qmd bin was a custom bash script that discovered node via hardcoded
fallback paths (mise, asdf, nvm, homebrew). This was nonstandard and
caused ABI mismatches when installed via bun (native modules compiled
for bun but executed with node).

Now uses the standard npm bin convention: dist/qmd.js with a node
shebang, added by the build script. The isMain guard resolves symlinks
so it works when npm/bun create symlinked bin entries.

Also converts all dynamic require() calls in tests to ESM imports, and
adds container-based smoke tests (test/smoke-install.sh) that verify
install + run under both node and bun via mise in a Debian container.
2026-02-22 11:09:36 -04:00
Tobias Lütke
a815b52ede
Merge pull request #214 from pcasaretto/fix/nix-build-deps 2026-02-22 10:42:57 -04:00
Tobi Lütke
8d73eda4de
data: add 48 sports acronym training examples
Covers UFC, NFL, NBA, NHL, MLB, F1, MLS, IMSA, WEC, NASCAR, PGA, ATP, WTA, FIFA.
Fixes query expansion failures like UFC → 'united fighting club'.
2026-02-22 09:37:25 -05:00
Tobi Lütke
6ac7c6837e
chore: release 1.0.8 2026-02-19 06:56:17 -05:00
Tobi Lütke
3b87e3e224
feat: query document format, lex phrase/negation syntax, training data
The 'query document' is now a first-class concept in QMD: a structured
document with typed sub-queries that combine for best recall.

## Query types
- lex:    BM25 keyword search with phrase and negation syntax
- vec:    Semantic vector search (natural language questions)
- hyde:   Hypothetical document (write the expected answer)
- expand: Auto-expand via local LLM (max 1, default for plain queries)

## Lex syntax
Full BM25 operator support:
  "exact phrase"     verbatim match, no prefix
  -term              exclude documents containing term
  -"exact phrase"   exclude documents containing phrase

Examples:
  "C++ performance" optimization -sports -athlete
  "connection pool" timeout -redis
  "machine learning" -sports -athlete

## MCP tool description rewritten
The 'query' tool description now fully teaches AI agents the query
document format, lex syntax, and strategy for combining types.
Includes worked examples including intent-aware lex (C++ performance,
not sports) which is critical for disambiguation in dense corpora.

## Unit tests
11 new lex parser tests covering:
- plain terms, quoted phrases, negation, combined
- intent-aware disambiguation (performance -sports -athlete)
- only-negation returns null (FTS5 constraint)
- empty/whitespace handling

## Training data
12 new intent-aware examples for next model training round:
- Real technical topics with lex phrase+negation combinations
- Covers: C++ perf, Python memory, DB connections, rate limiting,
  SQL optimization, ML overfitting, Docker, JWT, async/await,
  git conflicts, Kubernetes, React state
- Each shows how context/intent shapes lex query construction
  (e.g. performance with C++ context → -sports -athlete exclusions)
2026-02-19 06:52:58 -05:00
Tobi Lütke
2cb7b59152
fix(cli): print timing inline after each step, not on separate line 2026-02-19 06:11:21 -05:00
Tobi Lütke
24ffa4876b
feat(cli): show timing for expand, embed, and rerank steps
Each LLM invocation now prints elapsed time:
  Expanding query...
    (4.2s) → searching 6 queries
  Embedding 4 queries...
    (605ms)
  Reranking 40 chunks...
    (3.2s)
2026-02-19 06:08:02 -05:00
Tobi Lütke
a81f013126
fix(status): improve tips with subfolder context example and better update cmd 2026-02-19 06:01:53 -05:00
Tobi Lütke
bdf0c205a9
feat(status): add tips for missing context and update commands 2026-02-19 05:54:18 -05:00
Tobi Lütke
262c7d351c
refactor: remove context check command 2026-02-19 05:53:13 -05:00
Tobi Lütke
2b94e097d2
feat(cli): add collection management commands
New collection subcommands:
- show <name>           Show collection details
- update-cmd <name> [cmd]  Set pre-update command (runs before indexing)
- include <name>        Include in default queries (default)
- exclude <name>        Exclude from default queries

Collections with includeByDefault=false are skipped unless
explicitly named with -c flag.

CLI improvements:
- 'qmd collection' shows help instead of error
- 'qmd collection list' shows [excluded] tag
- Better command descriptions and examples
2026-02-19 05:46:07 -05:00
Tobi Lütke
07421de55f
feat(http): keep /search as alias for /query 2026-02-19 05:30:27 -05:00
Tobi Lütke
4649069e62
feat: add expand: type, rename to query, document syntax
BREAKING CHANGES:
- MCP tool renamed: structured_search → query
- HTTP endpoint renamed: /search → /query

New features:
- expand: type auto-expands via local LLM (max 1 per query)
- docs/SYNTAX.md formal grammar for query documents
- lex syntax: "phrase", -negation documented

Query types: lex, vec, hyde, expand
Default (no prefix) = expand (backwards compatible)
2026-02-18 22:22:50 -05:00
Tobi Lütke
de3a83a553
refactor: remove OR operator from lex queries
Simplify to just: terms, "phrases", and -negation
2026-02-18 22:17:52 -05:00
Tobi Lütke
77e4d8f378
refactor: remove single collection param, use collections array only
BREAKING: collection param removed from structured_search.
Use collections: ['name'] for single collection filter.
2026-02-18 22:16:15 -05:00
Tobi Lütke
efb39616e6
feat(lex): add query syntax for exact phrases, negation, and OR
Lex queries now support:
- "exact phrase" - quoted exact matching (no prefix)
- -term or -"phrase" - exclude from results
- term1 OR term2 - match either term

Semantic queries (vec/hyde) validate and reject these operators
with helpful error messages.

Examples:
  performance -sports     → matches "performance" excluding "sports"
  "machine learning"      → exact phrase match
  auth OR authentication  → matches either term
2026-02-18 22:14:09 -05:00
Tobi Lütke
d1ec31eab8
feat: add collections array filter + improve query writing docs
- structured_search now accepts collections[] for OR filtering
- Updated skill docs with detailed query writing guidance
- lex: 2-5 keywords, include synonyms, exact names
- vec: full natural language questions with context
- hyde: 50-100 word hypothetical answer passages
2026-02-18 22:09:24 -05:00
Tobi Lütke
6d6bdff09c
docs: simplify skill documentation 2026-02-18 22:00:24 -05:00
Tobi Lütke
19284ddb80
refactor(mcp): remove deprecated search tools, keep only structured_search
BREAKING CHANGE: MCP tools search, vector_search, deep_search removed.
Use structured_search with lex/vec/hyde queries instead.

- Remove search, vector_search, deep_search MCP tool registrations
- Update MCP instructions to focus on structured_search
- Update skill docs to reflect simplified API
- Rename test describes to reflect they test store functions
- CLI commands (qmd search, vsearch, query) unchanged for backwards compat
2026-02-18 21:50:25 -05:00
Tobi Lütke
db44e1a5bc
test: add comprehensive tests for structured search
32 tests covering:
- parseStructuredQuery parser (24 tests)
  - plain queries returning null
  - single/multiple prefixed queries
  - mixed plain + prefixed lines
  - error on multiple plain lines
  - whitespace handling
  - edge cases (colons in text, etc.)
- StructuredSubSearch type validation (3 tests)
- structuredSearch function basics (5 tests)
  - empty searches
  - no matches
  - limit/minScore options
2026-02-18 21:39:40 -05:00
Tobias Lütke
222dde153d
Merge pull request #220 from tobi/feat/structured-search
feat: add structured_search for LLM-provided query expansions
2026-02-18 22:36:20 -04:00
Tobi Lütke
8ebe5ab31b
feat(cli): add structured query syntax to qmd query
Lines prefixed with lex:, vec:, or hyde: route directly to
structured search, skipping automatic query expansion.

Examples:
  qmd query 'lex: CAP theorem'
  qmd query $'lex: keywords\nvec: natural language question'
  qmd query $'lex: terms\nvec: question\nhyde: hypothetical answer...'

Plain queries (single line, no prefix) still use automatic expansion.
Multiple plain lines without prefixes error with helpful message.

This lets CLI users leverage the same structured search as MCP,
useful when piping from scripts or when you know exactly what
query variations you want.
2026-02-18 19:58:41 -05:00
Tobi Lütke
bdec84a3e9
docs: use npm package name, clarify vec/hyde both use vector similarity 2026-02-18 19:34:08 -05:00
Tobi Lütke
0201710c2b
feat: add structured_search for LLM-provided query expansions
- New MCP tool: structured_search - lets capable LLMs provide their own
  lex/vec/hyde query variations instead of using local expansion model
- New REST endpoint: POST /search - same functionality without MCP protocol
- Updated skill docs to prioritize structured_search for LLM callers
- Added installation instructions for Claude Code, Desktop, and OpenClaw

Pipeline: lex→FTS, vec/hyde→batch embed, RRF fusion (first query 2x weight),
chunk + rerank, position-aware blending, dedup.

This is the recommended endpoint for capable LLMs - they generate better
query variations than the small local model, especially for domain-specific
or nuanced queries.
2026-02-18 19:05:49 -05:00
Tobi Lutke
648779a04d
fix(test): reset currentIndexName between test files
collections-config.test.ts set currentIndexName to "myindex" in its
last test but only restored env vars in afterEach — not the module
variable. Under bun test (single process), this leaked into mcp.test.ts,
causing it to look for myindex.yml instead of index.yml.

Fix: reset setConfigIndexName("index") in afterEach, and add defensive
reset in mcp.test.ts beforeAll.
2026-02-18 15:53:58 -04:00
Tobi Lutke
0697bc59d6
release: v1.0.7 2026-02-18 15:36:54 -04:00
Tobi Lutke
8cddbcb247
changelog: write 1.0.7 unreleased notes
LFM2 query expansion model, multiple collection filters,
XDG_CONFIG_HOME support, and JSON output fixes.
2026-02-18 15:36:31 -04:00
Paulo Casaretto
1033fffca6
fix: add python3 and cctools to nix build dependencies
node-gyp needs python3 to compile better-sqlite3, and on macOS it also
needs libtool from cctools to create static libraries. Without these,
`nix build` fails in the sandbox.
2026-02-18 10:22:32 -03:00
Tobias Lütke
4950f423cd
Merge pull request #200 from vincentkoc/vincentkoc-code/fix-cli-add-message 2026-02-18 08:43:15 -04:00
Tobias Lütke
e3b56959e3
Merge pull request #201 from vincentkoc/vincentkoc-code/chore-remove-no-lex-option 2026-02-18 08:42:57 -04:00
Tobias Lütke
67e2aab18c
Merge pull request #206 from tobi/liquidai-query-expansion 2026-02-18 08:42:01 -04:00
Tobias Lütke
b142be8cdc
Merge pull request #205 from tobi/mate/dataset-v3-improvements 2026-02-18 08:41:36 -04:00
Tobias Lütke
1a67e1a093
Merge pull request #208 from tobi/fix/json-output-and-index-paths 2026-02-17 20:27:49 -04:00
Tobi Lütke
1007b46fcc
fix: return empty JSON array when no search results with --json flag
Previously, 'qmd search --json' would output plain text 'No results found.'
when no matches were found, which is invalid JSON. Now it correctly outputs
an empty JSON array [] when using --json format.

Fixed in all search commands: search, vsearch, and query.
2026-02-17 10:46:31 -05:00
Tobi Lütke
00bcfbbd34
fix: resolve relative paths in --index flag to prevent malformed config paths
When using --index with relative paths like './index/my-project', the path was
stored directly as the config filename, resulting in paths like:
/home/user/.config/qmd/./index/my-project.yml

This caused 'no such file or directory' errors. Now relative paths are resolved
and normalized by replacing path separators with underscores.
2026-02-17 10:46:31 -05:00
Tobi Lütke
48f0917269
feat(finetune): hyde-first ordering, relative paths, structured format
Dataset improvements:
- Reorder output to put hyde first for better retrieval priming
- Convert absolute paths to relative paths in scripts
- Add convert_to_structured.py for structured data format
- Add qmd_expansion_v3_structured.jsonl with type/query objects
- Update schema.py with reorder_hyde_first() helper
- Verify data now validates hyde-first ordering

Training data regenerated with new ordering (100% validation success).
2026-02-17 06:31:35 -05:00
Tobi Lütke
57f7caa93b
feat: add LiquidAI LFM2 support for query expansion
Add training configuration and documentation for using LiquidAI's LFM2-1.2B
as an alternative base model for query expansion fine-tuning.

LFM2 benefits:
- 2x faster decode/prefill vs standard transformers
- Optimized for edge/on-device inference
- Good at agentic tasks, RAG, and data extraction

Changes:
- Add configs/sft_lfm2.yaml with LFM2-specific LoRA target modules
- Add jobs/sft_lfm2.py for HuggingFace Jobs training
- Update llm.ts with LFM2 GGUF model URIs
- Add documentation for LFM2 training workflow

LFM2 uses a hybrid architecture (convolutions + attention) requiring
different LoRA targets: q_proj, k_proj, v_proj, out_proj, in_proj, w1, w2, w3
2026-02-17 06:20:57 -05:00
Tobi Lütke
a282ce7a26
feat(finetune): improve query expansion dataset v3
Dataset improvements:
- fix_hyde.py: Replace generic template hyde entries with query-specific ones
  using GPT-4o-mini (removed 'comprehensive guide covers everything' pattern)
- fix_lex_filler.py: Remove filler words (overview, tutorial, guide, examples,
  documentation, best practices) that were padding rather than genuine search intent
- qmd_expansion_v3.jsonl: Improved dataset with 1,498 high-quality entries

Training data preparation:
- convert_to_chatml.py: Convert to ChatML format for LFM2.5 training
- verify_data.py: Validation script to ensure data quality
- train-lfm2/: Ready-to-use training data (90/10 train/val split)

Data quality metrics:
- 100% success rate (all entries properly formatted)
- Query length: 6-65 chars (avg: 29.3)
- Response length: 307-777 chars (avg: 539.5)
- All entries contain lex, vec, and hyde expansions
2026-02-17 06:19:59 -05:00
Vincent Koc
7fee9f904b chore(cli): remove unused no-lex flag from argument parser 2026-02-16 20:55:29 -08:00
Vincent Koc
e9b30bb821 fix(cli): use collection add command in empty collection hints 2026-02-16 20:51:54 -08:00
Tobi Lutke
640ac13cd0
fix: support multiple -c collection filters in search commands
Closes #191 (thanks @openclaw)
2026-02-16 14:03:53 -04:00
Tobi Lutke
8c2282c979
fix: respect XDG_CONFIG_HOME in collection config path
Closes #190 (thanks @openclaw)
2026-02-16 14:03:49 -04:00
Tobi Lutke
1781e7bf61
fix: pre-push hook writes to stderr, no interactive prompts
Git hooks can't rely on tty access. Remove all interactive
prompting — just validate and exit non-zero on failure.
2026-02-16 11:53:52 -04:00
Tobi Lutke
51c03d9445
release: v1.0.6 2026-02-16 09:08:34 -04:00
Tobi Lutke
63f3b68559
feat: show models in status, improve pre-push hook
- Move model info from --help to `qmd status` with live HuggingFace
  links derived from actual configured URIs
- Pre-push hook: handle non-interactive shells gracefully, resolve
  annotated tags correctly for CI checks
2026-02-16 09:08:28 -04:00
Tobi Lutke
8dd6cdcebf
fix: hide bun:sqlite import from tsc on Node.js builds
Concatenate the module specifier at runtime ('bun:' + 'sqlite') so tsc
doesn't try to resolve it during compilation on Node.js CI runners.
2026-02-16 08:56:02 -04:00
Tobi Lutke
6d399bc50a
release: v1.0.5 2026-02-16 08:47:23 -04:00
Tobi Lutke
e39848c030
chore: gitignore .claude/ 2026-02-16 08:47:20 -04:00