From zkfy
Search the Obsidian Zettelkasten vault for notes matching a natural language query. Uses a tiered retrieval system: fast index lookup (Tier 0) → synthesis dedup (Tier 0.5) → grep-based fallback (Tiers 1-3). Works from any working directory. Use when you need to find related notes, check what exists on a topic, or gather context before creating new notes.
How this skill is triggered — by the user, by Claude, or both
Slash command
/zkfy:vault-searchThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
Search the ZK vault for notes matching a natural language query. Returns ranked results with paths, matched metadata, and abstract excerpts.
Search the ZK vault for notes matching a natural language query. Returns ranked results with paths, matched metadata, and abstract excerpts.
$ARGUMENTS — <query> [--limit N] [--vault PATH]
"front-end career developing suggestion", "XSS 攻擊防禦", "React performance optimization". — current working directory, i.e., run from inside your vault)Analyze the query and produce a flat list of search terms to drive all tiers:
"front-end career developing suggestion" → frontend, career, developmentfrontend / front-end / web前端, 職涯, 學習路徑)XSS, CORS, DP, DSA)interview-prep, career, learning-strategyinterview-prep, career, learning-strategy, performance, security,
testing, debugging, design-pattern, architecture, api-design,
concurrency, state-management, type-system, beginner, advanced,
reference, cheatsheet, stubProduce a deduplicated flat list of all search terms. Track which terms come from the original query vs. generated synonyms.
Before running grep-based tiers, check if .claude/index.md exists in the vault root.
If index.md does NOT exist:
⚠ No index found. Run /vault-index --full to build it.If index.md exists, run two phases:
.claude/index.md## Keyword Index section- <term>: (case-insensitive)[[NoteNames]] from matching linesIf Phase A yielded < limit results, scan enriched entry lines:
- [[)[[ and ]])— and |)cats:, sub:, tags:, aka: field valuesEarly exit: If Phase A + Phase B yields ≥ limit results → skip all grep tiers, jump to Tier 0.5. If some results but < limit → proceed to Tier 1 but merge with Tier 0 results.
After Tier 0 (and before grep tiers), check the current result set for prior synthesis notes:
Type: permanent in the note (read first 10 lines if needed)[SYNTHESIS]Synthesis notes are created by /query-to-note — finding one means this question may have already been answered and filed.
Only reached if Tier 0 yielded < limit results or index.md is missing.
1a. Search Aliases — for each primary keyword and synonym:
Grep pattern: ^Aliases:.*{term}
Path: {vault_root}
Glob: **/*.md
Case-insensitive: true
1b. Search Filenames — for each primary keyword:
Glob pattern: **/*{term}*.md
Path: {vault_root}
Exclude from all searches:
y.template/, row/, row/assets/, x.temp/, docs/,
.obsidian/, .claude/, .agents/, .prompts/, .github/, .instructions/
Merge Tier 1 results. Score: 25 pts per note, +5 per additional matched term.
If Tier 0 + Tier 1 yields ≥ limit → skip Tier 2 and Tier 3.
Catches topical matches not covered by exact aliases.
For each remaining search term:
Grep pattern: ^(Categories|Sub-Categories|tags):.*{term}
Path: {vault_root}
Glob: **/*.md
Case-insensitive: true
Add new matches (not already found). Score: 20 pts per note, +5 per additional matched term.
If Tier 0 + Tier 1 + Tier 2 ≥ limit → skip Tier 3.
For queries with few results after Tier 2, search note bodies:
Grep pattern: {term}
Path: {vault_root}
Glob: **/*.md
Case-insensitive: true
Restrict to primary keywords only (not all synonyms) to avoid noise. Add new matches. Score: 10 pts per note, +5 per additional term.
For each result note (up to limit), use the Read tool to extract the first 25 lines and parse:
Type, Categories, Sub-Categories, Aliases, tags### Abstract or ## Abstract until next heading or 10 lines## Vault Search: "{original query}"
Found {N} notes ({X} index matches, {Y} grep matches):
### 1. {Note-Filename.md} {[SYNTHESIS] if applicable}
- **Path**: {relative path from vault root}
- **Match**: {tier}: {matched term}
- **Categories**: {categories} **Tags**: {tags}
- **Aliases**: {aliases}
- **Abstract**:
> {abstract excerpt, max 5 lines}
### 2. ...
---
Vault: {vault_root} | Index: {used/missing} | Terms searched: {terms list}
No results found:
000.Index/ MOC files for topic discoveryRun /vault-index --full to enable fast searchChinese-only query:
Aliases field and Keyword Index both contain CJK — these are the primary Chinese match surfacesSingle-word or ambiguous query:
--vault override:
Synthesis note found (Tier 0.5):
[SYNTHESIS] label/query-to-note) can use this to offer dedup optionsThe vault uses this frontmatter schema:
Type: literature # or: permanent (synthesis from /query-to-note)
Categories: [Web, Security] # Title Case domain + secondary
Sub-Categories: [xss, injection] # lowercase-kebab topics
Aliases: [XSS, Cross-Site Scripting, 跨站腳本攻擊] # 3-5 search terms incl. CJK
tags: [security, interview-prep] # cross-cutting controlled vocab
Tags vocabulary (18): interview-prep, career, learning-strategy, performance, security, testing, debugging, design-pattern, architecture, api-design, concurrency, state-management, type-system, beginner, advanced, reference, cheatsheet, stub
When qmd is installed, vault-search gains a Tier -1 that supersedes all other tiers:
which qmd — if not found, skip to Tier 0qmd search "<query>" --path <vault_root> --limit <limit># macOS via Homebrew
brew install tobi/tap/qmd
# or from source
go install github.com/tobi/qmd@latest
qmd also provides an MCP server. If configured in .mcp.json, use the mcp__qmd__search tool instead of shelling out — no CLI install needed.
Use qmd when the vault exceeds ~5000 notes and the index-based Tier 0 becomes the bottleneck.
Guides creation, editing, and verification of skills for AI coding agents using test-driven development with subagent scenarios. Use when authoring or debugging skills.
npx claudepluginhub jasonsie/zkfy --plugin zkfy