| name | wiki-tags-refresh |
| description | Scan the vault (or a target directory) for tags used in page frontmatter and page bodies, diff against the vault's .obsidian/copilot/tag-index.md, prompt the user to approve new tags and clean stale ones, then update tag-index.md in place. Run after heavy ingest or other large content changes when new concepts may have introduced new tags. Triggers on: wiki-tags-refresh, refresh tags, update tag index, wiki tags, sync tags.
|
| allowed-tools | view, edit, create, bash, glob, grep |
wiki-tags-refresh
Read ~/.copilot/installed-plugins/ihudak-copilot-plugins/obsidian-llm-wiki/skills/wiki-schema/SKILL.md fully before proceeding.
Invoke with: /wiki-tags-refresh
Step 1 — Resolve vault path
Set VAULT using the recommended fallback pattern:
VAULT="${VAULT_PATH:-${VAULT:-${HOME}/obsidian_vault}}"
VAULT_PATH takes precedence; VAULT is accepted as an alias; ~/obsidian_vault is the default.
WSL users with a Windows-side vault must set VAULT_PATH explicitly (e.g. /mnt/c/Users/<name>/obsidian_vault).
Step 2 — Read the current tag index
Read .obsidian/copilot/tag-index.md fully. Extract every documented tag (lines matching
`#tagname`).
Step 3 — Collect tags from pages
Resolve the scan root:
SCAN_ROOT="${VAULT_PATH:-${VAULT:-${HOME}/obsidian_vault}}"
If /wiki-tags-refresh was invoked with a directory argument, append it instead: scan
every .md file under the vault root by default (excludes .obsidian/), or under
"${SCAN_ROOT}/<directory>" if a directory argument was given.
The frontmatter extraction (YAML multi-line) across $SCAN_ROOT:
find "$SCAN_ROOT" -name "*.md" -not -path "*/.obsidian/*" -print0 | xargs -0 awk '
FNR==1{front=0; intags=0}
/^---/{if(front==0) front=1; else front=0; next}
!front{next}
/^tags:/{intags=1; next}
/^[a-zA-Z]/{intags=0; next}
intags && /^ - /{gsub(/^ - /, ""); print}
' | sort -u
Note: only the YAML multi-line block form (tags: followed by - tagname lines) is
parsed; inline arrays (tags: [a, b]) are silently skipped by this script. Worth knowing
now that the scan covers the whole vault, where inline-array frontmatter is common outside
plugin-authored wiki pages.
Also collect inline tags from page bodies across the same scope:
grep -roh --exclude-dir=".obsidian" "#[a-zA-Z][a-zA-Z0-9/_-]*" "$SCAN_ROOT" | sort -u
Exclude false positives by inspecting each match's source line: the tag pattern already
requires a letter immediately after #, so standard # Heading / ## Heading lines never
match it. The main residual false-positive source is URL fragments (e.g. page.md#Section)
and code blocks — use judgment when presenting candidates in Step 6.
Deduplicate the full collected set.
This walks the vault tree twice (once for frontmatter, once for inline tags); on a large
vault expect it to take longer than the previous wiki/-only scan.
Step 4 — Diff against tag-index.md
- New tags: found in scanned pages (default: entire vault) but NOT documented in
tag-index.md
- Stale candidates: documented in
tag-index.md but found in ZERO scanned pages
(flag only — never auto-remove; they may be used in other vault files)
Step 5 — Report findings
wiki-tags-refresh results
─────────────────────────
New (undocumented in tag-index.md): #newtag #anothertag
Stale (0 uses in scanned pages): #oldtag #unusedtag
Already in sync: N tags
Step 6 — Process new tags
For each new tag, ask the user:
- "What does
#newtag mean?"
- "Which section of tag-index.md should it go in?"
Present the existing section list as choices + "Other / new section…"
- If the user skips a tag, leave it undocumented.
Step 7 — Process stale candidates
Present the stale list and ask:
"Remove all stale tags from index" — removes only confirmed zero-use tags
"Review one by one" — step through each with keep/remove choice
"Keep all (ignore)" — leave index unchanged for these
Note: Step 3's scan may have been directory-scoped (if a directory argument was given to
/wiki-tags-refresh), so a "stale" candidate might still be in use elsewhere in the vault.
Always confirm zero vault-wide use before suggesting removal, using an exact tag match — a
substring match like grep "#tagname" would false-match #tagname-extended or
#tagname/nested — and excluding only tag-index.md itself: every documented tag appears
in tag-index.md by definition, so excluding it (not the whole .obsidian/ directory)
avoids a false "always used" result while still letting genuine uses elsewhere in
.obsidian/ (e.g. custom prompts) protect a tag from removal:
grep -roh --include="*.md" --exclude="tag-index.md" "#[a-zA-Z][a-zA-Z0-9/_-]*" "${VAULT_PATH:-${VAULT:-${HOME}/obsidian_vault}}" \
| grep -xF "#tagname" | wc -l
If vault-wide count > 0, flag as "used elsewhere in the vault — keep?" rather than suggesting removal.
Step 8 — Update tag-index.md
For approved new tags:
For confirmed removals:
- Remove the entry from its section.
- Do NOT remove from
## Recently Approved Tags (history record).
Do not touch any section not affected by the diff.
Step 9 — Append to _log.md
## [YYYY-MM-DD] tags-refresh | N new tags proposed, M approved, L removed
- New: #tag1, #tag2 (if any approved)
- Removed: #oldtag (if any removed)
Finish
wiki-tags-refresh complete.
Tags added: N Tags removed: M Unchanged: K
tag-index.md updated.