wiki-lint · ar9av — скилл для Claude Code: что делает и как установить
Проверяет здоровье базы Obsidian: находит битые ссылки, страницы-сироты, пропуски во фронтметтере и устаревшие заметки без полного чтения всех файлов хранилища.
npx skills add Ar9av/obsidian-wiki --skill wiki-lint -a claude-codeЧто делает wiki-lint
Скилл проводит аудит базы знаний в Obsidian в режиме отчёта. Проверка выявляет страницы без входящих ссылок, неработающие викиссылки с учётом якорей или алиасов, а также пропущенные обязательные поля фронтметтера вроде title, tags или updated. Каталоги _archives/, _raw/, _readouts/ и .obsidian/ сканирование намеренно пропускает.
Логика опирается на точечный grep заголовков и секций заметок вместо сплошного вычитывания файлов. Если в системе установлен CLI obsidian-wiki, скилл вызывает команду obsidian-wiki lint "$OBSIDIAN_VAULT_PATH" --json, передавая настройки схемы и правила из $OBSIDIAN_VAULT_PATH/AGENTS.md. При отсутствии утилиты проверки выполняются через поиск по тексту.
Перед запуском скиллу требуется путь к хранилищу через переменную OBSIDIAN_VAULT_PATH или файл .env. Любые пустые значения в переопределениях схем скилл считает ошибкой конфигурации и сразу останавливает валидацию.
Какие задачи решает
- найти страницы-сироты без входящих викиссылок
- выявить битые ссылки на несуществующие заметки
- проверить обязательные поля фронтметтера в файлах Markdown
- обнаружить устаревшие заметки по дате обновления источников
Примеры запросов агенту
- Запусти аудит хранилища Obsidian с помощью wiki-lint
- Проверь битые викиссылки и сироты в базе заметок
Как установить wiki-lint
1Через Skills CLI (Vercel)
npx skills add Ar9av/obsidian-wiki --skill wiki-lint -a claude-code2Вручную: положить файлы
~/.claude/skills/wiki-lint/SKILL.mdПапка скилла целиком; для одного проекта — .claude/skills/wiki-lint/
1Через Skills CLI (Vercel)
npx skills add Ar9av/obsidian-wiki --skill wiki-lint -a codex2Вручную: положить файлы
.agents/skills/wiki-lint/SKILL.mdДля всех проектов — ~/.agents/skills/
1Через Skills CLI (Vercel)
npx skills add Ar9av/obsidian-wiki --skill wiki-lint -a cursor2Вручную: положить файлы
.cursor/skills/wiki-lint/SKILL.mdCursor читает и .agents/skills/, и .claude/skills/
1GitHub CLI
gh skill install Ar9av/obsidian-wiki wiki-lint2Вручную: положить файлы
.github/skills/wiki-lint/SKILL.md1Через Skills CLI (Vercel)
npx skills add Ar9av/obsidian-wiki --skill wiki-lint -a gemini-cli2Командой платформы
gemini skills install https://github.com/Ar9av/obsidian-wiki --path .skills/wiki-lintВручную: положить файлы
.devin/skills/wiki-lint/SKILL.mdСтарый путь .windsurf/skills/ тоже читается
Через Skills CLI (Vercel)
npx skills add Ar9av/obsidian-wiki --skill wiki-lint -a opencodeClaude.ai
Упакуйте папку в zip и загрузите в Settings → Capabilities → Skills
По шагам, с командами для каждой платформы: Как установить скилл в Claude Code: пять способов
Вопросы о wiki-lint
Как установить wiki-lint в Claude Code?
Выполните команду npx skills add Ar9av/obsidian-wiki --skill wiki-lint -a claude-code.
Что делает скилл wiki-lint?
Скилл сканирует заметки Obsidian и формирует отчёт о битых ссылках, страницах без связей, отсутствии обязательных полей метаданных и устаревшем содержимом.
Обязательно ли устанавливать CLI obsidian-wiki?
Нет, наличие утилиты не требуется. Если CLI obsidian-wiki недоступен в PATH, скилл автоматически переключается на grep-проверки по файлам хранилища.
Исходный текст
SKILL.md · MIT
---
name: wiki-lint
description: >
Audit wiki health: broken links, orphans, contradictions, stale content, lifecycle and tag issues. Use for maintenance or health checks. Default is report-only; use wiki-dedup for page-identity merges.
---
# Wiki Lint — Health Audit
You are performing a health check on an Obsidian wiki. Your goal is to find and fix structural issues that degrade the wiki's value over time.
**Before scanning anything:** follow the Retrieval Primitives table in `llm-wiki/SKILL.md`. Prefer frontmatter-scoped greps and section-anchored reads over full-page reads. On a large vault, blindly reading every page to lint it is exactly what this framework is built to avoid.
## Before You Start
**Writing profile:** Before drafting or rewriting natural-language Markdown, read and apply the `Writing Profile Resolution` section in `llm-wiki/SKILL.md`. Framework schema, provenance, safety, and operation-specific requirements take precedence.
Apply `WRITING.md` preferences only to generated consolidation reports; deterministic findings and fixes keep their existing formats.
1. **Resolve config** — follow the Config Resolution Protocol in `llm-wiki/SKILL.md` (inline `@name` override → walk up CWD for `.env` → global config → prompt setup). This gives `OBSIDIAN_VAULT_PATH` plus any `OBSIDIAN_ALLOWED_LIFECYCLES`, `OBSIDIAN_ALLOWED_RELATIONSHIP_TYPES`, `OBSIDIAN_REQUIRED_TRUST_FIELDS`, and `OBSIDIAN_SCHEMA_SOURCE` values.
2. **Read owner rules** — if `$OBSIDIAN_VAULT_PATH/AGENTS.md` exists, read it before interpreting any schema. Owner rules override framework defaults.
3. **Form the effective schema** — record the schema source locator plus effective required/optional frontmatter, lifecycle values, relationship types, and provenance markers. Framework values are defaults; preserve owner extensions and relaxed requiredness exactly. Never coerce an owner type to a framework type.
4. Read `index.md` for the full page inventory
5. Read `log.md` for recent activity context
Pass the effective schema to deterministic checks explicitly. For example, add each owner extension with `--allow-lifecycle` / `--allow-relationship-type`, replace trust requiredness with repeatable `--required-trust-field`, and identify the authority with `--schema-source "$OBSIDIAN_VAULT_PATH/AGENTS.md"`. The JSON report's `schema` block must match the schema you formed before findings are accepted.
Schema precedence is CLI flags > resolved environment/config values > framework defaults; lifecycle and relationship extensions remain additive. Strip every override before use. An explicitly configured empty or whitespace-only value—and any empty comma-separated list entry—fails closed; never treat it as a valid lifecycle, relationship type, required field, or authority locator. Remove the variable instead when defaults are intended.
When `obsidian-wiki` is on PATH, prefer `obsidian-wiki lint "$OBSIDIAN_VAULT_PATH" --json` (with the same schema override flags as above) and fold the JSON `findings` into the health report. If the CLI is unavailable, keep the grep-based checks below — do not require the binary.
If the JSON report includes `findings.snapshot_mismatch`, list those pages in the report. Missing or drifted `snapshots:` is **not** missing required frontmatter (section 3 still covers only title, category, tags, sources, created, updated). Do not rewrite `sources:` to fix snapshot drift. Run `obsidian-wiki snapshots apply --from-json <lint.json>` (dry-run), show the preview, and pass `--apply` only after explicit user confirmation. Apply writes quoted `"[[_raw/_archived/stem|stem]]"` list items (native Property links with display text). `wiki-lint --consolidate` still does not apply this finding.
## Lint Checks
Run these checks in order. Report findings as you go.
**Scope:** skip `_archives/`, `_raw/`, `_readouts/`, and `.obsidian/` in every check. These hold frozen snapshots, unprocessed staging drafts, and derived readouts (saved by `wiki-narrate`) — they are not knowledge-graph pages, so orphan, frontmatter, and link checks don't apply to them.
### 1. Orphaned Pages
Find pages with zero incoming wikilinks. These are knowledge islands that nothing connects to.
**How to check:**
- Glob all `.md` files in the vault
- For each page, Grep the rest of the vault for `[[page-name]]` references
- Pages with zero incoming links (except `index.md` and `log.md`) are orphans
**How to fix:**
- Identify which existing pages should link to the orphan
- Add wikilinks in appropriate sections
### 2. Broken Wikilinks
Find `[[wikilinks]]` that point to pages that don't exist.
**How to check:**
- Grep for `\[\[.*?\]\]` across all pages
- Extract the link target: drop everything from the first `|` (alias) or `#` (heading/block anchor), and strip a trailing backslash left by an escaped `\|` inside a table cell
- Skip a target whose extension is an attachment type (`.png`, `.jpg`, `.gif`, `.svg`, `.webp`, `.pdf`, `.canvas`, `.base`, audio and video): it's an embed, not a page link, and has no entry in the `.md` inventory this check compares against
- Do **not** treat every dot as an extension — `[[Node.js]]`, `[[Next.js]]`, and `[[v1.2 release notes]]` are page links whose names happen to contain a dot, and dropping them would both miss real broken links and make the target page look like an orphan
- Strip an explicit `.md` suffix from what remains, then check if a corresponding `.md` file exists
**How to fix:**
- If the target was renamed, update the link
- If the target should exist, create it
- If the link is wrong, remove or correct it
### 3. Missing Frontmatter
Every page should have: title, category, tags, sources, created, updated.
**How to check:**
- Grep frontmatter blocks (scope to `^---` at file heads) instead of reading every page in full
- Flag pages missing required fields
**How to fix:**
- Add missing fields with reasonable defaults
### 3a. Missing Summary (soft warning)
Every page *should* have a `summary:` frontmatter field — 1–2 sentences, ≤200 chars. This is what cheap retrieval (e.g. `wiki-query`'s index-only mode) reads to avoid opening page bodies.
**How to check:**
- Grep frontmatter for `^summary:` across the vault
- Flag pages without it, **but as a soft warning, not an error** — older pages predating this field are fine; the check exists to nudge ingest skills into filling it on new writes.
- Also flag pages whose summary exceeds 200 chars.
**How to fix:**
- Re-ingest the page, or manually write a short summary (1–2 sentences of the page's content).
### 4. Stale Content
Pages whose `updated` timestamp is old relative to their sources.
**How to check:**
- Compare page `updated` timestamps to source file modification times
- Flag pages where sources have been modified after the page was last updated
**Undated claims (line-level).** `obsidian-wiki lint` reports `undated_claims`: lines stating a count or amount that goes stale (stars, users, customers, downloads, deals, MRR/ARR) with no date on the line. Lines under a dated heading, pages in `journal/` or named `YYYY-MM-…`, code, and blockquotes are exempt. A warning, never a failure. For each one, either re-check the number and stamp it `(as of YYYY-MM-DD)`, replace it with a link to where the live number lives, or move it under a dated heading as history.
### 5. Contradictions
Claims that conflict across pages.
**How to check:**
- This requires reading related pages and comparing claims
- Focus on pages that share tags or are heavily cross-referenced
- Look for phrases like "however", "in contrast", "despite" that may signal existing acknowledged contradictions vs. unacknowledged ones
**How to fix:**
- Add an "Open Questions" section noting the contradiction
- Reference both sources and their claims
### 6. Index Consistency
Verify `index.md` matches the actual page inventory.
**How to check:**
- Compare pages listed in `index.md` to actual files on disk
- Check that summaries in `index.md` still match page content
### 7. Provenance Drift
Check whether pages are being honest about how much of their content is inferred vs extracted. See the Provenance Markers section in `llm-wiki` for the convention.
**How to check:**
- For each page with a `provenance:` block or any `^[inferred]`/`^[ambiguous]` markers, count sentences/bullets and how many end with each marker
- Compute rough fractions (`extracted`, `inferred`, `ambiguous`)
- Apply these thresholds:
- **AMBIGUOUS > 15%**: flag as "speculation-heavy" — even 1-in-7 claims being genuinely uncertain is a signal the page needs tighter sourcing or should be moved to `synthesis/`
- **INFERRED > 40% with no `sources:` in frontmatter**: flag as "unsourced synthesis" — the page is making connections but has nothing to cite
- **Hub pages** (top 10 by incoming wikilink count) with INFERRED > 20%: flag as "high-traffic page with questionable provenance" — errors on hub pages propagate to every page that links to them
- **Drift**: if the page has a `provenance:` frontmatter block, flag it when any field is more than 0.20 off from the recomputed value
- **Skip** pages with no `provenance:` frontmatter and no markers — treated as fully extracted by convention
**How to fix:**
- For ambiguous-heavy: re-ingest from sources, resolve the uncertain claims, or split speculative content into a `synthesis/` page
- For unsourced synthesis: add `sources:` to frontmatter or clearly label the page as synthesis
- For hub pages with INFERRED > 20%: prioritize for re-ingestion — errors here have the widest blast radius
- For drift: update the `provenance:` frontmatter to match the recomputed values
### 8. Fragmented Tag Clusters
Checks whether pages that share a tag are actually linked to each other. Tags imply a topic cluster; if those pages don't reference each other, the cluster is fragmented — knowledge islands that should be woven together.
**How to check:**
- For each tag that appears on ≥ 5 pages:
- `n` = count of pages with this tag
- `actual_links` = count of wikilinks between any two pages in this tag group (check both directions)
- `cohesion = actual_links / (n × (n−1) / 2)`
- Flag any tag group where cohesion < 0.15 and n ≥ 5
**How to fix:**
- Run the `cross-linker` skill targeted at the fragmented tag — it will surface and insert the missing links
- If a tag group is large (n > 15) and still fragmented, consider splitting it into more specific sub-tags
### 9. Visibility Tag Consistency
Checks that `visibility/` tags are applied correctly and aren't silently missing where they matter.
**How to check:**
- **Untagged PII patterns:** Grep page bodies for patterns that commonly indicate sensitive data — lines containing `password`, `api_key`, `secret`, `token`, `ssn`, `email:`, `phone:` followed by an actual value (not a field description). If a page matches and lacks `visibility/pii` or `visibility/internal`, flag it as a likely mis-classification.
- **`visibility/pii` without `sources:`:** A page tagged `visibility/pii` should always have a `sources:` frontmatter field — if there's no provenance, there's no way to verify the classification. Flag any `visibility/pii` page missing `sources:`.
- **Visibility tags in taxonomy:** `visibility/` tags are system tags and must **not** appear in `_meta/taxonomy.md`. If found there, flag as misconfigured — they'd be counted toward the 5-tag limit on pages that include them.
**How to fix:**
- For untagged PII patterns: add `visibility/pii` (or `visibility/internal` if it's team-context rather than personal data) to the page's frontmatter tags
- For missing `sources:`: add provenance or escalate to the user — don't auto-fill
- For taxonomy contamination: remove the `visibility/` entries from `_meta/taxonomy.md`
### 10. Misc Promotion Candidates
Find pages in `misc/` that have accumulated enough project affinity to be promoted.
**How to check:**
- Glob `$OBSIDIAN_VAULT_PATH/misc/*.md`
- For each page, read the `affinity` frontmatter field
- Flag pages where any single project's score ≥ 3
**How to fix:**
- Run the `cross-linker` skill first if affinity scores look stale (e.g., `affinity: {}` on a page with many wikilinks)
- To promote: move the page to `projects/<project-name>/references/` (or another appropriate category), update its `category` frontmatter, remove `promotion_status`, and grep the vault for backlinks to update them
### 12. Confidence and Lifecycle Schema
Enforces the confidence + lifecycle frontmatter schema (see `llm-wiki/SKILL.md`, Confidence and Lifecycle section).
Two modes:
- **`--check`** (default, read-only) — reports errors and warnings
- **`--consolidate`** — may apply separately approved structural maintenance, but **never rewrites `base_confidence`**
Confidence is a semantic judgment. A deterministic tool cannot infer independent evidence lineages or whole-page claim coverage from source strings alone. Confidence automation therefore validates an explicitly approved manual trust ledger; it never substitutes URL counting for review.
#### Rule 12a — `lifecycle` enum validation
**How to check:** Grep frontmatter for `^lifecycle:` across all pages. Flag any value outside the effective lifecycle set (framework default: `{draft, reviewed, verified, disputed, archived}`).
**How to fix:** n/a (only a human should set lifecycle state)
#### Rule 12b — `base_confidence` range
**How to check:** Grep frontmatter for `^base_confidence:` across all pages. Flag any present value outside `[0.0, 1.0]`; flag absence only when the effective owner schema requires the field.
**How to fix:** n/a (wrong value means the skill computed it wrong — surface for manual correction)
#### Rule 12c — Stale page report (computed overlay)
Staleness is never stored — it is computed at read time: `is_stale = (today − updated) > 90 days`.
**How to check:** For each page, read `updated:` from frontmatter and compute `is_stale`. If stale, also check `lifecycle:`. Report:
- Stale pages with `lifecycle: verified` with a louder annotation (these are the most dangerous — high-trust pages that may be wrong)
- All other stale pages as a standard warning
**How to fix:** `--fix` does **not** rewrite `lifecycle`. Staleness clears automatically when a re-ingest bumps `updated`.
#### Rule 12c-2 — Illegal lifecycle transitions
The lifecycle enum is a state machine, not a free-form label. `obsidian-wiki lint` reports `illegal_lifecycle_transitions` by comparing each page's current `lifecycle` against the value recorded in `_meta/trust-ledger.json` at its last review.
**Flagged:** any state falling back to `draft` (only ingest sets `draft`), and any exit from `archived` (terminal — a restore is a deliberate human delete-and-recreate).
**Not flagged:** `draft → verified`. Ledger snapshots are sparse, so a legitimate intermediate `reviewed` may have happened between two reviews; flagging it would fire on valid history.
Warns by default; fails under `--strict-trust`. Pages whose ledger entry predates the `lifecycle` field have no baseline and are skipped silently.
**How to fix:** n/a — a page that moved along a forbidden edge means either a skill wrote `lifecycle` when it shouldn't have, or a human transition needs recording. Surface for human resolution.
#### Rule 12d — Supersession integrity
**How to check:** For each page with `superseded_by: "[[target]]"`:
- Verify the target page exists
- Verify the target page is not itself `archived` (no circular or chained supersession)
- Verify there are no cycles (A supersedes B which supersedes A)
- Warn if `lifecycle != archived` while `superseded_by` is set (inconsistent state)
**How to fix:** n/a — flag for human resolution
#### Rule 12e — Confidence review integrity
**How to check:** Run the deterministic ledger validator first:
```bash
obsidian-wiki trust-check "$OBSIDIAN_VAULT_PATH" --strict --json --pretty
```
Use `--strict` for CI and scheduled gates: stale, unreviewed, or missing-page
warnings then return nonzero. Without `--strict`, `trust-check` remains a
read-only reporting command and returns nonzero only for hard ledger errors or
score mismatches.
The approved ledger lives at `_meta/trust-ledger.json`. Each entry records the human-reviewed score plus a SHA-256 fingerprint of material page content and evidence metadata. The fingerprint excludes volatile bookkeeping (`updated`, `base_confidence`, and lifecycle transition fields), so timestamp-only edits do not reopen review.
Interpret results as follows:
- `reviewed` — current material fingerprint and stored score both match the approved review; do **not** recompute from source strings.
- `stale` — body, summary, sources, provenance, tags, or relationships changed; perform a new manual lineage + claim-coverage review.
- `unreviewed` — page has no approved ledger entry; manual review is required.
- `score_mismatches` — material content still matches, but stored `base_confidence` differs from the approved value; fail the lint.
- `errors` — malformed/missing ledger data; fail the lint.
For a separately approved full-vault review, record the accepted state explicitly:
```bash
obsidian-wiki trust-record "$OBSIDIAN_VAULT_PATH" \
--all --reviewed-at "<ISO-8601 timestamp>" --approved --json --pretty
```
After a separately approved review of only specific stale/unreviewed pages, update only those entries:
```bash
obsidian-wiki trust-record "$OBSIDIAN_VAULT_PATH" \
--page "concepts/example.md" --page "skills/example.md" \
--reviewed-at "<ISO-8601 timestamp>" --approved --json --pretty
```
`--approved` means a human approved every score being recorded. It is a workflow
assertion, not a cryptographic signature: keep `_meta/trust-ledger.json` under
version control and require human diff review before merging ledger changes.
`--all` is valid only after a full-vault review; use repeatable `--page` for
partial reviews so unrelated stale pages remain open. Never run `trust-record`
merely to silence warnings.
**Manual recomputation protocol for stale/unreviewed pages:**
1. Decompose the page into material claims and map each claim to evidence.
2. Collapse dependent evidence into independent lineages: files/commits from one repository, retries in one task chain, snapshots plus their captured source, duplicate memories, and parent/child tasks each count once.
3. Assign reviewed quality per independent lineage using `llm-wiki` buckets.
4. Compute the raw base score, then assess whole-page claim coverage. The formula is a starting point, not an automatic target.
5. Classify the result as `raise`, `keep`, `lower`, or `repair first`; require approval before changing `base_confidence` or refreshing the ledger.
**How to fix:** There is no automatic confidence fix. Apply only an explicitly approved exact patch, verify its scope, then refresh only the reviewed ledger state. `--consolidate` must never rewrite `base_confidence`.
#### Current enforcement
Under framework defaults, every non-reserved content page must contain a
finite `base_confidence` in `[0.0, 1.0]` and a documented lifecycle value.
An owner schema may relax either field; present values remain validated.
Missing or malformed trust fields, malformed ledger data, and a missing required
ledger are hard errors. New pages with valid trust fields but no approved ledger
entry are `unreviewed`; material changes to approved pages are `stale`.
#### Output additions
Add to the Wiki Health Report:
```markdown
### Confidence/Lifecycle Issues (N found)
- `concepts/foo.md` — missing `lifecycle` field (warning: Phase 1)
- `entities/bar.md` — `lifecycle: stalestate` is not a valid enum value
- `concepts/scaling.md` — `base_confidence: 1.4` is out of range [0.0, 1.0]
- `synthesis/old-analysis.md` — STALE (last updated 2025-10-01, 182 days ago) lifecycle=verified ⚠️ HIGH PRIORITY
- `concepts/outdated.md` — STALE (last updated 2025-11-15, 137 days ago) lifecycle=draft
- `entities/tool-v1.md` — `superseded_by: [[entities/tool-v2]]` but lifecycle=draft (expected archived)
- `concepts/drift-example.md` — confidence review stale: material fingerprint changed; manual lineage + coverage review required
- `entities/mismatch.md` — confidence mismatch: stored=0.80, approved=0.59
```
Append to the `LINT` log entry:
```
- [TIMESTAMP] LINT ... lifecycle_issues=N
```
### 13. Typed Relationships Validity
Validate `relationships:` frontmatter blocks. Skip pages that have no `relationships:` block — the field is optional.
**Framework-default types:** `extends`, `implements`, `contradicts`, `derived_from`, `uses`, `replaces`, `related_to`. Validate against the effective set after applying owner extensions.
**How to check:**
- Grep frontmatter for `^relationships:` across all vault pages
- For each page that has a `relationships:` block, read its frontmatter (not the full page body)
- For each entry in the block:
1. **Type validation** — flag any `type:` value not in the allowed set above
2. **Broken target** — strip `[[` and `]]` from the `target:` string, normalize (lowercase, spaces→hyphens, strip `.md`), and check whether a `.md` file at that path exists in the vault. Flag unresolved targets.
Before normalizing, drop everything from the first `|` (alias) or `#` (heading/block anchor): a pipe-aliased or heading-anchored target is not broken just because the literal bracket contents don't match a filename.
3. **Self-reference** — flag any entry where the resolved target equals the page's own node id
**How to fix:**
- Invalid type: report the value and effective schema source. Correct it only if it is absent from both framework defaults and owner extensions; never replace a valid owner type with `related_to`.
- Broken target: update or remove the entry; if the target page should exist, create it first
- Self-reference: remove the entry
**Output additions:**
```markdown
### Typed Relationship Issues (N found)
- `concepts/foo.md` — relationships[1]: type "contradication" is not an allowed type (did you mean "contradicts"?)
- `concepts/bar.md` — relationships[0]: target "[[skills/nonexistent-skill]]" resolves to no page in vault
- `entities/baz.md` — relationships[2]: self-reference (target resolves to this page's own id)
```
Append to the `LINT` log entry:
```
... relationship_issues=N
```
### 14. Event-Time Validity
Validate `valid_from` / `valid_until` / `superseded_by` frontmatter. All three are optional — skip pages that carry none of them.
`created`/`updated` are ingestion time; these three are event time, when the claim itself was true. A page whose `valid_until` has passed is **historical**, not wrong: it stays in the vault and in the graph, and only drops out of default retrieval.
**How to check:**
- Grep frontmatter for `^valid_from:`, `^valid_until:`, `^superseded_by:` across all vault pages
- For each page that has any of them:
1. **Date parseability** — each value must be `YYYY-MM-DD` or a full ISO 8601 timestamp. Flag anything else.
2. **Window order** — flag any page where `valid_until` precedes `valid_from`
3. **Dangling successor** — strip `[[`/`]]` from `superseded_by`, drop everything from the first `|` or `#`, strip `.md`, normalize, and check the page exists. Flag unresolved targets and self-references.
`obsidian-wiki lint` reports all three as `temporal_errors` (dates, windows) and `superseded_dangling` (successors). A bracketed dangling successor also shows up in `broken_links`.
**Why the dates fail rather than warn:** retrieval treats an unparseable window as current, so an unreported typo lets a stale claim answer as fact — the exact failure the fields exist to prevent.
**How to fix:**
- Unparseable date: rewrite as `YYYY-MM-DD`; if the real date is unknown, remove the field rather than guessing
- Inverted window: confirm which date is wrong with the page's sources; never silently swap them
- Dangling successor: create the replacement page, correct the pointer, or remove it if nothing replaced the claim
- Never "fix" a historical page by rewriting it as current — that destroys the record the window exists to keep
**Output additions:**
```markdown
### Event-Time Issues (N found)
- `references/gateway-nginx.md` — valid_until (2026-04-01) precedes valid_from (2026-05-01)
- `references/old-limits.md` — valid_until "soon" is not a date
- `references/legacy-auth.md` — superseded_by "[[oauth-rollout]]" resolves to no page in vault
```
Append to the `LINT` log entry:
```
... temporal_issues=N
```
### 11. Synthesis Gaps
Identify high-value synthesis opportunities the wiki is missing — concept pairs that co-occur across many pages but have no `synthesis/` page connecting them.
**How to check:**
- List all pages in `synthesis/` — collect the concept pairs each one already covers (from its `[[wikilinks]]` or title)
- Pick 10-15 frequently linked concepts from `concepts/` and `entities/`
- For each pair, run a quick grep to count pages that link to both:
```bash
rg -l --glob '*.md' "\[\[ConceptA\]\]" "$OBSIDIAN_VAULT_PATH" > /tmp/a.txt
rg -l --glob '*.md' "\[\[ConceptB\]\]" "$OBSIDIAN_VAULT_PATH" > /tmp/b.txt
comm -12 <(sort /tmp/a.txt) <(sort /tmp/b.txt) | wc -l
```
- Flag pairs with co-occurrence ≥ 3 that have no existing synthesis page
**How to fix:**
- Run `/wiki-synthesize` to automatically discover and fill the top gaps
## Output Format
Report findings as a structured list:
```markdown
## Wiki Health Report
### Orphaned Pages (N found)
- `concepts/foo.md` — no incoming links
### Broken Wikilinks (N found)
- `entities/bar.md:15` — links to [[nonexistent-page]]
### Missing Frontmatter (N found)
- `skills/baz.md` — missing: tags, sources
### Stale Content (N found)
- `references/paper-x.md` — source modified 2024-03-10, page last updated 2024-01-05
- `projects/foo.md:28` — undated claim: "GitHub: 6★" (stamp it, link it, or date the heading)
### Contradictions (N found)
- `concepts/scaling.md` claims "X" but `synthesis/efficiency.md` claims "not X"
### Index Issues (N found)
- `concepts/new-page.md` exists on disk but not in index.md
### Missing Summary (N found — soft)
- `concepts/foo.md` — no `summary:` field
- `entities/bar.md` — summary exceeds 200 chars
### Provenance Issues (N found)
- `concepts/scaling.md` — AMBIGUOUS > 15%: 22% of claims are ambiguous (re-source or move to synthesis/)
- `entities/some-tool.md` — drift: frontmatter says inferred=0.10, recomputed=0.45
- `concepts/transformers.md` — hub page (31 incoming links) with INFERRED=28%: errors here propagate widely
- `synthesis/speculation.md` — unsourced synthesis: no `sources:` field, 55% inferred
### Fragmented Tag Clusters (N found)
- **#systems** — 7 pages, cohesion=0.06 ⚠️ — run cross-linker on this tag
- **#databases** — 5 pages, cohesion=0.10 ⚠️
### Visibility Issues (N found)
- `entities/user-records.md` — contains `email:` value pattern but no `visibility/pii` tag
- `concepts/auth-flow.md` — tagged `visibility/pii` but missing `sources:` frontmatter
- `_meta/taxonomy.md` — contains `visibility/internal` entry (system tag must not be in taxonomy)
### Misc Promotion Candidates (N found)
Pages in misc/ that have ≥ 3 connections to a single project and are ready to be promoted:
| Page | Top Project | Affinity Score |
|---|---|---|
| `misc/web-martinfowler-articles-microservices.md` | `obsidian-wiki` | 4 |
### Typed Relationship Issues (N found)
- `concepts/foo.md` — relationships[1]: type "contradication" is not an allowed type
- `concepts/bar.md` — relationships[0]: target "[[skills/nonexistent]]" resolves to no page
### Synthesis Gaps (N found)
Concept pairs that co-occur frequently but have no synthesis page:
| Pair | Co-occurrence | Suggested Action |
|---|---|---|
| [[Caching]] × [[Consistency]] | 5 pages | Run `/wiki-synthesize` |
| [[Testing]] × [[Observability]] | 3 pages | Run `/wiki-synthesize` |
```
## After Linting
Append to `log.md`:
```
- [TIMESTAMP] LINT issues_found=N orphans=X broken_links=Y stale=Z contradictions=W prov_issues=P missing_summary=S fragmented_clusters=F visibility_issues=V promotion_candidates=C synthesis_gaps=G relationship_issues=R
```
Offer to fix issues automatically or let the user decide which to address.
---
## Consolidate Mode (`--consolidate`)
Triggered by `wiki-lint --consolidate`. Switches from report-only to **act-and-report** — the "dream cycle" that runs periodically so the wiki self-heals.
### Safety protocol
**Always run in dry-run first.** Before writing anything:
1. Run all 12 lint checks (Step 1–12 above).
2. Print the planned consolidation actions as a structured list (see Dry-Run Output below).
3. Ask the user: `"Apply these N changes? [yes / no / select]"`.
4. Only proceed with writes after explicit confirmation. If the user selects individual actions, apply only those.
5. Never merge pages — use `wiki-dedup` for that. Only link, promote, demote, and flag. Never apply `snapshot_mismatch` here; that stays on the snapshots CLI with its own confirmation (see Before You Start).
### Consolidation actions (in order, after confirmation)
**Pre-write snapshot** — before the first file write, check whether the vault itself is the root of a Git repository. Merely being a subdirectory of a larger repository does not qualify: running `git add -A` there could capture unrelated files. If the vault is not a standalone Git repository, skip this step silently — no nagging, no suggesting `git init`.
```bash
VAULT_REAL_PATH=$(cd "$OBSIDIAN_VAULT_PATH" && pwd -P)
VAULT_GIT_ROOT=$(git -C "$OBSIDIAN_VAULT_PATH" rev-parse --show-toplevel 2>/dev/null || true)
SNAPSHOT_SHA=""
if [ -n "$VAULT_GIT_ROOT" ] && [ "$VAULT_GIT_ROOT" = "$VAULT_REAL_PATH" ]; then
if git -C "$OBSIDIAN_VAULT_PATH" diff --quiet \
&& git -C "$OBSIDIAN_VAULT_PATH" diff --cached --quiet \
&& [ -z "$(git -C "$OBSIDIAN_VAULT_PATH" ls-files --others --exclude-standard)" ]; then
SNAPSHOT_SHA=$(git -C "$OBSIDIAN_VAULT_PATH" rev-parse HEAD)
else
if ! git -C "$OBSIDIAN_...
© Ar9av · MIT · Ar9av/obsidian-wiki
Похожие скиллы
Всё по теме «Заметки, задачи и проекты» →Сначала — wiki-lint от других авторов.