agentleFS
tristanphvntristanphvn/keel/skills/qmd/SKILL.md

qmd

Skill1 starsChanged 40 days agoMITView on GitHub

Set up local markdown search with qmd as one global index that every Claude Code profile and project on the machine shares. Adds the folders the user picks, then wires the active profile with the qmd MCP server, an edit hook, a scheduled refresh, and CLAUDE.md search guidance. Use for /keel:qmd, "set up qmd", or "search my notes/vault across projects".

  • Installs packages

23 other projects use a version of this.

Adopted by

Most recently taken up by

Used with

Projects with it also use defuddle, obsidian-bases and 6 more.

Other files people use alongside this one.

Files found in the same public projects as a version of this one, more often than they turn up anywhere else. Each project counts once, large collections count for less, and this file's own repository is left out.
  • HK-hubSkill

    defuddle

    Extract clean markdown content from web pages using Defuddle CLI, removing clutter and navigation to save tokens. Use instead of WebFetch when the user provides a URL to read or analyze, for online documentation, articles, blog posts, or any standard web page.

    Also in 4 projects that use this

  • wangzhuofengSkill

    obsidian-bases

    Create and edit Obsidian Bases (.base files) with views, filters, formulas, and summaries. Use when working with .base files, creating database-like views of notes, or when the user mentions Bases, table views, card views, filters, or formulas in Obsidian.

    Also in 4 projects that use this

  • jykimSkill

    obsidian-cli

    Interact with Obsidian using the official CLI to read, search, create, and manage notes, daily notes, tasks, properties, and more. Use when the user wants to query or manipulate vault content via the obsidian command.

    Also in 4 projects that use this

  • wangzhuofengSkill

    json-canvas

    Create and edit JSON Canvas files (.canvas) with nodes, edges, groups, and connections. Use when working with .canvas files, creating visual canvases, mind maps, flowcharts, or when the user mentions Canvas files in Obsidian.

    Also in 3 projects that use this

  • VercelSkill

    agent-browser

    Automates browser interactions for web testing, form filling, screenshots, and data extraction. Use when the user needs to navigate websites, interact with web pages, fill forms, take screenshots, test web applications, or extract information from web pages.

    Also in 4 projects that use this

  • VercelSkill

    vercel-react-best-practices

    React and Next.js performance optimization guidelines from Vercel Engineering. This skill should be used when writing, reviewing, or refactoring React/Next.js code to ensure optimal performance patterns. Triggers on tasks involving React components, Next.js pages, data fetching, bundle optimization, or performance improvements.

    Also in 3 projects that use this

  • +1 more from wangzhuofeng

The file

We split this skill into the rules it gives an agent

10 rules. 0 are common, 0 are distinctive, and 10 are very specific to this project.

  • 0

    Common

    Most of the 22 edited versions we read keep these.

  • 0

    Distinctive

    This author's own choices. Worth a look.

  • 10

    Very specific

    Tied to their project's names, files or tools. Probably skip.

  • Common
  • Distinctive
  • Very specific
  1. Very specific:

    Run the script with --dry-run and no other flags.

    line 17
  2. Very specific:

    Run <qmd> collection list with the absolute path the script printed, so the user sees what the index already holds.

    line 20
  3. Very specific:

    Ask whether to index this profile's Claude Code auto-memory too (--memory).

    line 27
  4. Very specific:

    Run with --dry-run and the chosen flags, then read the output.

    line 32
  5. Very specific:

    Run these for each profile you wired, with P="${CLAUDE_CONFIG_DIR:-$HOME/.claude}".

    line 76
  6. Very specific:

    Run claude mcp remove -s user qmd.

    line 78
  7. Very specific:

    Delete the PostToolUse entry whose command runs on-edit-hook.sh from $P/settings.json.

    line 79
  8. Very specific:

    Delete the block between the keel:qmd markers in $P/CLAUDE.md.

    line 80
  9. Very specific:

    Delete the backups setup left next to those files: $P/settings.json.qmd-backup-*, $P/CLAUDE.md.qmd-backup-*, and, when the script merged …

    line 81
  10. Very specific:

    Delete reconcile.sh, on-edit-hook.sh, and any *.qmd-backup-* files from ${XDG_CONFIG_HOME:-$HOME/.config}/qmd/, and the log folder, …

    line 86

“Common” is measured: kept by at least 6 in 10 of the 22 edited versions of this file we could read. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.

Keep what fits and drop the rest. Your version, ready for your agents.
Files
SKILL.md

qmd

Set up qmd so agents in every profile and project can search the user's markdown through one index. qmd keeps that index at its default locations, ${XDG_CONFIG_HOME:-$HOME/.config}/qmd/index.yml for the collection list and ~/.cache/qmd for the database and models. Nothing here sets QMD_CONFIG_DIR or makes a per-profile index.

scripts/setup-qmd.sh makes every change and is safe to re-run. Your job is to choose its inputs with the user, run it, check the result, and report. Call it as bash "${CLAUDE_SKILL_DIR}/scripts/setup-qmd.sh".

Steps

1. Detect

  1. Run the script with --dry-run and no other flags. It finds qmd on PATH, then at ~/.bun/bin/qmd, then under $(npm prefix -g)/bin.
  2. Exit code 3 means qmd is missing. Ask the user before you install it. Offer bun install -g @tobilu/qmd when command -v bun succeeds, else npm install -g @tobilu/qmd. Install only on a yes, then run step 1 again.
  3. Tell the user which profile the run wires, from echo "${CLAUDE_CONFIG_DIR:-$HOME/.claude}". Each profile needs its own run. The index is shared, so a second profile's run needs no --root.
  4. Run <qmd> collection list with the absolute path the script printed, so the user sees what the index already holds. If it fails with node: not found or bun: not found, the runtime qmd was installed with is not on PATH. Fix that before you go on.
  5. Look for an earlier qmd setup. List ~/Library/LaunchAgents/*qmd* on macOS or crontab -l | grep qmd elsewhere, and grep the profile's settings.json for qmd and on-edit-hook. The dry run also warns about another LaunchAgent that mentions qmd, and keeps a hook that already runs on-edit-hook.sh instead of adding a second one. If you find a scheduler or hook this script did not make, ask the user whether to remove it or keep it before the real run.

2. Pick what to index

  1. Run the script with --discover. It counts *.md under each folder in $HOME and one level below. It skips node_modules, .git, dist, build, vendor, and dot folders, and at the top level also Library, Applications, Movies, Music, and Pictures. Folders it cannot read are left out of the counts.
  2. Suggest roots from that list and ask with AskUserQuestion, multiSelect: true, at most four options. Prefer one collection per root folder, such as a code folder with one subfolder per project, so a new project under it gets indexed without a re-run. The script skips a root that sits inside an existing collection.
  3. Ask whether to index this profile's Claude Code auto-memory too (--memory). It adds <profile>/projects with the pattern */memory/**/*.md and ignores the -private-tmp-* and -tmp-* project folders that scratch sessions leave.
  4. Offer a one-line description per root. qmd shows it to agents next to search results.

3. Run

Run with --dry-run and the chosen flags, then read the output. If it would change anything the user did not choose, stop and ask. Otherwise run the same command without --dry-run.

FlagEffect
--root PATH[:NAME]Add a collection of every *.md under PATH. NAME defaults to the folder name, lowercased, with each character outside a-z0-9_- turned into -. A PATH that is itself a folder is never split at a colon. Repeat per root.
--context NAME:TEXTAttach a description to collection NAME. Repeat per collection. Pass an explicit PATH:NAME on the matching --root, so the two names agree.
--memoryAdd this profile's auto-memory folders as <profile-dir-name>-memory. When another folder already holds that name, as with a second profile also named .claude, it uses <parent-dir-name>-<profile-dir-name>-memory. When both names are taken it warns and adds nothing.
--no-scheduleSkip the scheduled refresh. QMD_SCHEDULE=0 does the same.
--dry-runPrint what would change and write nothing.
--discoverList folders under $HOME by markdown file count, then exit.

QMD_LAUNCHD_LABEL overrides the LaunchAgent label, local.qmd.reconcile by default.

4. Verify

  1. <qmd> collection list shows each chosen root, or the script printed why it skipped one.
  2. claude mcp get qmd finds the server. Without the claude CLI, check that mcpServers.qmd exists in the .claude.json path the script printed.
  3. The profile's settings.json has a PostToolUse entry whose command runs on-edit-hook.sh, as the script's PostToolUse hook line reported.
  4. tail -n 5 on the log path the script printed shows a start (...) line. It may come from an earlier run whose embed is still going, since a run that finds another one holding the lock only leaves a reconcile.rerun file in the log folder and logs nothing. Either a start line without a later done, or that file, passes this check.
  5. <qmd> status shows documents waiting for embeddings, and its Device section shows whether qmd found a GPU.

5. Report

Tell the user what each collection holds, which profile you wired, and that Claude Code needs a restart to load the MCP server and hook. Give the two commands the script printed for watching progress. On a CPU-only machine the first embed can take hours for about 1000 documents. Searches work before it ends, and lexical results come first.

What the script writes

WhatWhere
Collectionsindex.yml, through qmd collection add and qmd context add only. collection add builds the keyword index for that root before it returns, which takes a while on a big root. It skips a name that exists and a path inside an existing collection. The one direct edit adds an ignore: list to the memory collection, since the CLI cannot set one. qmd keeps that list when it rewrites the file.
reconcile.sh, on-edit-hook.shNext to index.yml. reconcile.sh runs qmd update then qmd embed at nice 15, one run at a time, with up to five passes while edits keep arriving. qmd's launcher runs under node or bun and launchd passes a bare PATH, so it puts qmd's own folder, the folders where setup found node and bun, ~/.bun/bin, /usr/local/bin, and /opt/homebrew/bin on PATH. It logs to ~/Library/Logs/qmd/reconcile.log on macOS, else ${XDG_STATE_HOME:-~/.local/state}/qmd/reconcile.log. The hook starts it in the background when a Write or Edit touches a .md file inside a collection, and returns at once.
MCP server qmdUser scope, through claude mcp add -s user qmd -- <qmd> mcp. Claude Code keeps it in $CLAUDE_CONFIG_DIR/.claude.json when that variable is set, else ~/.claude.json. Without the claude CLI the script merges the entry into that file itself.
PostToolUse hook<profile>/settings.json, matcher Write|Edit, timeout 10.
Search guidance<profile>/CLAUDE.md, between <!-- keel:qmd start --> and <!-- keel:qmd end -->. A re-run replaces the block in place.
Scheduled refreshmacOS gets ~/Library/LaunchAgents/<label>.plist, every 1800 s, RunAtLoad, Nice 15, LowPriorityIO. The script loads it with launchctl bootstrap when launchctl print gui/$UID/<label> fails. When the agent is loaded and the plist content changed, it unloads it with launchctl bootout and loads it again. Other systems get a cron line to add by hand.

The first reconcile.sh run starts in the background, from the LaunchAgent or from the script, so setup never waits for embeddings.

Before it rewrites settings.json, CLAUDE.md, .claude.json, index.yml, reconcile.sh, or on-edit-hook.sh, the script copies the old file next to it as <file>.qmd-backup-<timestamp>. The plist's backup goes next to reconcile.sh, because launchd may load any file in LaunchAgents. A rewrite follows a symlink to its target and keeps the file's mode. A config file that is not valid JSON stops the run with an error that names it, and nothing in that file changes.

The CLAUDE.md block's rerank line follows the Device section of qmd status, which takes under a second. With GPU: none it tells agents to always pass rerank: false, because on a CPU-only Intel i7 a reranked query took over 240 s, while lex took about 3 s and vec about 7 s. With a GPU it leaves the line out. When status names neither, as under --dry-run, the line says to pass rerank: false when qmd status shows no GPU. A re-run on new hardware rewrites the line.

Undo

Run these for each profile you wired, with P="${CLAUDE_CONFIG_DIR:-$HOME/.claude}".

  1. Run claude mcp remove -s user qmd. Without the claude CLI, delete mcpServers.qmd from $CLAUDE_CONFIG_DIR/.claude.json when that variable is set, else from ~/.claude.json.
  2. Delete the PostToolUse entry whose command runs on-edit-hook.sh from $P/settings.json.
  3. Delete the block between the keel:qmd markers in $P/CLAUDE.md.
  4. Delete the backups setup left next to those files: $P/settings.json.qmd-backup-*, $P/CLAUDE.md.qmd-backup-*, and, when the script merged the MCP entry itself, .claude.json.qmd-backup-* next to the .claude.json path it printed. When one of these files is a symlink, its backup sits next to the link's target.

Then once per machine:

  1. On macOS, run launchctl bootout gui/$(id -u)/<label> and delete ~/Library/LaunchAgents/<label>.plist. The label is local.qmd.reconcile unless QMD_LAUNCHD_LABEL set another at setup. Elsewhere, remove the cron line.
  2. Delete reconcile.sh, on-edit-hook.sh, and any *.qmd-backup-* files from ${XDG_CONFIG_HOME:-$HOME/.config}/qmd/, and the log folder, ~/Library/Logs/qmd on macOS or ${XDG_STATE_HOME:-$HOME/.local/state}/qmd elsewhere.
  3. To drop the index too, run qmd collection remove <name> for each collection, or delete index.yml and ~/.cache/qmd, which also holds the downloaded models.

Download now (ZIP)

Does it work?

Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.

No reviews yet

People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.

  • It worked
  • Partly
  • It didn't
What did you use it for? e.g. Reviewing pull requests in a Rails app

Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.

Your trail

Files you open will collect here, so you can find them again.

Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.

Now do this for your own.

Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.