$npx -y skills add aviflombaum/claude-code-in-avinyc --skill searchSearch project documentation using qmd semantic search. Invoke with /avinyc:qmd-search <query> to find docs, plans, or indexed markdown content in your project.
| 1 | # QMD Search |
| 2 | |
| 3 | Search your project's indexed markdown documentation using qmd's MCP tools. This skill reads your project's qmd configuration to know which collections to search, constructs structured queries, and retrieves relevant documents. |
| 4 | |
| 5 | ## Step 1: Read Config |
| 6 | |
| 7 | Read `.claude/qmd.json` from the project root. |
| 8 | |
| 9 | If missing, tell the user: |
| 10 | |
| 11 | > qmd is not configured for this project. Run `/avinyc:qmd-configure` to set it up. |
| 12 | |
| 13 | Then STOP. |
| 14 | |
| 15 | Extract `project` name and `collections` — each has a name, path, and description. Pick the best collection for the query by matching against descriptions. If only one collection exists, use it. |
| 16 | |
| 17 | ## Step 2: Search via MCP |
| 18 | |
| 19 | Use the `mcp__qmd__query` tool with a structured query. This is the primary search method — it's faster than CLI (models stay warm between queries) and supports multi-type queries with intent disambiguation. |
| 20 | |
| 21 | ### Constructing the Query |
| 22 | |
| 23 | Every search should include at least two query types for best recall. The first query gets **2x weight** in fusion scoring, so put your best guess first. |
| 24 | |
| 25 | ```json |
| 26 | { |
| 27 | "searches": [ |
| 28 | { "type": "lex", "query": "2-5 exact keywords, no filler" }, |
| 29 | { "type": "vec", "query": "full natural language question" } |
| 30 | ], |
| 31 | "collections": ["<collection_name>"], |
| 32 | "limit": 10 |
| 33 | } |
| 34 | ``` |
| 35 | |
| 36 | ### Query Types |
| 37 | |
| 38 | | Type | Method | When to use | Writing tips | |
| 39 | |------|--------|-------------|--------------| |
| 40 | | `lex` | BM25 keyword | You know the exact terms in the docs | 2-5 terms. Exact phrases: `"rate limiter"`. Exclude: `-sports`. Code identifiers work. | |
| 41 | | `vec` | Vector semantic | You don't know the vocabulary | Full question. Be specific: "how does the auth system handle session expiry?" | |
| 42 | | `hyde` | Hypothetical doc | Complex topic, you can imagine the answer | Write 50-100 words of what the answer looks like, using vocabulary you expect in the result. | |
| 43 | |
| 44 | ### When to Use What |
| 45 | |
| 46 | | Situation | Query types to include | |
| 47 | |-----------|----------------------| |
| 48 | | Know exact terms | `lex` only | |
| 49 | | Don't know vocabulary | `vec` only | |
| 50 | | Best recall | `lex` + `vec` | |
| 51 | | Complex or broad topic | `lex` + `vec` + `hyde` | |
| 52 | | Ambiguous query (e.g., "performance" could mean web perf, team health, etc.) | Any combination + `intent` | |
| 53 | |
| 54 | ### Intent Disambiguation |
| 55 | |
| 56 | When a query term is ambiguous, add `intent` to steer all pipeline stages (expansion, reranking, snippet extraction): |
| 57 | |
| 58 | ```json |
| 59 | { |
| 60 | "searches": [ |
| 61 | { "type": "lex", "query": "performance" }, |
| 62 | { "type": "vec", "query": "how to improve page load speed" } |
| 63 | ], |
| 64 | "intent": "web page load times and Core Web Vitals", |
| 65 | "collections": ["project_docs"], |
| 66 | "limit": 10 |
| 67 | } |
| 68 | ``` |
| 69 | |
| 70 | Intent does not search on its own — it's a steering signal that disambiguates what you mean. |
| 71 | |
| 72 | ## Step 3: Interpret Results |
| 73 | |
| 74 | Results include `docid`, `score`, `file`, `title`, `context`, and `snippet`. |
| 75 | |
| 76 | | Score | Meaning | |
| 77 | |-------|---------| |
| 78 | | **0.7+** | Highly relevant — read this document | |
| 79 | | **0.5–0.7** | Worth reading if topic matches | |
| 80 | | **< 0.5 on all** | Try different query types or refine | |
| 81 | |
| 82 | ## Step 4: Retrieve Documents |
| 83 | |
| 84 | To read a full document from the results, use `mcp__qmd__get`: |
| 85 | |
| 86 | ```json |
| 87 | { "file": "#docid" } |
| 88 | ``` |
| 89 | |
| 90 | Or by file path: |
| 91 | |
| 92 | ```json |
| 93 | { "file": "collection_name/path/to/file.md" } |
| 94 | ``` |
| 95 | |
| 96 | For multiple related documents, use `mcp__qmd__multi_get` to batch retrieve: |
| 97 | |
| 98 | ```json |
| 99 | { "pattern": "collection_name/docs/*.md" } |
| 100 | ``` |
| 101 | |
| 102 | This is faster than reading files one at a time. |
| 103 | |
| 104 | ## Error Handling |
| 105 | |
| 106 | If MCP tools fail, diagnose the issue: |
| 107 | |
| 108 | | Error | Likely cause | Fix | |
| 109 | |-------|-------------|-----| |
| 110 | | `mcp__qmd__query` not available | MCP server not configured | Run `claude mcp add qmd -- qmd mcp` or add qmd to `.mcp.json`. Run `/avinyc:qmd-configure`. | |
| 111 | | MCP call returns error | Server not running or crashed | Run `qmd mcp` to verify. Check `qmd status`. | |
| 112 | | Collection not found | Config out of sync | Run `/avinyc:qmd-doctor` to diagnose. | |
| 113 | | No results | Index empty or stale | Run `qmd update && qmd embed` to rebuild. | |
| 114 | |
| 115 | ## CLI Fallback |
| 116 | |
| 117 | If MCP tools are unavailable, fall back to the CLI. The `qmd query` command supports structured queries via multiline strings: |
| 118 | |
| 119 | ```bash |
| 120 | qmd query $'lex: exact keywords here\nvec: natural language question here' -c <collection> --json -n 10 |
| 121 | ``` |
| 122 | |
| 123 | This single command subsumes `qmd search` (BM25 only) and `qmd vsearch` (vector only). Always use `--json` for parseable output. |
| 124 | |
| 125 | ## Fallback to Glob/Grep |
| 126 | |
| 127 | After 2 poor query attempts (different query types, refined terms), fall back to Glob/Grep on the collection's directory path from config. qmd can't find everything — sometimes a direct file search is faster. |