A thin wrapper around qmd that adds a graph-aware search layer for Obsidian-style wiki vaults.
qmd handles the heavy lifting — BM25 + vector + LLM reranking, all on-device, no cloud. qkb keeps that engine intact and stacks one extra trick on top: a typed wikilink/embed/reference graph that boosts retrieval when the right answer is one or two hops away from a strong lexical match.
Built for vaults where pages link to each other heavily — the karpathy LLM wiki, Andy Matuschak / Maggie Appleton-style note collections, a flight-planning kb, anything in that shape. If your corpus is flat (no wikilinks), qkb degrades cleanly to plain qmd.
npm install -g @agent-ops/qkb
qkb --helpThat's it. qmd, sqlite-vec, GraphQLite, and the GGUF models all get pulled or downloaded automatically on first use.
Two things, both opt-out:
-
A graph layer. Every wikilink
[[Foo]], embed![[Bar]], or reference becomes a typed edge in a SQLite graph table. At query time, the top-K post-RRF candidates seed a 1-hop graph expansion, and the expanded set is merged back into the rerank pool. RFC-0007 + RFC-0008 indocs/rfcs/for the details. -
qkbCLI shape. Same surface asqmd(search,vsearch,query,get,multi-get,mcp,status,update,embed,collection,context), plusgraph neighbors/graph queryfor direct graph navigation. The defaultqkb queryincludes graph expansion; pass--no-graphto matchqmd queryexactly.
The headline use case is calling qkb from a vault-query skill, the same way skills call qmd today. Two patterns:
Swap the retrieval step. Wherever the skill reads the hot cache + index + curated pages, replace it with a single qkb call:
qkb --index <your-index> query "$QUESTION" --graph -n 8 --files -c <your-collection>That returns the top 8 vault-relative file paths. Read those, synthesize, cite. You get ICAO-on-NOTAM-style transitive hits the curated-reading path misses.
Keep the original vault-query for AB testing. Mirror its structure but route through qkb. There's a working example in flight-planner-kb/.claude/skills/vault-query-graph/ if you want a template.
The skill body stays small — qkb does retrieval, the skill does synthesis + citation discipline.
Tested against a 4-question subset of flight-planner-kb, with subagents running each skill end-to-end:
| Metric | vault-query (curated reading) | vault-query-graph (qkb-backed) |
|---|---|---|
| Mean wall-clock | 67.6s | 59.8s (12% faster) |
| Recall vs expected docs | 32% | 65% (2× better) |
| Synthesis depth wins | 1 / 4 | 3 / 4 |
Full results in bench/results/skill-bench-vault-query-vs-graph.md. Underlying retrieval-only comparison across 7 modes (qkb-bm25 / qkb-vector / qkb-hybrid / qkb-graph / qmd-bm25 / qmd-vector / qmd-hybrid) in bench/results/full-bench-baseline.md.
- Multi-hop conceptual questions. "What are the international NOTAM coverage requirements?" — ICAO is the canonical answer but the ICAO page doesn't say "NOTAM." Graph traversal from NOTAM-Reform → ICAO lands it. Raw BM25 misses.
- Entity-relation queries. "Who built the FAA NMS API?" — the contractor page (CGI Federal) links to FAA NMS via wikilink. qkb finds both; vault-query has to know to look.
- Speed when your hot/index pages are large. qkb retrieves directly; vault-query has to chunk through a 30k-token
index.mdfirst.
- Exact-name lookups. "What is FAA NMS?" — BM25 alone wins; graph expansion is noise. qkb still returns the right answer, just doesn't add value here.
- Sparsely-linked corpora. If your vault has 50 wikilinks total, the graph signal is too thin to reshape rankings. The pipeline falls back to plain hybrid retrieval gracefully.
- Out-of-scope questions. "Engine-out emergency procedures" against a flight-planning vault — no amount of graph hops surfaces an answer. Both approaches correctly admit the gap; qkb-graph just explores more dead-end neighbors before giving up.
qkb is ~2k LoC of glue over @tobilu/qmd (the upstream qmd package on npm). qmd owns the state engine, schemas, and search; qkb owns the graph layer, CLI dispatch, and a handful of Obsidian-flavored utilities (qkb:// URL parsing, wikilink extraction, docid hashing) carved into src/internals/.
If you want the heavy documentation on indexing, embedding models, RRF tuning, MCP usage, score interpretation, output formats, AI-agent workflows, or anything else qmd already documents — read qmd's README. All of it applies here, byte-identically. qkb just adds --graph.
For the longer story:
- RFC-0007: Graph layer — schema, GraphQLite integration, typed edges
- RFC-0008: Hybrid graph queries — the four blending strategies, why we shipped edge-weighted 1-hop
- RFC-0009: Thin-wrapper architecture — how qkb consumes qmd via SDK without forking
MIT. Same as qmd. Built on qmd's shoulders — credit there.
