description: Run a vault health check - grouped by severity, detects contradictions, concept gaps, stale claims, and structural issues
category: meta
triggers_en: ["vault health", "check vault", "audit vault", "vault diagnostics"]
triggers_es: ["salud del vault", "revisa el vault", "audita el vault", "diagnóstico del vault"]
triggers_pt: ["saúde do vault", "verifique o vault", "audite o vault", "diagnóstico do vault"]
triggers_zh: ["检查知识库健康状况", "给我的知识库做体检", "审计我的笔记库", "诊断知识库问题"]
Use the obsidian-second-brain skill. Execute `/obsidian-health`:
1. Read `_CLAUDE.md` first to find the vault path 2. Run the health scan from the skill root (its absolute path was given at session start as **Skill root**; substitute it for `SKILL_ROOT`): `uv run --directory "SKILL_ROOT" scripts/vault_health.py --path ~/path/to/vault --json` (replace vault path with the one from `_CLAUDE.md`)
- **Large or noisy vault?** If the scan surfaces thousands of findings from directories the user does not maintain by hand (atomic-card pools, backup snapshots, imported dumps), do NOT hardcode fixes. Offer to write a `<vault>/.vault-config.json` that extends the exclude list: `{"exclude-dirs": ["_card-pool"], "exclude-paths": ["Archive/Backup"]}`. `exclude-dirs` matches directory names anywhere in the tree; `exclude-paths` matches vault-relative path prefixes. Both are additive - the built-in excludes always apply - and a missing or malformed file is ignored silently. Re-run the scan afterward.
- **`source_payload` findings?** (#194) Three different problems under one type. An `error` naming one source means the note declares `capture_scope: full-local` or `bounded-local` and has essentially no body - it claims evidence it does not hold, so re-capture it or set `capture_scope: url-only` and say so plainly. A `warning` naming a source plus the notes that link it means active knowledge rests on a `url-only` record: the vault kept the locator, not the evidence. Offer to re-capture the source, or to mark the dependent claims as URL-backed; never resolve it by copying a complete copyrighted work. The single `info` line counting sources with no `capture_scope` is every source written before the field existed - fill them in as you touch them, do not sweep the vault. `"source_policy": "strict-local"` in `.vault-config.json` raises the last two by one severity.
- **`rewrite_policy: unattended` info line?** The vault has opted out of the confirm-before-rewrite gate in `/obsidian-ingest` (#250) and reviews rewrites through its own layer. Nothing to fix; the line is there so a reader of the report knows the vault runs without the gate. Remove the key from `.vault-config.json` to restore the default.
3. Parse the JSON output and split findings into categories 4. Spawn parallel subagents to handle each category simultaneously:
- **Wanted-notes agent**: the script reports `wanted_note` items - links to a note that does not exist yet. These are NOT errors: in a wiki-style vault you link a thing the moment you mention it, so wanted notes are a demand-ranked wishlist of pages worth writing, not breakage. Triage them with `uv run --directory "SKILL_ROOT" scripts/triage_links.py --path <vault> --limit N`, which sorts each into keep (a deliberate seed, leave it), create (referenced enough to deserve a real note now), or delete (junk or a typo - fix the link). Report-only by default; needs `ANTHROPIC_API_KEY`. Headless on purpose: it can run unattended or on a schedule. The goal is to triage the backlog, never to drive the count to zero.
- **Duplicates agent**: confirm duplicates are truly the same concept, not just similar names
- **Taxonomy agent**: only fires when `<vault>/_meta/taxonomy.md` exists (format in `references/taxonomy-format.md`) - the script's `tag_synonym` and `tag_not_in_taxonomy` findings are empty otherwise, so a vault without the file sees nothing. `tag_synonym` means a note's tag is a known synonym of a canonical tag: the fix is unambiguous, so offer to rewrite that note's `tags:` frontmatter to the canonical form, per note, with explicit confirmation before editing - never batch-rewrite across the vault unattended. `tag_not_in_taxonomy` means the tag matches neither a canonical tag nor a synonym: report it as informational only - it may be a legitimate new tag - and never auto-fix it; the taxonomy file is a human-curated vocabulary, not something this command edits on its own.
- **Frontmatter agent**: identify notes missing required fields by type. If the script reports a `code_fence_wrapped` note (frontmatter trapped inside a leading ```` ```markdown ```` fence), the fix is to **unwrap it** - strip the opening fence line and the matching closing ```` ``` ```` so the inner `---` frontmatter and body become real markdown. **Never add a new frontmatter block to a wrapped note** - that produces duplicate frontmatter and leaves the body trapped. If the note already has both a prepended frontmatter block and an inner wrapped one, merge them (keep the richer fields) and unwrap.
- **Staleness agent**: check overdue tasks and unfilled template syntax
- **Orphans agent**: check orphaned notes and empty folders
- **Contradictions agent**: scan Key Decisions sections and reference/concept notes (the concept or knowledge folder per `references/folder-map.md` - wiki-style `wiki/concepts/`, Obsidian-style `Knowledge/`) for claims that conflict with each other or have been superseded by newer sources
- **Typed-edge lint agent**: run `uv run --directory "SKILL_ROOT" scripts/link_graph.py --path <vault> --lint`, which validates the `relations:` typed-edge layer (see `references/ai-first-rules.md` Rule 6 § Typed edges). It returns `findings` (each with `severity`, `kind`, `note`, `target`, `type`, `detail`) and a `summary`. Map them into the severity groups below: `contradiction` (A and B claim the same asymmetric type about each other) is 🔴 Critical; `unknown_type`, `dangling_target`, and `sel