OptionalResearchVersion 1.0.0

Qmd Skill for Hermes Agent: Local Hybrid Search Guide

Hybrid local search over notes, docs, and transcripts.

Written by Neura Market from the official Hermes Agent documentation for Qmd. Commands, paths, and version numbers are reproduced from the source unchanged.

Read the official documentation

Qmd is an optional Hermes Agent skill that gives the agent a local, on-device search engine over your markdown notes, documentation, meeting transcripts, and other text files. It combines keyword matching, semantic vector search, and LLM reranking, with no cloud dependency. Reach for it when you want the agent to answer questions from your own corpus rather than the open web, or when you are building a personal knowledge base the agent can query.

What it does

Qmd indexes directories you register as collections, then answers queries against that index in three escalating modes. A keyword mode uses BM25 over SQLite FTS5 for exact terms and identifiers. A vector mode uses an embedding model for conceptual questions. A hybrid mode runs both, expands the query with a small language model, fuses the results, and reranks the top candidates with a dedicated reranker model. All of this runs on your machine. The skill wraps the upstream qmd tool by Tobi Lütke, which is MIT licensed, and the skill itself is MIT licensed, version 1.0.0, authored by Hermes Agent + Teknium.

The practical value is that the agent can search your notes the way you would, not just grep them. You ask "what decisions were made about the database migration" and the pipeline finds the relevant passages even when the wording differs. You ask for handleError async and the fast keyword path returns in a fraction of a second without loading any models.

Before you start

Qmd is an optional skill, installed on demand from optional-skills/research/qmd. It supports macOS and Linux only.

You need Node.js 22 or newer. The source gives install paths for both platforms:

# Check version
node --version  # must be >= 22

# macOS — install or upgrade via Homebrew
brew install node@22

# Linux — use NodeSource or nvm
curl -fsSL https://deb.nodesource.com/setup_22.x | sudo -E bash -
sudo apt-get install -y nodejs
# or with nvm:
nvm install 22 && nvm use 22

On macOS there is a second prerequisite: the system SQLite lacks extension loading, so you install Homebrew's SQLite. This is a macOS-only step.

brew install sqlite

Then install qmd globally, either with npm or Bun:

npm install -g @tobilu/qmd
# or with Bun:
bun install -g @tobilu/qmd

The first run auto-downloads three local GGUF models, roughly 2GB in total. The source lists them explicitly:

ModelPurposeSize
embeddinggemma-300M-Q8_0Vector embeddings~300MB
qwen3-reranker-0.6b-q8_0Result reranking~640MB
qmd-query-expansion-1.7BQuery expansion~1.1GB

Verify the install before doing anything else:

qmd --version
qmd status

In practice, the model download is the slowest part of setup. Budget for it once, and know that it is a one-time operation. If you are on a metered connection or a machine with little free disk, plan around it.

Quick reference

The source provides a compact command table. Speeds are the source's own figures.

CommandWhat It DoesSpeed
qmd search "query"BM25 keyword search (no models)~0.2s
qmd vsearch "query"Semantic vector search (1 model)~3s
qmd query "query"Hybrid + reranking (all 3 models)~2-3s warm, ~19s cold
qmd get Retrieve full document contentinstant
qmd multi-get "glob"Retrieve multiple filesinstant
qmd collection add --name Add a directory as a collectioninstant
qmd context add "description"Add context metadata to improve retrievalinstant
qmd embedGenerate/update vector embeddingsvaries
qmd statusShow index health and collection infoinstant
qmd mcpStart MCP server (stdio)persistent
qmd mcp --http --daemonStart MCP server (HTTP, warm models)persistent

Setup workflow

1. Add collections

A collection is a directory qmd indexes. Point it at each corpus you want searchable:

# Add a notes directory
qmd collection add ~/notes --name notes

# Add project docs
qmd collection add ~/projects/myproject/docs --name project-docs

# Add meeting transcripts
qmd collection add ~/meetings --name meetings

# List all collections
qmd collection list

Keep collection names short and stable. You will reference them later when scoping searches and when writing context descriptions.

2. Add context descriptions

Context metadata tells the search engine what a collection is about. The source states this significantly improves retrieval quality, so treat it as part of setup rather than an optional polish step:

qmd context add qmd://notes "Personal notes, ideas, and journal entries"
qmd context add qmd://project-docs "Technical documentation for the main project"
qmd context add qmd://meetings "Meeting transcripts and action items from team syncs"

Write the description as if briefing a new colleague on what lives in that folder. Vague descriptions give the retriever less to work with.

3. Generate embeddings

qmd embed

This processes every document in every collection and generates vector embeddings. Re-run it after adding new documents or collections. If you skip this step, vector and hybrid search have nothing to match against.

4. Verify

qmd status   # shows index health, collection stats, model info

Search patterns

Fast keyword search (BM25)

Use this for exact terms, code identifiers, names, and known phrases. No models load, so results are near-instant.

qmd search "authentication middleware"
qmd search "handleError async"

Semantic vector search

Use this for natural language questions and conceptual queries. The embedding model loads on the first query, which the source puts at about 3 seconds.

qmd vsearch "how does the rate limiter handle burst traffic"
qmd vsearch "ideas for improving onboarding flow"

Hybrid search with reranking

This is the highest-quality mode. It uses all three models: query expansion, parallel BM25 and vector retrieval, then reranking. Reserve it for queries where the answer matters.

qmd query "what decisions were made about the database migration"

Structured multi-mode queries

You can combine search types in one query. The source shows a BM25 term alongside a vector concept, and a variant with query expansion:

# BM25 for exact term + vector for concept
qmd query $'lex: rate limiter\nvec: how does throttling work under load'

# With query expansion
qmd query $'expand: database migration plan\nlex: "schema change"'

Query syntax in lex/BM25 mode

The keyword mode supports a small operator set:

SyntaxEffectExample
termPrefix matchperf matches "performance"
"phrase"Exact phrase"rate limiter"
-termExclude termperformance -sports

HyDE (hypothetical document embeddings)

For complex topics, write out what you expect the answer to look like and let the pipeline embed that instead of the question:

qmd query $'hyde: The migration plan involves three phases. First, we add the new columns without dropping the old ones. Then we backfill data. Finally we cut over and remove legacy columns.'

Scoping to collections

Restrict a search to one collection when you know where the answer lives:

qmd search "query" --collection notes
qmd query "query" --collection project-docs

Output formats

qmd search "query" --json        # JSON output (best for parsing)
qmd search "query" --limit 5     # Limit results
qmd get "#abc123"                # Get by document ID
qmd get "path/to/file.md"       # Get by file path
qmd get "file.md:50" -l 100     # Get specific line range
qmd multi-get "journals/*.md" --json  # Batch retrieve by glob

When the agent is the consumer, --json is the sensible default because it parses cleanly. When you are reading results yourself, the plain output is easier on the eye.

MCP integration

Qmd exposes an MCP server, and the source calls this the preferred integration. Once configured, Hermes Agent gets qmd tools through its native MCP client without loading the skill each time.

Option A: stdio mode

Add this to ~/.hermes/config.yaml:

mcp_servers:
  qmd:
    command: "qmd"
    args: ["mcp"]
    timeout: 30
    connect_timeout: 45

This registers the tools mcp_qmd_search, mcp_qmd_vsearch, mcp_qmd_deep_search, mcp_qmd_get, and mcp_qmd_status. The tradeoff is that models load on the first search call, which the source puts at about 19 seconds cold, then stay warm for the session. That is acceptable for occasional use.

Option B: HTTP daemon mode

Start the daemon separately so models stay warm in memory:

# Start daemon (persists across agent restarts)
qmd mcp --http --daemon

# Runs on http://localhost:8181 by default

Then point Hermes Agent at it over HTTP:

mcp_servers:
  qmd:
    url: "http://localhost:8181/mcp"
    timeout: 30

The tradeoff is roughly 2GB of RAM while running, but every query is fast at about 2 to 3 seconds. This is the right choice if you search your knowledge base often.

Keeping the daemon running

macOS (launchd)

cat > ~/Library/LaunchAgents/com.qmd.daemon.plist << 'EOF'
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN"
  "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
  <key>Label</key>
  <string>com.qmd.daemon</string>
  <key>ProgramArguments</key>
  <array>
    <string>qmd</string>
    <string>mcp</string>
    <string>--http</string>
    <string>--daemon</string>
  </array>
  <key>RunAtLoad</key>
  <true/>
  <key>KeepAlive</key>
  <true/>
  <key>StandardOutPath</key>
  <string>/Users/YOU/.hermes/cache/scratch/qmd-daemon.log</string>
  <key>StandardErrorPath</key>
  <string>/Users/YOU/.hermes/cache/scratch/qmd-daemon.log</string>
</dict>
</plist>
EOF

launchctl load ~/Library/LaunchAgents/com.qmd.daemon.plist

Replace YOU in the log paths with your macOS username before loading the plist.

Linux (systemd user service)

mkdir -p ~/.config/systemd/user

cat > ~/.config/systemd/user/qmd-daemon.service << 'EOF'
[Unit]
Description=QMD MCP Daemon
After=network.target

[Service]
ExecStart=qmd mcp --http --daemon
Restart=on-failure
RestartSec=10
Environment=PATH=/usr/local/bin:/usr/bin:/bin

[Install]
WantedBy=default.target
EOF

systemctl --user daemon-reload
systemctl --user enable --now qmd-daemon
systemctl --user status qmd-daemon

MCP tools reference

Once connected, these tools are available under the mcp_qmd_* prefix:

MCP ToolMaps ToDescription
mcp_qmd_searchqmd searchBM25 keyword search
mcp_qmd_vsearchqmd vsearchSemantic vector search
mcp_qmd_deep_searchqmd queryHybrid search + reranking
mcp_qmd_getqmd getRetrieve document by ID or path
mcp_qmd_statusqmd statusIndex health and stats

The MCP tools accept structured JSON queries for multi-mode search:

{
  "searches": [
    {"type": "lex", "query": "authentication middleware"},
    {"type": "vec", "query": "how user login is verified"}
  ],
  "collections": ["project-docs"],
  "limit": 10
}

CLI usage without MCP

If MCP is not configured, the agent can still drive qmd through the terminal. The source shows the pattern for a query and for setup tasks:

terminal(command="qmd query 'what was decided about the API redesign' --json", timeout=30)

For setup and management, always use the terminal:

terminal(command="qmd collection add ~/Documents/notes --name notes")
terminal(command="qmd context add qmd://notes 'Personal research notes and ideas'")
terminal(command="qmd embed")
terminal(command="qmd status")

How the search pipeline works

Knowing the internals helps you pick a mode rather than guessing.

  1. Query expansion. A fine-tuned 1.7B model generates two alternative queries. The original gets 2x weight in fusion.
  2. Parallel retrieval. BM25 over SQLite FTS5 and vector search run simultaneously across all query variants.
  3. RRF fusion. Reciprocal Rank Fusion with k=60 merges results. The top rank gets a +0.05 bonus, ranks 2 and 3 get +0.02.
  4. LLM reranking. The qwen3-reranker scores the top 30 candidates on a 0.0 to 1.0 scale.
  5. Position-aware blending. Ranks 1 to 3 use 75% retrieval and 25% reranker. Ranks 4 to 10 use 60/40. Ranks 11 and beyond use 40/60, trusting the reranker more for the long tail.

Documents are chunked at natural break points such as headings, code blocks, and blank lines, targeting about 900 tokens with 15% overlap. Code blocks are never split mid-block.

Best practices

  1. Always add context descriptions. The source says qmd context add dramatically improves retrieval accuracy, so describe what each collection contains.
  2. Re-embed after adding documents. qmd embed must be re-run when new files land in collections.
  3. Use qmd search for speed. For code identifiers and exact names, BM25 is instant and needs no models.
  4. Use qmd query for quality. For conceptual questions or when the best possible results matter, use hybrid search.
  5. Prefer MCP integration. Once configured, the agent gets native tools without loading the skill each time.
  6. Daemon mode for frequent users. If you search your knowledge base regularly, the HTTP daemon setup is the better fit.
  7. Put the most important query first in structured search. The first query gets 2x weight, so lead with the one you are most certain about.

When not to use it

The source does not name direct alternatives, but its own guidance implies the boundaries. If you only need exact-string lookup, the BM25 path is the right tool and the heavier modes add nothing. If your content is not text-based, qmd has nothing to index. If you are on Windows, the skill is not supported. And if you have not set up collections and embeddings, there is nothing to search, so run setup first.

Limits and gotchas

  • First-run download. About 2GB of GGUF models downloads automatically on first use. It is a one-time operation, but it is not instant.
  • Cold start latency. About 19 seconds when models are not in memory. The fixes are HTTP daemon mode, qmd search when models are not needed, or stdio MCP mode which loads on first search and stays warm for the session.
  • macOS extension loading. If you see "unable to load extension", install Homebrew SQLite with brew install sqlite and make sure it is on PATH ahead of the system SQLite.
  • No collections found. Add directories with qmd collection add --name and then index them with qmd embed.
  • Multilingual content. For CJK or other non-English material, set the QMD_EMBED_MODEL environment variable to a multilingual model:
export QMD_EMBED_MODEL="your-multilingual-model"
  • Data storage. The index and vectors live at ~/.cache/qmd/index.sqlite. Models are auto-downloaded to a local cache on first run. There are no cloud dependencies; everything runs locally.

What pairs with it

Qmd sits naturally beside the obsidian skill if your notes live in a vault, and beside arxiv if your research reading needs to be searchable alongside your own writing. The hermes-agent skill is the general reference for the runtime itself. Upstream, the project lives at tobi/qmd, and the changelog tracks releases.

Skills the docs pair this with

More Research skills