
Intro
People say note management is just a matter of reading, writing, and finding things easily — but in truth each of those steps is complicated enough that "simple" hardly applies. Reading and writing in particular get a lot of attention in formal education, so we understand their importance and can claim some degree of fluency. Finding, not so much. This post introduces QMD, a tool that lets you find notes by meaning. Personally, it's a tool I've been putting to good use alongside Obsidian.
One caveat: QMD runs locally, so your machine needs to have at least reasonable specs.
Types of Search and Semantic Search
File search methods can be divided broadly into two kinds.
graph TD
A[파일 검색 방식] --> B[Lexical Search<br/>#40;Keyword search#41;]
A --> C[Semantic Search]Lexical searchfinds things that contain the search term. It's the kind of search that intuitively comes to mind. BM25 is the classic example.Semantic searchfinds things whose meaning is close to the search term. There are various ways to search by meaning, but in Personal Knowledge Management the approach you'll usually encounter is one based on an embedding model.
Using an embedding model works like this.
graph LR
A[📄📄📄<br/>노트들] --> B[🧠<br/>Embedding Model]
C[🔍<br/>검색어] --> B
B --> D["[0.2, -0.5, ...] × N<br/>벡터 집합"]
B --> E["[0.3, -0.4, ...]<br/>쿼리 벡터"]
D --> M(( ))
E --> M
M -- cosine similarity --> F[📄<br/>유사한 노트]
classDef plain fill:none,stroke:none
class A,B,C,F,M plainEmbedding a note turns it into a vector. A good embedding model maps similar meanings to similar vectors and different meanings to different vectors. Then, when a search term comes in, the term is likewise turned into a vector and cosine similarity is used to find the most similar notes.
QMD
What Is QMD
I'd wanted to search my Obsidian notes by meaning for a long time, and in fact the Smart Connections community plugin made that possible. But at some point specifying the embedding model became a paid feature, and unless you pay, Smart Connections is a mess — because the embedding model you're allotted for free performs very poorly on Korean. While I was looking for an alternative, QMD came along.
QMD is a local markdown search tool built by Shopify founder Tobi Lütke. It runs as a CLI, indexing (tokenizing or embedding) your markdown notes locally so they can be searched. It offers a variety of search modes, too: BM25, vector search, and even hybrid search that combines an LLM with BM25 plus vector search. All of it runs on local models.
Honestly, for embedding at least, I would have liked to use OpenAI's or Voyage AI's embedding models. There's a cost, but embedding isn't that expensive, and it doesn't tax your local machine. Either way, running entirely locally can be an advantage when you're using it somewhere security-conscious, like at a company.
QMD is also specialized for markdown, so it chunks in a markdown-friendly way. That is, when a document gets long, it splits it up as it embeds. But if you coldly (?) cut the document at a fixed token count, you can end up splitting content in the middle of a sentence. So it uses markdown elements like headings to chunk within the markdown structure.
Use QMD for Semantic Search Only
Be aware that QMD's lexical search method, BM25, doesn't work well for Korean as-is. For example, if you have a note named 안보위기 (security crisis), searching 안보 finds it but 위기 doesn't. That's because Korean, unlike English, is sometimes written without spaces between words. It's a problem that arises during tokenization, and there are projects like kQMD meant to solve it. (For what it's worth, the same problem occurs with the Obsidian plugin Omnisearch.) It's possible QMD will support a fix for this down the line, though.
Given the situation, I leave lexical search not to QMD but to an AI agent that searches files on its own. In other words, in that case Claude Code ends up using Grep or Glob. I only use QMD's semantic search when I need meaning-based search. This sort of hybrid approach may look inefficient, but it works for now, so I'm leaving it alone. Realistically, a PKM setup has at most 10,000 notes.
Using QMD
Installation
For installing qmd, see https://github.com/tobi/qmd. Windows users may find it a bit of a headache.
Adding a Collection
QMD manages sets of markdown notes in units called collections. So to use an Obsidian vault with QMD, you need to add the vault folder as a collection. In your terminal, navigate to the Obsidian vault folder and run qmd collection add . --name pkm to add the vault folder as a collection named pkm.
Change the Embedding Model
The embedding model set by default is embeddinggemma-300M-Q8_0, which has the problem of poor Korean performance. So you'll want to change the embedding model. The Qwen3 embedding model works well; here's how:
export QMD_EMBED_MODEL="hf:Qwen/Qwen3-Embedding-0.6B-GGUF/Qwen3-Embedding-0.6B-Q8_0.gguf"
qmd embed -f
Since you're changing an environment variable with export, you'll need to register it in ~/.zshrc or whatever shell config you use so the embedding model is set automatically when the shell starts. Also, because the embedding model has changed, if you already embedded with embeddinggemma you'll need to force a re-embed with qmd embed -f. (If none of this makes sense, just ask an AI agent and it'll handle it.)
Also, the embeddings in a collection aren't updated automatically just because the files changed. So you'll want to set up a cronjob that updates the collection and then embeds. In my case I've set the following command to run around 2 a.m. Embedding on every single file change doesn't seem necessary.
qmd update && qmd embed
You can check whether it worked with qmd status.
Since it's a local embedding model, you may have doubts about its performance. I cover that in Qwen3-Embedding 0.6B Embedding Performance.
Using QMD as Openclaw's Memory Engine
Openclaw users can also use qmd as their memory engine. Openclaw saves bits of conversational context to memory as you talk, recorded as markdown files.
Those need to be retrieved via semantic search. Honestly, while you still have few conversations, you don't need it — you could just hand the AI the whole set of files. But as the number of entries grows, you need to pull only what's relevant, and to do that you need to pull based on meaning. That's where qmd comes in, and the method is written up at https://docs.openclaw.ai/concepts/memory-qmd. If you wire it up successfully, running
qmd status will show memory-root-main, memory-alt-main, and memory-dir-main added as collections.
Letting an AI Agent Use QMD on Your Obsidian Vault
QMD supports MCP. So if you want Claude Code or similar to use the notes you've embedded with QMD, you can hook it up via MCP. For example, with Claude Desktop, the following configuration sets up the MCP connection.
{
"mcpServers": {
"qmd": {
"command": "qmd",
"args": ["mcp"]
}
}
}
Wrapping Up
The era of full-blown local LLMs may still be some way off, but when it comes to embedding models, I suspect we'll soon reach a level that's satisfying even running on a local PC. QMD is a great tool that lets an AI agent search my Obsidian vault by meaning, with no fees and no annoying API setup. I recommend giving it a try.