Search the vault for notes matching a query. Backed by `POST /search/simple/` — works against both the Obsidian Local REST API (lexical only) and vault-storage (lexical + semantic). Use when the user says /vault-search, asks to find notes matching a phrase, or wants to locate the right note to read before answering a question. Returns ranked hits with snippets.
Install
npx skillscat add uhop/vault-storage/vault-search Install via the SkillsCat registry.
Vault — search
Run a single search query against the vault and return ranked hits. The dominant entry point for "is there already a note about X?" — cheaper than reading _index.md and skimming, more accurate than guessing filenames.
Invocation
/vault-search <query> # lexical, limit 20
/vault-search <query> --semantic # embedding-NN (vault-storage only)
/vault-search <query> --limit=N # cap results (1..100)Combinable: /vault-search auth flow --semantic --limit=10.
<query> may contain spaces and quotes; pass it through verbatim. Don't strip or normalize.
Procedure
Parse args from
$ARGUMENTS:- Extract
--semanticflag →mode=semanticelsemode=lexical. - Extract
--limit=N→ integer; default 20; clamp to[1, 100]. - The remaining tokens (joined with single spaces) are the query.
- Extract
Call the endpoint via vault-curl:
vault-curl /search/simple/ -X POST -G \ --data-urlencode "query=$QUERY" \ --data-urlencode "mode=$MODE" \ --data-urlencode "limit=$LIMIT"-G --data-urlencodeproduces a POST with the params as URL query (the shape the endpoint expects).Parse the JSON response. Shape:
[{filename, score, matches: [{match: {start, end}, context}]}].- Lexical mode:
matchesis non-empty (up to 5 spans per file). - Semantic mode:
matchesis[]; the score is1 − distance/2(0..1, higher = more similar).
- Lexical mode:
Format for the user:
### N hits for "<query>" (mode=<mode>) 1. **<filename>** — score <score> > <context excerpt> > <context excerpt> 2. **<filename>** — score <score> > <context excerpt> …For semantic results (no contexts), drop the
>lines and just list filename + score.Empty results. If the response is
[]:- In lexical mode: tell the user, and suggest
--semanticif the query is conceptual (paraphraseable) rather than a literal string. - In semantic mode: tell the user; suggest dropping
--semanticif the query is a verbatim phrase.
- In lexical mode: tell the user, and suggest
Result interpretation
- Lexical scoring is ordinal, not absolute — the two backends use different formulas. Obsidian Local REST API returns BM25-style scores (often negative; smaller magnitudes for better matches in some scoring variants). vault-storage returns
(body matches) + 3 × (title matches). Treat the order returned by the endpoint as authoritative; don't reason about the numeric score across backends. - Semantic scoring: 1 = identical embedding; ~0.7+ = strong match; ~0.5 = topical neighbour; < 0.4 = noise. Don't filter on threshold by default — return whatever the endpoint ranked.
When the user is researching a topic, the natural next step after a search is to read the top hit. Offer it: "Want me to read <top-hit>?" — don't auto-read unless the user clearly just wants the content (e.g. asked for "the note on X", not "find the note on X").
Backend compatibility
| Backend | Lexical | Semantic | Honors limit |
|---|---|---|---|
Obsidian Local REST API (:8089) |
yes | param ignored → lexical | no — returns all hits |
vault-storage (:8123) |
yes | yes | yes |
The skill works against whichever URL $VAULT_API_URL points at. If --semantic is requested but the backend doesn't support it, results will silently fall back to lexical — acceptable for now; flag it to the user only if the result shape suggests a fallback occurred (lexical hits returned when the user wanted embedding similarity).
Truncate client-side. Obsidian's /search/simple/ ignores the limit query param and returns every hit. Always slice the JSON response to the requested limit before formatting — don't trust the server to do it. After cutover to :8123 this becomes a no-op (server already truncates).
Dependencies
vault-curlon$PATH— standard for the vault skills.- Falls back to raw
curlwithAuthorization: Bearer $VAULT_API_TOKENifvault-curlis missing.