wiki-lint
Skill3.7k starsChanged 9 days agoMITView on GitHub
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.
- Reads credentials
42 other projects use a version of this, 2 of them edited.
Adopted by
Steady: 0 new projects took it in the last 4 weeks, none the 4 weeks before.thin data
Most recently taken up by
- ggoosen/Digital-Workforcetheir own version, first seen Nov 8, 2026
- barakgut/llm-wikitheir own version, first seen Nov 1, 2026
- chobizzy/llm-wikiedited, first seen Nov 1, 2026
- wareagledusty/wiki-federation-starter-kittheir own version, first seen Nov 1, 2026
- leiverkus/research-superpowerstheir own version, first seen Nov 1, 2026
- ProduktEntdecker/enterprise-memory-startertheir own version, first seen Nov 1, 2026
Who's talking about Ar9av/obsidian-wiki
- @ar9av.bsky.social“github.com/Ar9av/obsidi...”Bluesky · Oct 8, 2026 · 1 likes
- @pythonhub.dev“obsidian-wiki Framework for AI agents to build and maintain a digital brain through Obsidian wiki using …”Bluesky · Jun 23, 2026 · 1 likes
- sudosubin/agents.nix“claude-code-marketplaces.github.ar9av.obsidian-wiki: 2026.10.4 → 2026.11.2”GitHub · Nov 4, 2026
- sudosubin/agents.nix“claude-code-plugins.github.ar9av.obsidian-wiki: 2026.10.4 → 2026.11.2”GitHub · Nov 4, 2026
- sudosubin/agents.nix“agent-skills.github.ar9av.obsidian-wiki: 2026.10.4 → 2026.11.2”GitHub · Nov 4, 2026
The biggest 5 of 27 mentions linking to the repository that our crawl found. Each line is their own headline.
See all 27
Talked about on GitHub and Bluesky (27 times).
On GitHub · 25
- Nov 4, 2026claude-code-marketplaces.github.ar9av.obsidian-wiki: 2026.10.4 → 2026.11.2 — sudosubin/agents.nix0 reactions
- Nov 4, 2026claude-code-plugins.github.ar9av.obsidian-wiki: 2026.10.4 → 2026.11.2 — sudosubin/agents.nix0 reactions
- Nov 4, 2026agent-skills.github.ar9av.obsidian-wiki: 2026.10.4 → 2026.11.2 — sudosubin/agents.nix0 reactions
- Nov 2, 2026fix(deps): update dependency obsidian-wiki to v2026.10.4 — lkshrk/agent-stack0 reactions · 2 comments
- Nov 1, 2026chore(deps): update dependency pipx:obsidian-wiki to v2026.10.4 — lkshrk/agent-stack0 reactions · 2 comments
20 more on GitHub
- Oct 28, 2026claude-code-plugins.github.ar9av.obsidian-wiki: init at 2026.10.4 — sudosubin/agents.nix0 reactions
- Oct 28, 2026claude-code-marketplaces.github.ar9av.obsidian-wiki: init at 2026.10.4 — sudosubin/agents.nix0 reactions
- Oct 27, 2026agent-skills.github.ar9av.obsidian-wiki: 2026.10.3 → 2026.10.4 — sudosubin/agents.nix0 reactions
- Oct 21, 2026agent-skills.github.ar9av.obsidian-wiki: 2026.10.2 → 2026.10.3 — sudosubin/agents.nix0 reactions
- Oct 13, 2026agent-skills.github.ar9av.obsidian-wiki: 2026.10.1 → 2026.10.2 — sudosubin/agents.nix0 reactions
- Oct 3, 2026agent-skills.github.ar9av.obsidian-wiki: init at 2026.10.1 — sudosubin/agents.nix0 reactions
- Sep 27, 2026[Candidate] ar9av/obsidian-wiki/.skills/llm-wiki - llm-wiki — ProSkillsMD/proskills0 reactions · 2 comments
- Sep 27, 2026[Candidate] ar9av/obsidian-wiki/.skills/impl-validator - impl-validator — ProSkillsMD/proskills0 reactions · 2 comments
- Sep 27, 2026[Candidate] ar9av/obsidian-wiki/.skills/hermes-history-ingest - hermes-history-ingest — ProSkillsMD/proskills0 reactions · 2 comments
- Sep 26, 2026[Candidate] ar9av/obsidian-wiki/.skills/graph-colorize - graph-colorize — ProSkillsMD/proskills0 reactions · 2 comments
- Sep 26, 2026[Candidate] ar9av/obsidian-wiki/.skills/cross-linker - cross-linker — ProSkillsMD/proskills0 reactions · 2 comments
- Sep 26, 2026[Candidate] ar9av/obsidian-wiki/.skills/copilot-history-ingest - copilot-history-ingest — ProSkillsMD/proskills0 reactions · 2 comments
- Sep 26, 2026[Candidate] ar9av/obsidian-wiki/.skills/codex-history-ingest - codex-history-ingest — ProSkillsMD/proskills0 reactions · 2 comments
- Sep 26, 2026[Candidate] ar9av/obsidian-wiki/.skills/code-understand - code-understand — ProSkillsMD/proskills0 reactions · 2 comments
- Sep 26, 2026[Candidate] ar9av/obsidian-wiki/.skills/claude-history-ingest - claude-history-ingest — ProSkillsMD/proskills0 reactions · 1 comment
- Jul 12, 2026Add obsidian-wiki as a local workspace — aristoapp/awesome-second-brain0 reactions
- Jun 20, 2026feat: Obsidian-compatible wiki.md output from compiled graph — manhhailua/lorekeep0 reactions · 1 comment
- Jun 15, 2026Daily tribute 2026-06-15: obsidian-wiki by @_ar9av — Talonsturgill/signalsniper0 reactions
- May 15, 2026Tracking: AI workflow patterns & companion plugins — brenthaertlein/universal-skills0 reactions · 1 comment
- Apr 9, 2026wiki 生成质量提高 — nashsu/llm_wiki0 reactions · 2 comments
On Bluesky · 2
- Oct 8, 2026github.com/Ar9av/obsidi... — @ar9av.bsky.social1 likes and repost
- Jun 23, 2026obsidian-wiki Framework for AI agents to build and maintain a digital brain through Obsidian wiki using Karpathy's LLM Wiki pattern.… — @pythonhub.dev1 likes and repost · 1 reply
Used with
Projects with it also use wiki-init.
Other files people use alongside this one.
Files found in the same public projects as a version of this one, more often than they turn up anywhere else. Each project counts once, large collections count for less, and this file's own repository is left out.
bozhouDevSkillwiki-init
Use when bootstrapping a new personal wiki for any knowledge domain — research, codebase documentation, reading notes, competitive analysis, or any long-term knowledge accumulation project.
Also in 7 projects that use this
Other versions42 projects use a version of this.
Word for word · 0
None found.
Edited · 2
- Ivy-Chen1999/llm-wiki-kit★ 2157% same
- chobizzy/llm-wiki★ 347% same
Wrote their own version · 40
- AgriciDaniel/claude-obsidian★ 16ksame name
- kfchou/wiki-skills★ 189same name
- IssacW228/student-llm-wiki★ 173same name
- vanillaflava/llm-wiki-skills★ 65same name
- cookyman74/llmwiki-harness★ 34same name
- schub-tech/llm-ideation-wiki★ 11same name
- CarbeneAI/Forge★ 9same name
- CodePhobiia/claude-roblox-game-studio★ 9same name
- SantaJordan/gtm-engineer-starter★ 9same name
- crabin/llm-wiki★ 8same name
30 more not listed
How matches are found. Word for word: the exact same text. Edited: shares passages with this file (“99% same” means 99% of its five-word phrases also appear here; 10% or more counts). Their own version: similar meaning, or, weakest, the same name. We can’t tell which project had it first. Projects are counted among the 200 most-starred candidates, and mentions are links to the repository we found, up to 50 per site, so both counts are a floor.
In this repository43 other files it gives its agents.
- AGENTS.mdAGENTS.md
- docs/agents.mdAGENTS.md
- .github/copilot-instructions.mdCopilot instructions
- .cursor/rules/obsidian-wiki.mdcCursor rule
- claude-history-ingestSkill
- code-understandSkill
- codex-history-ingestSkill
- copilot-history-ingestSkill
- cross-linkerSkill
- daily-updateSkill
- graph-colorizeSkill
- hermes-history-ingestSkill
- impl-validatorSkill
- llm-wikiSkill
- memory-bridgeSkill
- obsidian-layout-adjustmentSkill
- openclaw-history-ingestSkill
- pi-history-ingestSkill
- session-brainSkill
- session-searchSkill
- skill-creatorSkill
- tag-taxonomySkill
- vault-skill-factorySkill
- wiki-agentSkill
- wiki-captureSkill
- wiki-context-packSkill
- wiki-dashboardSkill
- wiki-dedupSkill
- wiki-digestSkill
- wiki-exportSkill
- wiki-history-ingestSkill
- wiki-importSkill
- wiki-ingestSkill
- wiki-narrateSkill
- wiki-querySkill
- wiki-rebuildSkill
- wiki-researchSkill
- wiki-setupSkill
- wiki-stage-commitSkill
- wiki-statusSkill
- wiki-switchSkill
- wiki-synthesizeSkill
- wiki-updateSkill
The file
Show its rules and text
We split this skill into the rules it gives an agent
54 rules. 0 are common, 25 are distinctive, and 29 are very specific to this project.
0
Common
Most of the 33 edited versions we read keep these.
25
Distinctive
This author's own choices. Worth a look.
29
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- could be automatic: a setting could enforce it
- Very specific: line 11
Before scanning anything: follow the Retrieval Primitives table in llm-wiki/SKILL.md.
- Very specific: line 15
Writing profile: Before drafting or rewriting natural-language Markdown, read and apply the Writing Profile Resolution section in …
- Very specific: line 21
Read index.md for the full page inventory
- Very specific: line 22
Read log.md for recent activity context
- Very specific: line 28
When obsidian-wiki is on PATH, prefer obsidian-wiki lint "$OBSIDIAN_VAULT_PATH" --json (with the same schema override flags as above) and …
- Distinctive: line 34
Run these checks in order.
- Distinctive: line 49
Add wikilinks in appropriate sections
- Very specific: line 59
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 …
- Distinctive: line 63
If the target was renamed, update the link
- Distinctive: line 64
If the target should exist, create it
- Distinctive: line 65
If the link is wrong, remove or correct it
- Distinctive: line 69
Every page should have: title, category, tags, sources, created, updated.
- Distinctive: line 76
Add missing fields with reasonable defaults
- Very specific: line 80
Every page *should* have a summary: frontmatter field — 1–2 sentences, ≤200 chars.
- Distinctive: line 109
Look for phrases like "however", "in contrast", "despite" that may signal existing acknowledged contradictions vs.
- Distinctive: line 112
Add an "Open Questions" section noting the contradiction
- Very specific: line 117
Verify index.md matches the actual page inventory.
- Very specific: line 121
Check that summaries in index.md still match page content
- Very specific: line 125
Check whether pages are being honest about how much of their content is inferred vs extracted.
- Very specific: line 134
Drift: if the page has a provenance: frontmatter block, flag it when any field is more than 0.20 off from the recomputed value
- Very specific: line 155
Run the cross-linker skill targeted at the fragmented tag — it will surface and insert the missing links
- Distinctive: line 156
If a tag group is large (n > 15) and still fragmented, consider splitting it into more specific sub-tags
- Very specific: line 183
Run the cross-linker skill first if affinity scores look stale (e.g., affinity: {} on a page with many wikilinks)
- Distinctive: line 214
All other stale pages as a standard warning
- Distinctive: line 233
Verify the target page exists
- Very specific: line 234
Verify the target page is not itself archived (no circular or chained supersession)
- Distinctive: line 235
Verify there are no cycles (A supersedes B which supersedes A)
- Distinctive: line 242
How to check: Run the deterministic ledger validator first:
- Very specific: line 248
Use --strict for CI and scheduled gates: stale, unreviewed, or missing-page warnings then return nonzero.
- Distinctive: line 271
After a separately approved review of only specific stale/unreviewed pages, update only those entries:
- Distinctive: line 307
Add to the Wiki Health Report:
- Very specific: line 338
Before normalizing, drop everything from the first | (alias) or # (heading/block anchor): a pipe-aliased or heading-anchored target is not …
- Distinctive: line 381
Never "fix" a historical page by rewriting it as current — that destroys the record the window exists to keep
- Very specific: line 413
Run /wiki-synthesize to automatically discover and fill the top gaps
- Distinctive: line 497
Always run in dry-run first: Before writing anything:
- Distinctive: line 499
Run all 12 lint checks (Step 1–12 above).
- Very specific: line 501
Ask the user: "Apply these N changes?
- Distinctive: line 502
Only proceed with writes after explicit confirmation.
- Very specific: line 503
Never merge pages — use wiki-dedup for that.
- Very specific: line 535
If SNAPSHOT_SHA is non-empty and the skill writes files, include the SHA in the final report.
- Very specific: line 545
Search the vault for a page whose title or filename is the closest fuzzy match (use Grep across index.md titles)
- Very specific: line 546
If a unique best match exists (edit distance ≤ 2 characters or same root word): rewrite the link.
- Very specific: line 547
If no match or ambiguous: convert to plain text (~~[[Target]]~~ → Target) and add a comment <!-- broken link: no match found -->.
- Distinctive: line 548
Never create a new page just to satisfy a broken link.
- Very specific: line 562
Demote
verified→stale: NOT a state transition — stale is a computed overlay, not a lifecycle value. - Very specific: line 570
Do not demote tier: core pages automatically — those were manually set.
- Very specific: line 574
Read _meta/taxonomy.md for the alias mapping (e.g., ml → machine-learning).
- Very specific: line 579
Check whether a > ⚠️ Contradiction flagged with [[Other Page]] callout already exists near the relevant claim.
- Distinctive: line 580
If not, add it at the end of the "Key Ideas" section (or before "Open Questions" if no "Key Ideas" section).
- Distinctive: line 581
Do not resolve the contradiction.
- Very specific: line 585
After all actions, write a report to synthesis/consolidation-<YYYY-MM-DD>.md:
- Very specific: line 658
Use $QMD_CLI if set; otherwise use qmd.
- Distinctive: line 664
If the output says vectors are needed or embeddings may be stale, run:
- Distinctive: line 670
Verify the collection with either:
“Common” is measured: kept by at least 6 in 10 of the 33 edited versions of this file we could read. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
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.
- Resolve config — follow the Config Resolution Protocol in
llm-wiki/SKILL.md(inline@nameoverride → walk up CWD for.env→ global config → prompt setup). This givesOBSIDIAN_VAULT_PATHplus anyOBSIDIAN_ALLOWED_LIFECYCLES,OBSIDIAN_ALLOWED_RELATIONSHIP_TYPES,OBSIDIAN_REQUIRED_TRUST_FIELDS, andOBSIDIAN_SCHEMA_SOURCEvalues. - Read owner rules — if
$OBSIDIAN_VAULT_PATH/AGENTS.mdexists, read it before interpreting any schema. Owner rules override framework defaults. - 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.
- Read
index.mdfor the full page inventory - Read
log.mdfor 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
.mdfiles in the vault - For each page, Grep the rest of the vault for
[[page-name]]references - Pages with zero incoming links (except
index.mdandlog.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.mdinventory 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
.mdsuffix from what remains, then check if a corresponding.mdfile 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
updatedtimestamps to source file modification times - Flag pages where sources have been modified after the page was last updated
Uncovered sources. obsidian-wiki lint reports uncovered_sources: .manifest.json entries whose pages_produced/pages_created/pages_updated list is empty (no_pages) or names only pages that no longer exist (pages_missing). Each one is a source the vault says it ingested but no page now carries. A warning. For each, re-ingest the source, or point the manifest entry at the page that absorbed it (after a rename or wiki-dedup merge). Never delete the entry to silence the finding.
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.mdto actual files on disk - Check that summaries in
index.mdstill 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
- 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
- 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 tagactual_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-linkerskill 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 lacksvisibility/piiorvisibility/internal, flag it as a likely mis-classification. visibility/piiwithoutsources:: A page taggedvisibility/piishould always have asources:frontmatter field — if there's no provenance, there's no way to verify the classification. Flag anyvisibility/piipage missingsources:.- 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(orvisibility/internalif 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
affinityfrontmatter field - Flag pages where any single project's score ≥ 3
How to fix:
- Run the
cross-linkerskill 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 itscategoryfrontmatter, removepromotion_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 rewritesbase_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: verifiedwith 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 != archivedwhilesuperseded_byis 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:
obsidian-wiki trust-check "$OBSIDIAN_VAULT_PATH" --strict --json --prettyUse --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.ignored_entries— how many reviewed pages are now excluded by.okignore. A count only, so the pages stay unnamed. Anytrust-recordclears them.score_mismatches— material content still matches, but storedbase_confidencediffers 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:
obsidian-wiki trust-record "$OBSIDIAN_VAULT_PATH" \
--all --reviewed-at "<ISO-8601 timestamp>" --approved --json --prettyAfter a separately approved review of only specific stale/unreviewed pages, update only those entries:
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:
- Decompose the page into material claims and map each claim to evidence.
- 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.
- Assign reviewed quality per independent lineage using
llm-wikibuckets. - Compute the raw base score, then assess whole-page claim coverage. The formula is a starting point, not an automatic target.
- Classify the result as
raise,keep,lower, orrepair first; require approval before changingbase_confidenceor 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:
### 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.59Append to the LINT log entry:
- [TIMESTAMP] LINT ... lifecycle_issues=N13. 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:
- Type validation — flag any
type:value not in the allowed set above - Broken target — strip
[[and]]from thetarget:string, normalize (lowercase, spaces→hyphens, strip.md), and check whether a.mdfile 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. - Self-reference — flag any entry where the resolved target equals the page's own node id
- Type validation — flag any
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:
### 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=N14. 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:
- Date parseability — each value must be
YYYY-MM-DDor a full ISO 8601 timestamp. Flag anything else. - Window order — flag any page where
valid_untilprecedesvalid_from - Dangling successor — strip
[[/]]fromsuperseded_by, drop everything from the first|or#, strip.md, normalize, and check the page exists. Flag unresolved targets and self-references.
- Date parseability — each value must be
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:
### 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 vaultAppend to the LINT log entry:
... temporal_issues=N11. 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/andentities/ - For each pair, run a quick grep to count pages that link to both:
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-synthesizeto automatically discover and fill the top gaps
Output Format
Report findings as a structured list:
## 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=ROffer 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:
- Run all 12 lint checks (Step 1–12 above).
- Print the planned consolidation actions as a structured list (see Dry-Run Output below).
- Ask the user:
"Apply these N changes? [yes / no / select]". - Only proceed with writes after explicit confirmation. If the user selects individual actions, apply only those.
- Never merge pages — use
wiki-dedupfor that. Only link, promote, demote, and flag. Never applysnapshot_mismatchhere; 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.
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_VAULT_PATH" add -A; then
echo "Pre-write snapshot failed; abort the skill without writing any vault files." >&2
exit 1
fi
if ! git -C "$OBSIDIAN_VAULT_PATH" commit -m "pre-wiki-lint snapshot" --quiet; then
echo "Pre-write snapshot failed; abort the skill without writing any vault files." >&2
exit 1
fi
SNAPSHOT_SHA=$(git -C "$OBSIDIAN_VAULT_PATH" rev-parse HEAD)
fi
fiThe clean-repository branch deliberately avoids calling git commit, so "nothing to commit" is not treated as an error. If git add or git commit fails, stop before editing the vault; never continue without the promised snapshot.
If SNAPSHOT_SHA is non-empty and the skill writes files, include the SHA in the final report. To discard the entire run, after confirming there are no later changes worth keeping, the user can run:
git -C "$OBSIDIAN_VAULT_PATH" reset --hard "$SNAPSHOT_SHA"
git -C "$OBSIDIAN_VAULT_PATH" clean -fdAction 1: Fix broken wikilinks
For each broken [[Target]] found in Check 2:
- Search the vault for a page whose title or filename is the closest fuzzy match (use
Grepacrossindex.mdtitles) - If a unique best match exists (edit distance ≤ 2 characters or same root word): rewrite the link. Note the rewrite:
[[Oringal]] → [[corrected-page]]. - If no match or ambiguous: convert to plain text (
~~[[Target]]~~→Target) and add a comment<!-- broken link: no match found -->. - Never create a new page just to satisfy a broken link.
Action 2: Add missing cross-references for orphans
For each orphan page found in Check 1 (zero incoming links):
- Grep the vault body text for mentions of the page's title or aliases (case-insensitive).
- For each mention found in another page, add a
[[wikilink]]replacing the plain-text mention. - Limit to 3 insertions per orphan — don't flood pages with links.
- This is scoped to orphans only (different from
cross-linkerwhich runs broadly).
Action 3: Correct lifecycle states
Apply these rules automatically (they don't require human judgment — they enforce the documented state machine):
- Promote
draft→reviewed: pages wherelifecycle: draftANDcreated> 30 days ago ANDbase_confidence > 0.7. Setlifecycle: reviewed,lifecycle_changed: <today>,lifecycle_reason: "auto-promoted by wiki-lint --consolidate: age>30d, confidence>0.7". - Demote
verified→stale: NOT a state transition —staleis a computed overlay, not a lifecycle value. Instead: for verified pages whereis_stale = (today − updated) > 180 days, add a callout at the top of the page body:> ⚠️ **Stale**: This page was last updated <date>. Verify before relying on it.Only add if the callout isn't already present. - Do not change
reviewed→verifiedor any other transition — those are human-only.
Action 4: Tier demotion
For pages with tier: supporting (or unset) that have 0 incoming links AND haven't been updated in 90+ days:
- Set
tier: peripheral. - Emit a list of demotions for the user to review.
- Do not demote
tier: corepages automatically — those were manually set.
Action 5: Tag normalization
Read _meta/taxonomy.md for the alias mapping (e.g., ml → machine-learning). For each page, replace known alias tags with their canonical form in the tags: frontmatter field. This is a subset of tag-taxonomy's work — only alias fixes, no full audit.
Action 6: Contradiction callouts
For each pair of pages marked as contradicting each other (via relationships: contradicts in frontmatter, or flagged in Check 5):
- Check whether a
> ⚠️ Contradiction flagged with [[Other Page]]callout already exists near the relevant claim. - If not, add it at the end of the "Key Ideas" section (or before "Open Questions" if no "Key Ideas" section). Keep it concise — one line.
- Do not resolve the contradiction; only flag it visually.
Action 7: Write consolidation report
After all actions, write a report to synthesis/consolidation-<YYYY-MM-DD>.md:
---
title: Consolidation Report <YYYY-MM-DD>
category: synthesis
tags: [maintenance, consolidation]
sources: []
summary: Auto-generated consolidation report from wiki-lint --consolidate run on <date>.
lifecycle: draft
lifecycle_changed: <date>
tier: peripheral
created: <obsidian-wiki memory now>
updated: <obsidian-wiki memory now>
---
# Consolidation Report — <YYYY-MM-DD>
## Summary
- Broken links fixed: N
- Cross-references added: M
- Lifecycle states updated: K
- Tier demotions: D
- Tags normalized: T
- Contradiction callouts added: C
## Broken Link Fixes
- `concepts/foo.md:12` — [[OldTarget]] → [[correct-target]]
- `entities/bar.md:8` — [[Missing]] → `Missing` (no match found)
## Cross-References Added (orphan rescue)
- `concepts/baz.md` — now linked from: [[concepts/alpha]], [[skills/beta]]
## Lifecycle Updates
- `concepts/old-draft.md` — draft → reviewed (age 45d, confidence 0.74)
- `synthesis/stale-verified.md` — stale callout added (last updated 2025-10-01)
## Tier Demotions
- `concepts/unused-concept.md` — supporting → peripheral (0 links, 120 days stale)
## Tag Normalizations
- `entities/some-tool.md` — `ml` → `machine-learning`
## Contradiction Callouts
- `concepts/scaling.md` — flagged contradiction with [[synthesis/efficiency]]Dry-Run Output (shown before any writes)
wiki-lint --consolidate — Dry Run
Planned actions (N total):
[1] Fix broken link: concepts/foo.md:12 [[OldTarget]] → [[correct-target]]
[2] Add cross-ref: concepts/baz.md ← [[concepts/alpha]] (orphan rescue)
[3] Lifecycle: concepts/old-draft.md → reviewed (age 45d, confidence 0.74)
[4] Tier demotion: concepts/unused.md → peripheral (0 links, 112 days stale)
[5] Tag alias: entities/some-tool.md: ml → machine-learning
[6] Contradiction callout: concepts/scaling.md ↔ [[synthesis/efficiency]]
Apply these 6 changes? [yes / no / select by number]Log entry for consolidate mode
- [TIMESTAMP] LINT_CONSOLIDATE links_fixed=N orphans_rescued=M lifecycle_updates=K tier_demotions=D tag_fixes=T contradiction_callouts=C report=synthesis/consolidation-YYYY-MM-DD.mdQMD Refresh After Vault Writes
QMD is a search index, not the source of truth. If $QMD_WIKI_COLLECTION is empty or unset, skip this step. Run it only after this skill has written or rewritten vault markdown. If QMD refresh fails, do not roll back the vault changes; report the QMD status separately.
Use $QMD_CLI if set; otherwise use qmd.
${QMD_CLI:-qmd} updateIf the output says vectors are needed or embeddings may be stale, run:
${QMD_CLI:-qmd} embedVerify the collection with either:
${QMD_CLI:-qmd} ls "$QMD_WIKI_COLLECTION"or, when a specific page path is known:
${QMD_CLI:-qmd} get "qmd://$QMD_WIKI_COLLECTION/<page>.md" -l 5Record one of:
QMD refreshed: update + embed + verifiedQMD refreshed: update only + verifiedQMD skipped: QMD_WIKI_COLLECTION unsetQMD skipped: qmd CLI unavailableQMD failed: <short error summary>
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

