
Llm Wiki
- 17 installs
- 154 repo stars
- Updated July 30, 2026
- sammcj/agentic-coding
Helps with ai & agent building tasks.
About
llm-wiki is a Claude Code skill for ai & agent building. It helps solo builders move faster with AI-assisted development.
- llm-wiki
- AI & Agent Building
- AI-coding skill
Llm Wiki by the numbers
- 17 all-time installs (skills.sh)
- +1 installs in the week ending Jul 26, 2026 (Skillselion tracking)
- Ranked #10,813 of 16,556 AI & Agent Building skills by installs in the Skillselion catalog
- Data as of Aug 1, 2026 (Skillselion catalog sync)
npx skills add https://github.com/sammcj/agentic-coding --skill llm-wikiAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 17 |
|---|---|
| repo stars | ★ 154 |
| Last updated | July 30, 2026 |
| Repository | sammcj/agentic-coding ↗ |
What it does
Helps with ai & agent building tasks.
Files
LLM Wiki
Build and maintain a personal knowledge base as plain markdown. You manage two directories: raw/ (immutable source material) and wiki/ (compiled knowledge you own). Sources land in raw/, you compile them into wiki/ articles, and the wiki compounds over time. Everything is local markdown with YAML frontmatter, readable on GitHub and openable as an Obsidian vault. No servers, no databases, no embeddings.
Core idea (Karpathy): the LLM writes and maintains the wiki; the human chooses sources and asks questions. Knowledge is compiled once at ingest and kept current, not re-derived on every query. That is the difference from RAG, which retrieves raw chunks and re-synthesises on every question.
Invocation
Query is the default. Ingest, Lint, Audit, and Critique are the four deliberate operations - each opted into by its verb or by a request that plainly calls for it. Anything else is a Query against the wiki: a bare question, "what do I know about X", "summarise everything on Y". You do not need a query keyword to query; it is what the skill does unless one of the four operations is clearly being asked for.
A leading mode argument routes straight to that operation:
ingest(aliasadd) - Ingest. Any trailing text is the source: a URL, a path, or pasted content.lint- Lint. Health checks; needs no further input.audit- Audit. Trailing text names the article or topic to verify.critique(aliasscrutinise) - Critique. Trailing text names the article, topic, or pasted content whose reasoning to examine.query(aliasask) - Query. Rarely needed as an explicit keyword, but it forces query handling when a question might otherwise look like one of the four operations above.
So /llm-wiki lint runs Lint and /llm-wiki ingest https://... ingests that URL. Otherwise treat the whole argument as a natural-language request: route it to Ingest, Lint, Audit, or Critique only when it clearly calls for one, and answer everything else as a Query.
What's always required, and what's scenario-gated
Every operation, always: you act only on the user's request (never background-write); any write compiles from a source already in raw/ (never straight from a live URL or external path), then updates wiki/index.md and appends wiki/log.md; you bump an article's updated whenever its content changes; and you replace outdated knowledge by superseding it, never by deleting or editing in place. These hold across all five operations.
Everything else is scenario-gated, and its detailed protocol lives in references/ - the authoritative procedure, which SKILL.md only summarises. When the request or the situation matches one - a rich-format source, a distilled extract, a long or noisy source, a concept map, the gap register, local content, a lint, an audit, a critique - you MUST read the named reference and follow it before acting, rather than working from memory or assuming you know the format or the steps. If a section points at a reference, that pointer is an instruction to open it, not a citation to note. When unsure whether a reference applies, read it and decide; the cost of reading is small next to the cost of corrupting the wiki by guessing.
Design philosophy
These principles decide what the wiki does and, just as much, what it leaves out. Follow them when a situation is not covered explicitly below.
- Filter at ingest, not in retention. Decide what is worth keeping, and strip secrets, when a source arrives. A clean ingest avoids most cleanup later.
- Supersession, not decay. Knowledge does not expire on a timer. When new information replaces old, mark the old article stale and point it at the replacement. Keep it. An old bug report or a superseded decision still explains why the current state exists.
- Evidence, not confidence scores. Never attach a number like
0.85to a claim. State the support instead: which sources confirm it, which contradict it, when it was last confirmed. A reader can check links; they cannot check a float. - Git is the audit trail. History, rollback, and "how did this get here" come from version control, not from bespoke versioning fields. Recommend the wiki live in a git repo.
- Invocation-driven, human in the loop. You act when the user asks. Do not set up background automation that writes to the wiki unsupervised. The user curates and directs; you do the bookkeeping.
- Text-only and self-contained. Plain markdown, relative links, YAML frontmatter. Readily available tools (grep, git, the agent's own file and web tools) are fine. External servers, vector stores, and embedding pipelines are not.
Deliberately excluded, and why: embedding or vector search and knowledge-graph databases (infrastructure the personal scale does not need; index plus grep covers it); numeric confidence scores (false precision); automatic forgetting or decay curves (they bury exactly the errors and superseded decisions you most need to remember); autonomous background writes (an unreviewed LLM corrupts the base silently); multi-agent sync and governance layers (out of scope for a personal wiki).
Architecture
Three layers, all under the user's project root, plus an optional local/ for personal content.
raw/ - Immutable source material. You read, never modify. Organised by topic subdirectories, e.g. raw/machine-learning/. The source of truth.
wiki/ - Compiled knowledge articles. You have full ownership. One level of topic subdirectories only: wiki/<topic>/<article>.md. Four special files:
wiki/README.md- Orientation for anyone opening the wiki without this skill: what the structure is and the conventions that keep it sound. Mostly static; created at init.wiki/index.md- Global catalogue. One row per article, grouped by topic, with link, summary, and Updated date. The entry point for queries.wiki/log.md- Append-only operation log with a greppable prefix.wiki/gaps.md- Register of known unknowns: concepts the wiki references but has not written, and questions it cannot answer. "What we don't know yet" to the index's "what we know".
local/ (optional) - Personal markdown kept out of git: meeting prep, drafts, working notes, private sources. A sibling of raw/ and wiki/, excluded by the wiki .gitignore, present in the user's clone only. It is a scratch bench, exempt from the index, log, gaps, cascade, and audit. One rule governs it: local/ may link into wiki/ and raw/, but no committed file may ever link into local/ (broken for other clones, and it leaks the path into git). Full rules, query behaviour, and the promotion path: references/local-content.md.
SKILL.md (this file) - The schema layer. Defines structure, format, and workflow. This is the most important file in the system: it is what makes a disciplined wiki maintainer rather than a generic chatbot. Templates live in references/ relative to this file; read them when you need the exact format.
File format
Every article and raw file starts with YAML frontmatter, then standard markdown. Frontmatter is machine-readable (the agent parses it; Obsidian shows it as Properties; the Dataview plugin can query it). The body uses standard markdown links so it renders everywhere, including GitHub, and still populates Obsidian's graph and backlinks panel.
Article frontmatter:
---
title: Transformer Architectures
type: concept # concept | entity | archive
topic: machine-learning
created: 2026-04-03
updated: 2026-04-03
status: current # current | stale
superseded_by: # relative path to replacement, set only when status: stale
tags: [transformers, attention]
aliases: []
---updatedis the canonical "knowledge last changed" date. The index mirrors it; lint reads it. It changes when the article's content changes, not when the file is touched.type: archivemarks crystallised query answers (see Query). Archives are point-in-time and are never cascade-updated.statusandsuperseded_bydrive supersession (see below). Leavesuperseded_byempty for current articles.tagsandaliasesare optional and exist for Obsidian and Dataview; the agent does not depend on them.
Links and paths
Inside wiki/ files, all links are relative to the current file:
- Same topic:
[Other Article](other-article.md) - Different topic:
[Other Article](../other-topic/other-article.md) - Raw file:
[Source](../../raw/topic/file.md)(two levels up to project root)
In conversation output, use project-root-relative paths, e.g. wiki/topic/article.md. superseded_by in frontmatter uses the same file-relative path form as body links.
Special files
wiki/README.md orients a reader who has the wiki but not this skill: the raw/wiki split, the frontmatter fields, supersession-not-deletion, and what index.md, log.md, and gaps.md are, with a pointer to the skill for the full workflow. It is the GitHub landing page for the wiki directory. Keep it high-level and mostly static - it describes the format, not the catalogue, so it does not change on every ingest. Do not copy the operational procedures from this file into it; point to them. Template: references/templates/wiki-readme-template.md.
wiki/index.md is the human-readable catalogue and the agent's first read on any query. Hand-maintained. If the user has Obsidian with Dataview, parts of it can be auto-generated from frontmatter, but never depend on a plugin: the maintained index.md is canonical.
wiki/log.md is append-only and chronological, a convenience over git history, which holds the canonical record. Each entry starts with ## [YYYY-MM-DD] <op> | <title> so grep "^## \[" wiki/log.md | tail -5 returns recent activity. Keep entries lean: the header carries the signal, and a sub-item names another article touched rather than narrating the change in prose. Operations only ever append; lint prunes the oldest entries for retention when the wiki is a git repo, so the file stays bounded and git recovers the rest.
wiki/gaps.md is the register of known unknowns. Two kinds of entry: wanted (a concept articles reference but no page covers) and question (something a source raised or a user asked that the wiki cannot answer). Entries are grouped by topic and ranked by evidence of demand - which articles reference the gap, how often it has been asked - never by a score. Gaps are captured during ingest, query, and lint, never by a background process; they close by a resolution link rather than deletion, the same as supersession; and the file is greppable (grep "^### \[open\]" wiki/gaps.md). Full format, capture rules, and lifecycle: references/gaps.md.
Initialisation
Triggers only on the first Ingest. Check whether raw/ and wiki/ exist. Create only what is missing; never overwrite existing files:
raw/directory (with.gitkeep)wiki/directory (with.gitkeep)wiki/README.md- orientation doc fromreferences/templates/wiki-readme-template.mdwiki/index.md- heading# Knowledge Base Index, empty bodywiki/log.md- heading# Wiki Log, empty bodywiki/gaps.md- heading# Knowledge Gaps, empty body (references/gaps.md).gitignore(project root) - fromreferences/templates/wiki-gitignore-template.md. Excludeslocal/and per-machine editor noise so the wiki can live in git cleanly. Do not overwrite an existing one; merge in thelocal/line if missing.SKILL.md(project root) - lets the wiki load as a query-only Agent Skill, fromreferences/templates/wiki-skill-template.md. See "The wiki as a skill" below.CLAUDE.md(project root) - project memory that orients any agent whose working directory is the wiki repo and tells it to activate the llm-wiki skill if present, fromreferences/templates/wiki-claude-md-template.md. See "The wiki's CLAUDE.md" below.
local/ is not created at init; it appears the first time the user stores personal content there (references/local-content.md).
If Query or Lint cannot find the wiki structure at the working directory, first check whether the directory instead holds several wiki subdirectories (each with its own wiki/ and raw/): that is a multi-wiki setup, handled per "Working across separate wikis" above, not an uninitialised wiki. Only when neither a wiki nor sibling wikis are present, tell the user: "Run an ingest first to initialise the wiki." Do not auto-create.
The wiki as a skill
SKILL.md at the project root lets an agent load the wiki as an Agent Skill and query it without this skill present. It is a different file from this skill's own SKILL.md: lightweight, mostly links into wiki/index.md and wiki/README.md, and read-only. Write it at init from references/templates/wiki-skill-template.md, which carries the exact format.
- Name and describe it from the content. Name it
<subject>-llm-wiki(e.g.ml-llm-wiki,team-runbook-llm-wiki), choosing the prefix from the wiki's subject or audience, so the name signals it is an llm-wiki. A skill's name must match the directory it loads from, so tell the user to load the wiki directory under that name. Write adescriptionthat says what the wiki is for and names concrete trigger topics. At init the wiki may be near-empty - write your best guess from the first sources or the user's stated purpose, and refreshnameanddescriptionas it grows. - Query only; writes go through llm-wiki. The file routes every add, update, supersede, lint, and audit back to this skill, and reminds the user that llm-wiki is required to keep the wiki current. It must not describe a write workflow of its own. When you create it, tell the user that the llm-wiki skill must stay installed to maintain the wiki.
- Created at init, never overwritten. Lint reports a missing one and offers to add it to wikis that predate this (
references/lint.md).
The wiki's CLAUDE.md
CLAUDE.md at the project root is project memory: an agent auto-loads it whenever the wiki repo is its working directory, no skill required. It complements the root SKILL.md - SKILL.md loads by description match, CLAUDE.md by location, so it is the entry point for an agent working inside the wiki. Keep it tiny: state what the repo is, point the agent at the root SKILL.md to learn how to interface with the wiki, and tell it to activate the llm-wiki skill if available (otherwise treat the wiki as read-only and route writes through it). It defers the query steps to SKILL.md rather than repeating them. Write it at init from references/templates/wiki-claude-md-template.md; created once, never overwritten. Lint reports a missing one and offers to add it (references/lint.md).
Working across separate wikis
A user may keep several independent wikis side by side - each a full, self-contained llm-wiki cloned wherever they like (e.g. ~/git/wikis/{ml,payments,ops}/). The wikis do not nest and do not know about each other; there is no host wiki and no shared root inside any of them.
When your session's working directory holds more than one wiki (subdirectories that each have their own wiki/ and raw/), you are in a multi-wiki setup. Two rules then apply, and the full protocol is in references/multiple-wikis.md - read it before querying or maintaining across wikis:
- Catalogue them in `WIKI-INDEX.md`. Maintain a
WIKI-INDEX.mdat that working directory (create it if missing): what each wiki is for and how to tell them apart, plus the cross-wiki rules below. If a wiki's purpose is not clear from its own README/SKILL, ask the user rather than guessing. - Each wiki is isolated; read its own instructions first. Before you query or change a wiki, read that wiki's own
CLAUDE.mdandSKILL.md(and any skill it bundles) - they do not auto-load from a parent directory. No wiki links or refers to another. If a fact in one wiki is worth having in another, ask the user, then add a version to the target as a normal ingest (cite the true origin; never link across wikis).
---
Ingest
Fetch a source into raw/, then compile it into wiki/. Always both steps.
Decide how much of the source to keep
Decide this before fetching or converting; it sets what lands in raw/.
- Verbatim (default) - a faithful copy of the source, the immutable ground truth Audit checks against. Use it unless the user asks otherwise.
- Distilled - the high-signal content only, with filler removed. Choose it when the user asks for "the valuable content", "the high-signal parts", "the useful bits", "just the signal", "the key points", "what matters" or similar - phrasing that wants the substance, not the whole source. Follow
references/distilled-ingest.md, which distils by removing filler rather than generalising specifics away, and ends in a mandatory separate-sub-agent review so nothing load-bearing is cut.
Pick one mode per source. A rich format (a docx transcript, a PDF) does not decide it: convert to markdown as an intermediate step, then keep or distil per the chosen mode. Converting a transcript and copying it in whole when the user asked for the signal is the failure to avoid. If a long, noisy source carries no instruction either way, ask rather than defaulting to a verbatim dump.
Fetch (raw/)
1. Get the source content using whatever web or file tools your environment provides. If nothing can reach the source, ask the user to paste it directly.
2. Filter before writing. Strip secrets and credentials (API keys, tokens, passwords) and obvious private data (PII that is not the point of the source). If a source is mostly sensitive, flag it and ask the user before saving rather than redacting silently.
3. Pick a topic directory. Check existing raw/ subdirectories first; reuse one if the topic is close enough. Create a new subdirectory only for genuinely distinct topics.
4. Save as raw/<topic>/YYYY-MM-DD-descriptive-slug.md:
- Slug from source title, kebab-case, max 60 characters.
- Published date unknown -> omit the date prefix from the file name. The frontmatter
publishedfield still appears, set toUnknown. - If a file with the same name exists, append a numeric suffix, e.g.
descriptive-slug-2.md. - Include frontmatter (source, collected, published) and preserve the original text (verbatim mode; a distilled extract follows
references/distilled-ingest.mdinstead). Clean formatting noise; do not rewrite opinions.
See references/templates/raw-template.md for the exact format.
Tip: Use sub-agents with well defined goals, scope and context to parallelise work and reduce context rot in the main conversation.
Rich and external sources
raw/ holds durable markdown only. When a source is a rich format (PDF, Word, slides, images, spreadsheets), convert it to markdown before saving, following references/rich-format-ingest.md: it covers structure preservation, the faithfulness review, and what to do with the original file. If the user asked for the high-signal content rather than the whole source (see "Decide how much of the source to keep"), the converted markdown is an intermediate step, not the raw file you keep - distil it per references/distilled-ingest.md.
Compile only from `raw/`. Land every source as markdown in raw/ before compiling, never straight from a live URL or an external path (a temp file vanishes, a URL changes; the Raw provenance link must persist). If a markdown file is already in raw/, skip the fetch and compile it directly.
Another of the user's wikis can be the origin of a source. To carry a fact across, re-land its underlying source into this wiki's raw/ and compile it like any normal ingest, citing the true upstream origin - never a link into the other wiki. The cross-wiki rules are in references/multiple-wikis.md.
Compile (wiki/)
Decide where the new content belongs:
- Same core thesis as an existing article -> Merge into it. Add the new source to the article's Sources/Raw lines. Update affected sections and bump
updated. - New concept -> Create a new article in the most relevant topic directory. Name the file after the concept, not the raw file. Write full frontmatter. Give it at least one inbound link from a related article (a See Also or an in-body reference), not just an
index.mdrow - an article nothing links to is an orphan. - Spans multiple topics -> Place in the most relevant directory; add See Also links to related articles elsewhere.
These are not exclusive: one source may merge into an existing article while also creating a new article for a distinct concept it introduces.
When a source is persuasive or argumentative rather than factual - an opinion piece, a vendor's case for its product, a strategy memo - consider a Critique pass (references/critical-analysis.md) before compiling it as settled knowledge, so its reasoning risks are on record. Report them and let the user decide; a common outcome is to attribute a contested claim to its source rather than assert it, or to log the open question in gaps.md.
One article, one concept. Merging keeps related knowledge together, but repeated merges can grow an article past its thesis. When an article has come to cover more than one distinct concept - typically visible as top-level sections that could each stand alone - split the secondary concept into its own article, leave a one-line summary and a See Also link in its place, and cross-link the two. Split on concept boundaries, not length: a long article on a single concept is fine. As a rough prompt to recheck scope, revisit an article that climbs past ~400-500 lines, but never split on line count alone.
Concept maps (optional). When several articles relate in a way prose handles poorly - branching, convergence, a supersession or causal chain - a small mermaid diagram can earn its place. Draw one only when it adds what a sentence cannot; a map that restates the See Also list or a linear A -> B -> C is noise, and a map with no value is worse than none. A map in a current article is load-bearing: it carries a map-sources marker and is maintained on cascade updates; a map in a type: archive page is a dated snapshot. The when/when-not test, the colour palette, the format, freshness, and how to brief a sub-agent to draw one (sub-agents propose, you embed) are in references/concept-map.md.
See references/templates/article-template.md for the format. Provenance lives in the body as clickable links:
- Sources line: author, organisation, or publication + date, semicolon-separated.
- Raw line: markdown links to
raw/files, semicolon-separated.
Long-form and noisy sources
Transcripts, chat logs, long articles, and interview notes carry load-bearing detail that one compile pass can silently drop or soften. When a source is long or noisy, extract the durable items (decisions, claims, numbers, named entities, open questions) as a list first, write the article from that list, then re-read the source once against the article to confirm nothing important was lost, hardened, or overstated. Keep the source's exact terms, figures, and hedging, and anchor the heaviest claims with an inline quote and a locator (the section, page, or timestamp) next to their raw link. For short, clean, single-claim sources the normal compile above is enough. Full protocol: references/high-fidelity-ingest.md.
Distilling an external source
When the retention mode is distilled (see "Decide how much of the source to keep") - the user points at a verbose external source like a meeting transcript, call notes, or a long thread and wants its valuable content kept rather than the whole source - read references/distilled-ingest.md and follow it. The extract saved to raw/ is marked fidelity: distilled (a derived artefact, not the verbatim source). The protocol distils by cutting filler and repetition without generalising away specifics - numbers, hedging, dissent, owners, conditionals, and open questions all stay - and ends in a mandatory critical review by a separate sub-agent before the source may be discarded, the guard against over-zealous cutting. This is the opposite choice from "Long-form and noisy sources" above, which keeps the verbatim source in raw/.
Conflicts and supersession
Check whether the new source disagrees with existing content.
- Disagreement, both views still plausible -> Annotate the conflict inline with an evidence chain, attributing each side: "Uses Redis for caching (Source A, Source B); Source C reports Memcached." Do not pick a winner with a number. If the conflicting claims live in separate articles, note it in both and cross-link them.
- New source clearly replaces old knowledge -> Supersede, do not delete. On the old article: set
status: staleandsuperseded_by:to the replacement's path, and add a callout directly under the title:
> [!warning] Superseded by [New Article](new-article.md) (2026-04-03). Kept for history.Create or update the replacement article as a normal current article, mentioning in prose what it replaces. Git history preserves the rest; no decay, no deletion.
Cascade updates
After the primary article, check for ripple effects:
1. Scan articles in the same topic directory for content affected by the new source. 2. Scan wiki/index.md entries in other topics for related concepts. 3. Update every materially affected article and bump its updated date.
Never cascade-update type: archive pages or status: stale pages. Archives are snapshots; stale pages are history.
Post-ingest
Update wiki/index.md: add or update entries for every touched article, with the updated date from frontmatter. When adding a new topic section, include a one-line description. Prefix a stale article's summary with [Stale].
Update wiki/gaps.md if this ingest touched the frontier of what is known: record a load-bearing open question the source raised but did not answer, or a concept you forward-referenced with no page yet, as a new entry; and close (resolve-and-link) any gap a new article filled. Skip it when nothing changed. See references/gaps.md.
Append to wiki/log.md:
## [YYYY-MM-DD] ingest | <primary article title>
- Created: <additional new article title>
- Updated: <cascade-updated article title>
- Superseded: <old article title> -> <new article title>Omit any sub-item that does not apply. The header names the primary new article; - Created: lists any additional articles the same source produced. Refer to articles by title, not file path, and keep each sub-item to the title alone - the article body and the git diff hold what changed, so do not restate it here.
Bulk and parallel ingest
For many sources at once (a folder of meeting transcripts, a backlog import) or when a single pass would exhaust context, split the work: parallelise the extract, keep the compile serial. The full protocol and the ingest-proposal schema are in references/bulk-ingest.md.
These rules keep a parallel batch from corrupting the wiki:
- Pre-assign the topics before fan-out. Read the existing
raw/andwiki/topics, fix the topic set for the batch, and hand it to every sub-agent so they cannot invent divergent names for the same thing. - Sub-agents extract; they do not compile. Each writes its sources only under
raw/<assigned-topic>/and returns a structured proposal. They never touchwiki/,index.md, orlog.md, so there are no write races. - The orchestrator is the sole writer to `wiki/`, `index.md`, and `log.md`. It merges proposals against one consistent view: combine same-concept proposals into a single article with a shared evidence chain, apply in source-date order so supersession resolves newest-first, then cascade and update the index and log once.
- Checkpoint before committing. Present a digest (created, merged, superseded, conflicts surfaced) and wait for the user before the batch
git commit. Favour quality over volume: ten well-supported articles beat fifty thin ones, and this checkpoint is where that gets enforced.
Documenting a codebase
When the wiki's subject is a codebase rather than external reading, the core workflow is unchanged but a few conventions help: topic directories and slug prefixes that fit source code, a rule for where the wiki ends and the repo's own README begins, and how to record decisions reconstructed from code and git history. Optional recipe: references/codebase-wiki.md.
---
Query
Search the wiki and answer questions. Triggers: "What do I know about X?", "Summarise everything on Y", "Compare A and B from my wiki".
Steps
1. Read wiki/index.md to locate relevant articles. 2. Read those articles. To find connections the index misses, follow body links and use backlinks: grep -rl "article-name.md" wiki/ lists pages that link to a given article. (In Obsidian, the graph view and backlinks panel show the same structure.) 3. Synthesise an answer. Prefer wiki content over your own training knowledge. Cite with markdown links: [Article Title](wiki/topic/article.md) (project-root-relative in conversation). 4. Note when a cited article is status: stale, and point to its replacement. 5. If local/ exists, search it too and fold in any relevant personal notes, labelling each hit clearly as local/ (uncommitted) so it is never mistaken for shared knowledge (references/local-content.md). A query runs against one wiki; never silently fold another of the user's wikis into the answer. If the question really spans wikis, say so and ask which to draw on (references/multiple-wikis.md). 6. Output the answer in the conversation. Do not write files unless asked. 7. Capture a miss. If the wiki could not answer, or answered only partially, and the question sits within the wiki's subject, propose recording it in wiki/gaps.md: append today's date to a matching gap's demand evidence, or add a new question entry. Record only with the user's go-ahead; a plain query writes nothing on its own. See references/gaps.md.
When the user asks not just what the wiki says but whether the reasoning behind it holds - to scrutinise or stress-test an answer or a wiki position rather than retrieve it - switch to Critique and follow references/critical-analysis.md.
Crystallise (archive)
When the user asks to save the answer to the wiki, file it as a first-class page so the exploration compounds like an ingested source.
1. Write the answer as a new article with type: archive. See references/templates/archive-template.md. Convert conversation citations to file-relative paths (e.g. wiki/topic/article.md becomes ../topic/article.md, or article.md for the same directory).
- Sources line: markdown links to the wiki articles the answer cites.
- No Raw line (content does not come from
raw/). - Capture the question, the findings, the articles and entities involved, and any lesson worth keeping as a standalone point.
- When the relationships are non-linear, a concept map can capture them; in an archive it is a snapshot (no
map-sourcesmarker, never cascade-checked). Seereferences/concept-map.md. - File name reflects the query topic; place in the most relevant topic directory.
2. Always create a new page; never merge an archive into an existing article. 3. Update wiki/index.md, prefixing the summary with [Archived]. 4. Append to wiki/log.md:
## [YYYY-MM-DD] query | Archived: <page title>---
Lint
Health checks on the wiki, in two tiers with different authority. The load-bearing boundary: deterministic problems are auto-fixed; anything needing judgement is reported, never silently rewritten. You never rewrite article prose on your own authority. Lint checks the wiki's internal consistency; to verify an article against the sources it cites, use Audit.
Before fixing anything you MUST read `references/lint.md` and follow it - it enumerates every check in each tier and its exact fix behaviour. SKILL.md states only the boundary; the checks below are an index, not the procedure.
- Deterministic (auto-fix): index consistency, internal and raw links, frontmatter, See Also, log retention, the wiki skill file's links, concept-map freshness, the gap register, and the
local/leak guard. Safe to repair without asking. - Heuristic (report only): factual contradictions, supersessions never marked stale, orphan pages, missing cross-references, undocumented concepts (propose as
wantedgaps), open gaps an article now answers, multi-concept articles, drifted archives, low-value concept maps, and a missing rootSKILL.md,CLAUDE.md, or wiki.gitignore. Surface them; never auto-fix.
Two dependency-free helpers back the deterministic tier, read-only and run with uv when available: scripts/lint_wiki.py <project-root> for structural findings (frontmatter, index, links, raw, and the local/ leak guard) and scripts/lint_mermaid.py for concept-map validity. Run them rather than improvising a shell script (a heredoc mangles !); when uv is absent, fall back to grep and the file tools, and check mermaid by eye. The helpers detect; you apply the fixes.
Post-lint
Append to wiki/log.md:
## [YYYY-MM-DD] lint | <N> issues found, <M> auto-fixed---
Audit
Verify that an article's claims hold up against the raw/ sources it cites. Where Lint checks internal consistency (links, frontmatter, index), Audit checks external fidelity: do the cited sources actually support what the article says - the verification the evidence chains imply but never enforce. Opt-in and user-invoked on a named article or topic, never automatic; it reads every cited source in full. Triggers: "audit X", "check the citations on Y", "does the wiki still match its sources".
Before auditing you MUST read `references/audit.md` and follow it - it carries the claim-extraction steps, the per-source sub-agent prompt, and the verdict schema. In outline: pick the target (skip status: stale and type: archive pages unless asked); list the article's provenance-bearing claims, including each labelled concept-map edge, and map each to the raw/ file that should back it (a load-bearing claim with no cited source is itself a finding); dispatch one read-only sub-agent per source in parallel to verdict each claim - supported, partial, unsupported, or source-missing - with the passage that backs it; aggregate worst-first and report, quoting what the source actually says for anything not supported. Report only - never rewrite article prose on your own authority (the same boundary as Lint's heuristic tier); a failed claim is surfaced for the user to fix, supersede, or accept.
Post-audit
Append to wiki/log.md:
## [YYYY-MM-DD] audit | <article or topic>: <N> claims, <S> supported, <U> unsupported/partialIf the user asks to keep the audit, crystallise it as a type: archive page (see Query > Crystallise), citing the audited article.
---
Critique
Examine the reasoning in a source or article and report what holds up. Where Audit checks external fidelity (do the cited raw/ sources support the claims), Critique checks internal soundness: argument structure, hidden assumptions, logical fallacies, bias risk, internal consistency. It deliberately does not fact-check empirical claims against the world - that is Audit's job - so the two are complementary halves of "is this knowledge trustworthy". Like Audit, it is opt-in, user-invoked, read-only, and reports its findings; it never rewrites prose. It runs on whatever the user points at - a raw/ source, a wiki/ article, or pasted content - and needs no raw/ to run. Triggers: "critique X", "is this argument sound?", "what is this assuming?", "stress-test the reasoning in Y".
Before critiquing you MUST read `references/critical-analysis.md` and follow its analysis steps and output structure - do not work from memory. In outline: pick the target (or several); work through the reasoning - understand the argument as the author would state it, isolate the core claims, weigh the evidence, spot logical issues, surface hidden assumptions, check what is missing and whether it is internally consistent; report the four sections - Summary, Key Issues, Questions to Probe, Bottom Line. Say so plainly when the reasoning is sound; do not manufacture criticism. For many targets, fan out one read-only sub-agent per target in parallel, then present grouped weakest-first.
Post-critique
Append to wiki/log.md:
## [YYYY-MM-DD] critique | <article, topic, or source>: <overall assessment>Critique writes nothing else on its own. With the user's go-ahead it may crystallise the analysis as a type: archive page (see Query > Crystallise) citing the critiqued target, or record an assumption or open question it surfaced as a question gap in wiki/gaps.md (references/gaps.md). Full protocol, output structure, and guidelines: references/critical-analysis.md.
---
Gotchas
The subtle failure points, worth checking before you finish an operation.
Paths and consistency
- Path direction inside the wiki. From
wiki/<topic>/, a raw file is two levels up (../../raw/<topic>/file.md) and a same-topic article is just its filename. A wrong../count is the most common broken link. - Keep `updated` and the index in step. Whenever an article's content changes (a cascade update or a supersession counts), bump
updatedin its frontmatter and the matchingindex.mdrow in the same pass. They are meant to agree, and drift between them is easy to miss.
Ingest fidelity
- Ingest is fetch and compile. A source saved to
raw/but never compiled intowiki/adds nothing. Finish both, and updateindex.mdandlog.md, before treating the ingest as done. - Long sources lose detail quietly. Load-bearing claims and exact numbers get dropped or softened when a transcript or chat log is compiled straight to prose. List the durable atoms first and re-read the source against your article before finishing (
references/high-fidelity-ingest.md). - Extract the signal when asked; don't convert-and-dump. When the user wants "the valuable content" or "the high-signal parts" - especially of a verbose source like a transcript - distilling is the job, not copying the whole thing in with the hellos and banter intact; a rich format (docx, PDF) is converted only as an intermediate step (
references/distilled-ingest.md). - Only delete rich originals that live in `raw/`. After extracting a binary to markdown, delete it only when it was inside
raw/(which stays markdown-only) and the extraction is verified faithful. A PDF in the user's Downloads or a temp dir is theirs: extract a markdown copy intoraw/, leave the original untouched, and do not link to it.
Lifecycle and authority
- Replace knowledge by superseding, not by editing in place or deleting. Write the replacement, mark the old page
status: stalewithsuperseded_byand a callout, and keep it - the history is the point. Full mechanic: Conflicts and supersession, above. - Auto-fix only the deterministic list. Index, links, frontmatter, and See Also are safe to repair; surface contradictions, stale claims, and orphans for the user rather than rewriting prose on your own authority (see Lint).
- Critique and Audit answer different questions. Audit checks whether the cited
raw/sources support an article's claims (external fidelity); Critique checks whether the reasoning itself holds up (internal soundness) and does not fact-check claims against the world. Both report only - neither rewrites prose on its own authority (references/critical-analysis.md,references/audit.md). - Gaps are a frontier, not a wishlist. Record a
wantedpage or openquestiononly when evidence backs it - an article references it, or a query asked it - and close gaps by resolution link rather than letting filled ones linger (references/gaps.md).
Maps and separate wikis
- Concept maps drift silently. A current-article map is load-bearing: when the article changes, the prose gets updated but the map can keep asserting the old relationships. Recheck it on cascade updates, keep its
map-sourcesmarker accurate, and remove it once it no longer adds value (references/concept-map.md). - Keep separate wikis separate. When the user has several wikis side by side, each operates in isolation: read the target wiki's own
CLAUDE.mdandSKILL.mdbefore touching it (they do not auto-load from a parent directory), never link or fold one wiki's content into another, and carry a fact across only by re-ingesting its source into the target with the user's go-ahead. Catalogue the wikis in aWIKI-INDEX.mdat the directory holding them (references/multiple-wikis.md).
---
Conventions
Format, paths, and dates
- Standard markdown throughout. YAML frontmatter on every article and raw file; relative links in bodies.
wiki/supports one level of topic subdirectories only. No deeper nesting.- Dates: today's date for log entries,
collected, andcreated/archived.updatedreflects when an article's knowledge content last changed.publishedcomes from the source (Unknownwhen unavailable). - Inside
wiki/files use file-relative links; in conversation use project-root-relative paths. - A distilled raw (
fidelity: distilled,references/distilled-ingest.md) holds an extract of a verbose external source instead of the verbatim original. It is produced through a separate-sub-agent review gate and audited with the weaker guarantee a derived source implies.
Supersession, gaps, maps, and critique
- Supersession replaces deletion for outdated knowledge: mark stale, link the replacement, keep the page. Git carries the history.
wiki/gaps.mdregisters known unknowns (references/gaps.md):wantedpages and openquestions, grouped by topic, ranked by evidence not a score, and closed by a resolution link rather than deletion. Record only gaps with evidence behind them.- Concept maps are optional and value-gated (
references/concept-map.md): a current-article map is load-bearing and carriesmap-sources; an archive map is a snapshot. Validate withscripts/lint_mermaid.pywhenuvis available. - Critique (
references/critical-analysis.md) examines reasoning quality - argument structure, hidden assumptions, fallacies, bias risk, internal consistency - and is the internal-soundness counterpart to Audit's external-fidelity check. It deliberately does not fact-check claims against sources. Opt-in, read-only, reports a four-section analysis, and never rewrites prose.
Operational behaviour
- Ingest updates
wiki/index.mdandwiki/log.md, andwiki/gaps.mdwhen it touches the knowledge frontier. Crystallise (from Query) updates the index and log. Lint updateswiki/log.md,wiki/index.mdonly when auto-fixing index entries, andwiki/gaps.mdwhen closing or proposing gaps. Audit updateswiki/log.mdonly, and writes an archive page only if the user asks to keep the result. Critique updateswiki/log.mdonly, and writes an archive page or agaps.mdquestion only if the user asks to keep the result. A plain query writes nothing on its own; with the user's go-ahead it may add a missed question towiki/gaps.md. - Ensure sub-agents have clear goals and scope to understand the context of the work they're tasked with. Use forked sub-agents (if available) when sub-agent tasks require the complete conversation history.
Repo infrastructure
- A root
SKILL.md(references/templates/wiki-skill-template.md) lets the wiki load as a query-only Agent Skill; it is created at init, named<subject>-llm-wiki, and routes all writes back through this skill. - A root
CLAUDE.md(references/templates/wiki-claude-md-template.md) is project memory that orients any agent whose working directory is the wiki repo and tells it to activate the llm-wiki skill if available. It loads by location where the root SKILL.md loads by description match; created at init, never overwritten. local/(references/local-content.md) is optional, gitignored personal content in the user's clone only, exempt from the index/log/gaps/cascade/audit machinery (Critique may still run on it when the user points at it). Local files may link intowiki/andraw/; no committed file may link intolocal/. Query scans it and labels hitslocal/ (uncommitted). Init writes a wiki.gitignore(references/templates/wiki-gitignore-template.md) that excludes it.- Multiple wikis (
references/multiple-wikis.md) are independent, side-by-side llm-wikis the user clones wherever they like; they do not nest and do not reference each other. When a session's working directory holds more than one, catalogue them in aWIKI-INDEX.mdthere, read each wiki's ownCLAUDE.md/SKILL.mdbefore querying or maintaining it, and carry a fact across only by re-ingesting its source into the target wiki with the user's go-ahead - never a cross-wiki link. - Recommend the wiki be a git repo so supersession and history have a real audit trail. Do not require it.
# OS
.DS_Store
Thumbs.db
# Editors
*.swp
*.swo
*~
.vscode/
.idea/
# Obsidian
.obsidian
.trash/
# Node (for npx add-skill tooling, if used)
node_modules/
# Misc
*.log
*.tmp
*.zip
*.tar.gz
*.tgz
.cache/
*.pem
*.crt
*.key
*.dmg
*.lock
.env
__pycache__/
*.pyc
*.local.*
*.lock
*.bak
Changelog
High-level record of functional changes to the llm-wiki skill, newest first. One line per change, pointing at the detail. Read it when someone asks what is new or changed - it is not loaded automatically. Maintainers: see CLAUDE.md for when and how to add an entry.
- 2026-06-05: Added support for multiple independent wikis kept side by side. Each is a separate, self-contained llm-wiki cloned wherever the user likes - they do not nest and never link to each other. When a session's working directory holds more than one, the skill catalogues them in a
WIKI-INDEX.md, reads each wiki's ownCLAUDE.md/SKILL.mdbefore querying or maintaining it, and carries a fact across only by re-ingesting its source into the target wiki. Seereferences/multiple-wikis.md. - 2026-06-05: Added Critique, a fifth operation that examines the reasoning in a source or article (argument structure, hidden assumptions, fallacies, bias risk, internal consistency) and reports a four-section analysis. It is the internal-soundness counterpart to Audit's external-fidelity check and deliberately does not fact-check claims against sources; read-only, with optional hooks from Ingest (persuasive sources) and Query (scrutinising an answer). See
references/critical-analysis.md. - 2026-06-05: Ingest now decides a retention mode (verbatim vs distilled) up front, so a request for "the valuable/high-signal content" routes to distilling instead of a verbatim convert-and-dump - including for rich formats like a docx transcript, where conversion is only an intermediate step. Distil now biases toward keeping anything uncertain. See
references/distilled-ingest.md. - 2026-06-04: Init now writes a root
CLAUDE.mdfor the wiki repo (project memory that auto-loads by working directory): it points an agent at the wiki's SKILL.md and tells it to activate the llm-wiki skill if available. Lint offers one to wikis that predate it. Seereferences/templates/wiki-claude-md-template.md. - 2026-06-04: Added
scripts/lint_wiki.py, a read-only stdlib helper for the deterministic structural lint checks (frontmatter, index, links, raw, local-leak), so agents stop improvising scripts piped through the shell. Seereferences/lint.md. - 2026-06-04: Added distilled ingest for verbose external sources (transcripts, meeting notes): extract the valuable content and keep a
fidelity: distilledraw instead of the verbatim source, gated by a critical review from a separate sub-agent, with optionalsource_sha256/source_modifiedfingerprints to detect a changed source or forgotten re-extraction. Seereferences/distilled-ingest.md. - 2026-06-04: Added optional
local/for gitignored personal content (notes, drafts, private sources), kept in the user's clone only. Seereferences/local-content.md; init now also writes a wiki.gitignorefromreferences/templates/wiki-gitignore-template.md.
Working on the llm-wiki skill
This repo is both a distributable Agent Skill. That dual role explains things pure skill-authoring guidance would flag: README.md, LICENSE, CHANGELOG.md, and examples/ are intentional and stay. Don't strip them as "skill clutter".
Update the changelog
When you change what the skill does or how it is used, append one line to CHANGELOG.md (newest first): - YYYY-MM-DD: <what changed>, see references/<doc>.md. Keep it terse and high-level - one functional change per line, pointing at the detail doc. Skip pure copy-edits, refactors, and internal tidy-ups; the changelog is "what's new for a user of the skill", not a git log. Do not link it from SKILL.md - it must stay out of the skill's loaded context, read only when asked.
Keep the three format definitions in sync
The file format is defined in three coupled places. Change a detail in one, update all three in the same pass:
SKILL.md- the spec and workflow (source of truth)references/templates/*.md- the fill-in templates (authoritative for exact format)examples/- a self-consistent sample vault that must conform to the spec
The examples are validated against the spec, not decorative. After any format change, re-check that example frontmatter, links, the supersession pair, and the index/log still match SKILL.md and the templates. The structural linter must stay clean on the sample vault: uv run scripts/lint_wiki.py examples reports no issues.
Concept maps add a fourth coupling: the palette and rules in references/concept-map.md, the worked map in examples/wiki/machine-learning/why-transformers-scale.md, and the checks in references/lint.md must agree, and the validator must stay green on the samples: uv run scripts/lint_mermaid.py --require-edge-labels --max-nodes 12 examples/ references/.
Don't re-add what the design omits
The skill deliberately excludes embeddings and vector search, a knowledge-graph database, numeric confidence scores, decay/forgetting curves, autonomous background writes, and multi-agent sync (see "Design philosophy" in SKILL.md). These omissions are the design, not gaps. It stays self-contained: plain markdown, relative links, git, and stdlib-only helper scripts that are read-only and write no artefacts. scripts/ holds exactly two, both run via uv when available and both intentional (don't strip them as clutter, the way README.md and examples/ are): lint_mermaid.py validates concept-map mermaid, and lint_wiki.py reports the deterministic structural lint checks. They detect only - the agent applies fixes - so neither mutates the wiki. A new script must keep that contract (stdlib, read-only, no artefacts) or it doesn't belong. No databases, servers, embeddings, or third-party packages.
Editing SKILL.md
- Keep it lean (aim under ~4k tokens); move detailed protocol into
references/and point to it, as the bulk-ingest protocol does. - The skill
namemust match the directory name (llm-wiki); the spec validator enforces this. - Validate after changes with the skill-creator-primer
validate_skill.py. Its siblingquick_validate.pywrongly rejects valid Claude Code frontmatter extensions, so trust the spec validator.
Commits and style
- Commit with the GitHub noreply alias (e.g.
<username>@users.noreply.github.com), never a personal email. - Match the repo's prose: Australian English, plain ASCII punctuation (straight quotes, single hyphens), and no marketing language.
MIT License
Copyright (c) 2026 Sam McLeod
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
LLM Wiki
A self-contained Agent Skill for building and maintaining a personal knowledge base in plain markdown. Your coding agent compiles sources into durable, cross-linked pages, answers questions from them with citations, and keeps the wiki healthy as it grows. No servers, no database, no embeddings. It opens as an Obsidian vault and reads cleanly on GitHub.
Based on Karpathy's LLM Wiki idea, with a design that stays small on purpose.
What an LLM wiki is
A knowledge system where the LLM maintains structured wiki pages instead of re-searching raw documents on every question. New sources are compiled into durable markdown pages, cross-references are kept current, and answers cite the pages that already hold the synthesised knowledge.
The split of work, from Karpathy: the LLM writes and maintains the wiki; you choose sources and ask questions.
| Operation | What it does | Output |
|---|---|---|
| Ingest | Filters and stores a source in raw/, then compiles it into the wiki | New or updated pages |
| Query | Reads the index, follows links, answers with citations | Grounded answers; optionally filed back as a page |
| Lint | Checks index, links, frontmatter, and health | Auto-fixes the deterministic issues, reports the rest |
See SKILL.md for the full specification.
Why not just RAG
| RAG | LLM wiki | |
|---|---|---|
| Knowledge lives in | Raw chunks and embeddings | Curated markdown pages |
| Synthesis happens | At query time, every time | Once, at ingest, then kept current |
| Good for | Broad retrieval over large corpora | Compounding knowledge, summaries, durable cross-links |
RAG retrieves and re-derives on every question. A wiki accumulates: the cross-references are already there, contradictions are already flagged, and the synthesis reflects everything you have read.
Architecture
Three layers under one project root, all plain markdown in git. raw/ is the immutable source of truth the agent reads but never edits. wiki/ is the compiled knowledge the agent owns. SKILL.md is the schema layer that governs every operation, and an optional local/ sibling holds private notes kept out of git.
%%{init: {'flowchart': {'curve': 'basis'}, 'themeVariables': {'fontFamily': 'ui-sans-serif, system-ui, sans-serif'}}}%%
flowchart TB
you["You<br/>choose sources, ask questions"]:::actor
agent["Coding agent<br/>compiles, maintains, answers"]:::actor
skill["SKILL.md<br/>schema: structure, format, workflow"]:::schema
subgraph repo["Wiki repo · plain markdown in git"]
direction TB
raw["raw/<br/>immutable sources, read never edited"]:::raw
wiki["wiki/<br/>compiled articles the agent owns"]:::wiki
special["index.md · log.md · gaps.md · README.md<br/>catalogue, history, known unknowns"]:::special
local["local/<br/>personal notes · gitignored · this clone only"]:::local
end
you --> agent
skill -. "governs every operation" .-> agent
agent -->|"compiles from"| raw
raw -->|"compiled into"| wiki
wiki --> special
local -. "may link into (never linked from)" .-> wiki
classDef actor fill:#dbeede,stroke:#4f9d69,stroke-width:2px,color:#1d3a28;
classDef schema fill:#e7e0f5,stroke:#7a5cb0,stroke-width:2px,color:#2e2147;
classDef raw fill:#f3ece0,stroke:#b08642,color:#4a3a1c;
classDef wiki fill:#cfe2ff,stroke:#2f6fb0,stroke-width:2px,color:#0d2a44;
classDef special fill:#e8eef6,stroke:#4a5b6e,color:#16202c;
classDef local fill:#ececec,stroke:#9aa0a6,stroke-dasharray:4 3,color:#5f6368;How it works
Ingest: fetch, then compile
Ingest is always two steps. A source is fetched, filtered for secrets, and landed in raw/ as durable markdown; then it is compiled into wiki/, either merged into an existing article or written as a new one. Compiling ripples outward: related articles are updated, outdated ones superseded, and the catalogue, log, and gap register are kept in step.
%%{init: {'flowchart': {'curve': 'basis'}, 'themeVariables': {'fontFamily': 'ui-sans-serif, system-ui, sans-serif'}}}%%
flowchart LR
src["Source<br/>URL · file · paste"]:::ext
mode{"Keep verbatim<br/>or distil?"}:::decision
fetch["Fetch + filter<br/>strip secrets & PII"]:::step
rawf["raw/topic/<br/>YYYY-MM-DD-slug.md"]:::raw
compile["Compile<br/>merge into article<br/>or create new"]:::step
art["wiki/topic/article.md"]:::wiki
cascade["Cascade<br/>update affected articles,<br/>supersede the outdated"]:::step
book["Update index.md · log.md,<br/>gaps.md if the frontier moved"]:::special
src --> mode --> fetch --> rawf --> compile --> art --> cascade --> book
classDef ext fill:#f4f4f2,stroke:#b9bdc4,stroke-dasharray:2 2,color:#444b54;
classDef decision fill:#fff5d6,stroke:#c8a52a,color:#5a4a12;
classDef step fill:#e8eef6,stroke:#4a5b6e,color:#16202c;
classDef raw fill:#f3ece0,stroke:#b08642,color:#4a3a1c;
classDef wiki fill:#cfe2ff,stroke:#2f6fb0,stroke-width:2px,color:#0d2a44;
classDef special fill:#e8eef6,stroke:#4a5b6e,color:#16202c;What each operation touches
Five operations, with Query as the default. Only Ingest and Lint write to the wiki by design. Query, Audit, and Critique are read-mostly: they answer or report, and touch the wiki only at the log, or as an opt-in when you ask to keep a result.
%%{init: {'flowchart': {'curve': 'basis'}, 'themeVariables': {'fontFamily': 'ui-sans-serif, system-ui, sans-serif'}}}%%
flowchart TB
ingest["Ingest<br/>fetch, compile, cascade"]:::write
lint["Lint<br/>health checks, auto-fix"]:::write
query["Query<br/>answer with citations"]:::read
audit["Audit<br/>claims vs raw/ sources"]:::read
critique["Critique<br/>reasoning soundness"]:::read
book["index.md · log.md · gaps.md"]:::special
ingest ==> book
lint ==> book
query -. "crystallise (opt-in)" .-> book
audit -. "log only" .-> book
critique -. "log only" .-> book
classDef write fill:#cfe2ff,stroke:#2f6fb0,stroke-width:2px,color:#0d2a44;
classDef read fill:#e8eef6,stroke:#4a5b6e,color:#16202c;
classDef special fill:#f3ece0,stroke:#b08642,color:#4a3a1c;The article lifecycle
Knowledge is replaced by supersession, never deletion. A current article is updated in place as related sources arrive; when a newer source clearly replaces it, it is marked stale and linked to its replacement, and kept so the history still explains why the current state exists. Crystallised query answers are filed as point-in-time archives that are never cascade-updated.
%%{init: {'themeVariables': {'fontFamily': 'ui-sans-serif, system-ui, sans-serif'}}}%%
stateDiagram-v2
direction LR
[*] --> Current: ingest / merge a source
Current --> Current: cascade update, bump updated
Current --> Stale: superseded_by a newer page
Stale --> [*]: kept for history, never deleted
[*] --> Archive: crystallise a query answer
Archive --> [*]: point-in-time, never cascadedDesign principles
These are the opinions that keep the wiki useful as it grows, and keep it free of infrastructure. They draw on the community "v2" discussion and its comments, taking the parts that hold up and dropping the rest.
- Self-contained. Plain markdown, relative links, YAML frontmatter. It uses tools you already have (grep, git) and nothing you have to stand up.
- Supersession, not decay. Outdated knowledge is marked stale and linked to its replacement, never deleted on a timer. An old bug or a superseded decision still explains why the current state exists.
- Evidence, not confidence scores. A claim carries the support behind it (which sources confirm, which contradict, when last confirmed), not an unverifiable number like
0.85. - Filter at ingest. Secrets and noise are stripped when a source arrives, so the wiki stays clean without a cleanup pass later.
- Git is the audit trail. History and rollback come from version control, not bespoke versioning fields.
- Human in the loop. It acts when you ask. It does not write to the wiki on background automation, because an unreviewed LLM corrupts a knowledge base quietly.
What it deliberately leaves out
Embedding or vector search, knowledge-graph databases, numeric confidence scores, automatic forgetting curves, autonomous background writes, and multi-agent sync. Each one either needs infrastructure the personal scale does not justify, or adds precision the model cannot actually back up. The index plus grep handles retrieval into the hundreds of pages; past that, you have outgrown this skill.
Install
This is a standard Agent Skills skill: a folder with a SKILL.md and a references/ directory. Copy it into your tool's skills directory.
Claude Code, available everywhere:
cp -r llm-wiki ~/.claude/skills/llm-wikiClaude Code, single project:
cp -r llm-wiki .claude/skills/llm-wikiOther tools: copy SKILL.md and references/ into the tool's skill directory (for example .agents/skills/llm-wiki/ for Codex). The published home is the sammcj/agentic-coding repo.
Quick start
Ingest a source:
"Ingest this article: https://example.com/attention-is-all-you-need"
It strips any secrets, stores the source in raw/, then compiles or updates the right pages in wiki/.
Ask the wiki:
"What do I know about attention mechanisms?"
It reads the index, follows links and backlinks, and answers with citations. Say "save that to the wiki" and the answer is filed as an archive page so the exploration compounds like a source.
Keep it healthy:
"Lint my wiki"
Auto-fixes index drift, broken links, and frontmatter gaps; reports contradictions, orphans, superseded claims, and knowledge gaps (concepts the wiki references but has not yet written).
Layout
your-project/
├── SKILL.md ← Optional: load the wiki as a query-only Agent Skill
├── raw/ ← Immutable sources (frontmatter + original text), never edited
│ └── topic/
│ └── 2026-04-03-source-article.md
├── wiki/ ← Compiled pages the LLM maintains (frontmatter + markdown)
│ ├── index.md ← Catalogue and query entry point
│ ├── log.md ← Append-only operation log
│ ├── gaps.md ← Register of known unknowns: wanted pages and open questions
│ └── topic/
│ ├── concept.md ← status: current
│ └── old-concept.md ← status: stale, superseded_by a newer page
└── local/ ← Optional: personal notes, gitignored, this clone onlylocal/ is excluded from git so you can keep meeting prep, drafts, and private notes alongside the wiki without committing them. It may link into wiki/, but nothing committed links back into it, so the shared wiki stays self-contained for everyone else. See the llm-wiki skill's references/local-content.md.
A worked example lives in examples/: two raw sources, the articles they compile to, a supersession pair, a crystallised query, a gap register, and the matching index and log.
Using it with Obsidian
The wiki is a folder of markdown, so it opens directly as an Obsidian vault. Frontmatter shows up as Properties, body links populate the graph view and backlinks panel, and the Dataview plugin can query frontmatter if you want it. None of that is required: the hand-maintained index.md is canonical and the skill works with no plugins.
Credits
I've used something similar for years with agents / agentic coding tools, but it was popularised and in some ways formalised by Karpathy. The design also learned from the v2 gist and its comment thread, keeping the self-contained ideas (supersession, evidence chains, ingest-time filtering, crystallised answers) and leaving out the infrastructure-heavy ones. It began as a community Agent Skills implementation and has since been redesigned.
License
MIT
Audit: verifying articles against their sources
How to check that a wiki article's claims are actually supported by the raw/ sources it cites. This operationalises the "evidence, not confidence" principle: rather than trust a provenance link, read the source and confirm it says what the article claims. Audit is read-only and reports its findings; it never rewrites article prose (the same authority boundary as Lint's heuristic checks).
When to use this
- After a large or noisy ingest, to confirm load-bearing claims survived compilation intact.
- Before leaning on an article for an important decision.
- Periodically on a topic, the way you would lint, but deeper.
- When Lint flags an archive whose cited sources have changed, or a possible contradiction, and you want to settle it against the raw text.
It is not automatic and not part of every ingest. Auditing reads every cited source in full, so reserve it for the articles that matter.
Claim extraction
1. Read the target article. List the claims that carry provenance: the headline assertions in Overview and the body sections, every inline quote, and anything a Sources or Raw line is meant to back. Skip generic framing and common knowledge. A labelled edge in a concept map is a claim too - the relationship it asserts between two nodes; list every edge and treat it like any other claim. 2. Map each claim to the raw/ file(s) that should support it, using the Raw line and any inline raw links. A load-bearing claim with no cited source is itself a finding: the article asserts something its provenance does not cover. 3. Group the claims by the raw file that backs them. Each group becomes one sub-agent task.
Parallel verification
Dispatch one sub-agent per cited raw source, in parallel. This mirrors the bulk-ingest discipline (references/bulk-ingest.md): each sub-agent reads exactly one source and judges only the claims assigned to it, so reads never overlap and the orchestrator aggregates a consistent set of verdicts.
Give each sub-agent:
- The path to the one
raw/file it owns. - The list of claims, verbatim from the article, that cite that file (with the locator if the article gives one).
- The verdict schema below, with an instruction to quote the supporting passage and to default to
unsupportedwhen the source does not clearly back the claim.
Per-claim verdict:
| Verdict | Meaning |
|---|---|
supported | The source states or directly entails the claim. Return the passage. |
partial | The source backs part of the claim, or a weaker version of it. Return the passage and say what is missing. |
unsupported | The source does not back the claim, or contradicts it. Say which. |
source-missing | The cited raw file is absent or unreadable. |
Sub-agents read only. They never edit wiki/, raw/, index.md, or log.md.
Distilled sources
A raw file marked fidelity: distilled (references/distilled-ingest.md) is itself an extract of a source that no longer exists, not the verbatim original. Audit it for what it can still show - that the article claims no more than the extract supports - but say plainly in the report that the guarantee is weaker: the extract cannot be checked back against the original, which was verified once at ingest by the review gate. A supported verdict against a distilled source means "the article matches the extract", not "the article matches the source". Flag each distilled source in the report so the user reads its verdicts with that in mind.
Aggregation and report
The orchestrator collects the verdicts and reports in conversation, grouped by article, worst verdicts first:
- For every
partial,unsupported, andsource-missing, show the claim and the passage the source actually contains (or note its absence), so the user can act. - Give the counts: claims checked, supported, partial, unsupported, source-missing.
Do not rewrite the article. A failed claim is a finding for the user, who directs the follow-up:
- Soften or correct an overstated claim (an Ingest edit, bumping
updated). - Supersede the article if a source has moved on (the supersession flow in SKILL.md).
- Accept a
partialand add the missing qualifier inline.
Append the one-line audit entry to wiki/log.md (format in SKILL.md). If the user wants the audit kept, crystallise it as a type: archive page citing the audited article, the same way a query answer is crystallised.
Why categorical verdicts, not scores
A verdict points at a passage the reader can check; a number like 0.72 cannot be checked and invents precision the evidence does not have. This is the same reason the rest of the skill refuses confidence scores. The audit's job is to surface the passage, not to grade it.
Bulk and parallel ingest
How to bring many sources into the wiki at once without losing the synthesis, dedup, and cross-linking that make a wiki worth more than a folder of notes.
When to use this
Default to plain single-source ingest. Reach for this protocol when you have many sources to bring in together (for example a folder of meeting transcripts) or when one agent would run out of context partway through. A handful of sources is fine to ingest serially; the fan-out overhead is not worth it for small batches.
The shape: map then reduce
Sub-agents extract in parallel (the expensive, context-heavy part). One orchestrator compiles serially (the part that must see the whole wiki). The compile stays serial on purpose: dedup, conflict detection, evidence merging, and cross-linking all need a single consistent view, and that is exactly what parallel writers destroy.
Step 0: prepare (orchestrator)
- List the source files for the batch.
- Decide the topic taxonomy: read the existing
raw/andwiki/topic directories, pick or extend the set, and write it down. This fixed list goes to every extractor so they cannot invent divergent names for one thing. - Choose a batch size per sub-agent: large enough to be worth a context, small enough to finish reliably.
Map: extractor sub-agents (parallel)
Give each sub-agent its file list, the fixed topic list, and this contract:
- You are one of several extractors. You own only
raw/<your-topic>/. Do not write towiki/,index.md, orlog.md. - For each source: apply the secret and PII filter, save it under
raw/following the naming rules in SKILL.md, then return a proposal. Do not compile. - Rich-format sources (PDF, slides, documents, images) convert to markdown per
references/rich-format-ingest.mdbefore extraction:raw/stays markdown-only. - For long or noisy sources (transcripts, chat logs), extract atoms faithfully: the
claimslist withevidenceis exactly the atom extraction and anchoring fromreferences/high-fidelity-ingest.md. Preserve exact terms, numbers, and hedging; setnet_newhonestly. - Your final message is the data the orchestrator merges, so return the proposals and nothing else.
One ingest proposal per source:
source_raw: raw/<topic>/<file>.md # the file you wrote
topic: <one of the assigned topics>
target:
mode: merge | new
article: <existing article to merge into, or proposed new title + slug>
claims:
- claim: <one durable claim, decision, or fact>
evidence: <short quote or section reference from the source>
entities: [people, projects, decisions]
conflicts: <anything that appears to contradict an assigned topic or known article, else empty>
cross_links: [<related article titles>]
net_new: yes | restates-known # transcript triage: does this add anything new?Reduce: orchestrator (serial)
1. Collect every proposal. 2. Sort by the source's meeting or published date. Applying oldest to newest makes "newer supersedes older" resolve deterministically despite parallel extraction. 3. Group by target concept. Several proposals about one concept become a single article whose evidence chain lists every supporting source. This "many sources, one well-supported claim" consolidation is only possible with all proposals in view, and it is the main reason the compile is serial. 4. Triage net_new. A restates-known source keeps its raw file but folds in as added evidence to an existing claim rather than spawning a new article. Avoid compiling noise. 5. Apply writes to wiki/ one at a time, resolving conflicts (annotate inline with an evidence chain) and supersession (mark the old page stale with superseded_by and a callout) against the now-stable state. 6. Update index.md and log.md once, as the sole writer. Use a single batch log entry:
## [YYYY-MM-DD] ingest | batch: <label> (<N> sources)
- Created: <article title>
- Updated: <article title>
- Superseded: <old title> -> <new title>7. Cascade once across the touched topics, now that every article in the batch exists. 8. Checkpoint, then commit (see below).
The review checkpoint (the quality gate)
Before committing, present a digest and wait for the user's go-ahead:
- sources ingested, and any skipped as
restates-known - articles created, merged (with how many sources back each), and superseded
- conflicts surfaced, for the user to judge
- anything the orchestrator was unsure where to file
Only after approval, git commit the batch. This pause is deliberate. Bulk ingest is where a wiki quietly fills with thin, duplicated pages, and a human glance at the batch boundary is the cheapest place to catch it. Quality over volume.
Advanced: parallel compile
Only when reduce throughput is the genuine bottleneck. Partition by wiki/ topic so each compile sub-agent owns a disjoint wiki/<topic>/. Keep index.md and log.md single-writer: each owner returns its index rows and log lines as data, and the orchestrator assembles them. Disjoint ownership is the rule; any overlap means agents erase each other's work.
Resumability
A batch can stop partway. Raw files are written first and are independent, so a re-run can skip any source already compiled (check the log for what landed). Commit per batch so a bad batch reverts cleanly with one git revert.
Gotchas
- One concept, one article. The most common bulk failure is two agents creating near-duplicate pages. The orchestrator's group-by-concept step prevents it, which is why extractors never create wiki pages.
- Date order matters. Without sorting, concurrent supersessions land in arbitrary order and the wrong claim can win.
- `index.md` and `log.md` have exactly one writer, ever. Almost every corruption traces back to this rule being broken.
- Watch the index size. Past a few hundred pages a single
index.mdgets heavy to read in one pass; consider per-topic index sections before a large batch makes it worse.
Domain recipe: documenting a codebase
An optional set of conventions for when the wiki's subject is a codebase rather than external reading. The core skill is unchanged - raw/ and wiki/, ingest, supersession, lint, audit, all as in SKILL.md. This adds topic and naming conventions that fit source code, and a rule for where the wiki ends and the repo's own docs begin.
Use it when the user points the wiki at a repository. Ignore it otherwise; the skill is domain-agnostic by default.
What goes where: wiki vs the repo's own docs
The repo's README and inline docs already cover how to set up and run the code. The wiki covers what those leave out: why the code is shaped this way, how the pieces fit, and the decisions behind them. Do not copy setup steps or API signatures the code already documents; link to them. An article earns its place by explaining context that is not reconstructable from a glance at the code.
Topics and naming
Use these topic directories under wiki/, and prefix article slugs so the kind is visible in a link:
| Topic | Slug prefix | Holds |
|---|---|---|
modules | mod- | What a module or package does, its responsibilities, and how it relates to others. |
apis | api- | Public interfaces, contracts, and how callers are meant to use them. |
decisions | dec- | Why a choice was made: the options, the trade-off, the constraint. The ADR role. |
flows | flow- | How a request, job, or data path moves through the system end to end. |
These are a starting set, not a straitjacket; add a topic when the code genuinely needs one. The one-level-of-subdirectories rule still holds.
Sources for a codebase wiki
raw/ still holds the immutable source material. For a codebase that means the durable artefacts you compiled from, not the live code:
- README, ADRs, design docs, RFCs, CONTRIBUTING.
- CI config and manifests (what the build and release actually do).
- Captured output that explains behaviour: a profiling run, a schema dump, an incident write-up.
Compile in dependency order so early articles ground later ones: README and design docs first, then ADRs, then CI and manifests, then the entry points and core modules.
Reconstructed decisions
Often the only record of why something was done is the code and the git history. When you infer a decision rather than read it from a doc, write it as a decisions article and say so: mark it as reconstructed, cite the commits or files it was inferred from (in the Raw line or inline), and keep the certainty honest. "Inferred from commit abc123; no written rationale found" is the claim, not "the team decided". This is the epistemic-status discipline of references/high-fidelity-ingest.md applied to code archaeology.
Drift
Code moves, and an article describing a module that has since been rewritten is stale knowledge. The supersession flow handles it: when a later source (a new ADR, a refactor's commit) replaces the old account, mark the old article status: stale, point superseded_by at the replacement, and keep it - it still explains why the previous structure existed. Audit (references/audit.md) is the tool for checking whether an article still matches the code and docs it cites.
Concept maps: agent-authored mermaid diagrams
A concept map is a small mermaid diagram that shows how a handful of ideas relate when prose conveys those relationships poorly. It is compiled content, authored the same way as an article and held to the same evidence standard: every edge is a claim you could defend in an audit. It is not decoration, and it is not a redraw of the link graph (Obsidian and grep already show what links to what). Its value is the thing a link graph cannot carry: the kind of relationship, named on the edge.
Default to prose. A map has to earn its place.
When to draw, and when not
Draw a map only when the relationships are non-linear and a reader would struggle to hold them from text:
- branching or convergence (several things feed into or out of one),
- a cycle or feedback loop,
- a multi-step supersession or causal chain across several articles.
Do not draw a map when:
- there are two nodes, or a single linear
A -> B -> Ca sentence states better, - it only restates the See Also list or the topic folder (the link graph already shows that),
- the edges would be unlabelled (an unlabelled edge means "links to", which adds nothing),
- it is purely linear - no node gains a second inbound or outbound edge - so it is a list, not a graph.
The test: if a sentence conveys it, or it only mirrors existing links, do not draw it. A map with no value is worse than no map - it costs maintenance and misleads when it drifts.
What makes a good map
- One theme, bounded. Aim for 12 nodes or fewer. If it needs more, the theme is too broad - narrow it or split it.
- Every edge labelled with the relationship, and the direction meaningful. Use a small vocabulary:
replaces/superseded by,depends on/requires,generalises/special case of,contrasts with/competes with,causes/enables,part of,derived from. - States encoded by the palette below: stale nodes dashed and grey, archive nodes amber, the focus highlighted. Colour is never the only signal - the dash patterns carry the same meaning so the map reads on a monochrome screen and for colourblind readers.
- Supportable. Every edge traces to the articles (and their
raw/sources) the map is built from. No edge you could not back. - Renders everywhere. Plain fenced mermaid so it shows on GitHub (light and dark) and in Obsidian. No external images, no HTML.
Colour palette
Copy these classDef lines into the diagram. Light fills with dark text read on both GitHub themes; the dash patterns give a redundant, non-colour signal.
classDef focus fill:#cfe2ff,stroke:#2f6fb0,stroke-width:2px,color:#0d2a44;
classDef current fill:#e8eef6,stroke:#4a5b6e,color:#16202c;
classDef stale fill:#ececec,stroke:#9aa0a6,stroke-dasharray:4 3,color:#5f6368;
classDef archive fill:#fdebcf,stroke:#c8862a,color:#5a3e12;
classDef external fill:#f4f4f2,stroke:#b9bdc4,stroke-dasharray:2 2,color:#444b54;focus- the central concept, or the article that owns the map.current- a normal concept orstatus: currentarticle.stale- astatus: stalearticle (matches the supersession callout's intent).archive- atype: archivepage or a crystallised conclusion.external- context from another topic, present to orient but not the subject.
Format
- Use
flowchart LR(orTDwhen the chain is naturally vertical). - Quote every node label:
id["Label"]. Parentheses, colons, and#break unquoted labels. - Keep labels short - the article title, or a few words for a concept that has no article.
- Apply a class with
:::classon the node, or a trailingclass id className;.
Where it lives, and how it stays fresh
A map's home decides its maintenance contract:
- Inside a `current` article (a
## Mapsection or inline) the map is load-bearing. It carries a provenance marker naming the articles whose changes should prompt a recheck, placed directly above the fenced block:
<!-- map-sources: transformer-architectures.md, attention-efficiency.md -->Paths are file-relative, like body links. The map rides cascade updates: when a listed source changes, recheck the map, redraw if the relationships moved, and bump the article's updated. Lint compares each source's updated to the host article's and flags the map when a source is newer (see below).
- As a `type: archive` page (a crystallised query answer with a map) the map is a dated snapshot. Archives are never cascade-updated, so an archive map needs no
map-sourcesmarker and is never flagged stale. It says "this is how it looked on this date", which is what archives are for.
How lint and audit keep maps honest
This is where freshness, validity, and value are enforced, so a map cannot quietly rot or sprawl:
- Freshness (lint, deterministic). For a map in a current article, if any
map-sourcesarticle'supdatedis newer than the host article's, lint annotates the block<!-- stale-map: <source> updated YYYY-MM-DD after host -->. It annotates, never redraws - the redraw is judgement, left to the user. - Validity (lint, deterministic). Run the bundled validator when
uvis available -uv run scripts/lint_mermaid.py --require-edge-labels --max-nodes 12 <file>- which is dependency-free and checks the block will render: balanced brackets and quotes, a diagram type, defined style classes, labelled edges, and a bounded node count. Ifuvis absent, skip scripted validation and check the block by eye; never block on a missing tool. Separately, everymap-sourcespath must resolve to an existing article, the same as an internal link. - Value (lint, heuristic). Lint flags a map that does not earn its place - linear or two-node, a restatement of See Also, unlabelled edges, no branching - for the user to prune.
- Support (audit). Audit treats each labelled edge as a claim and verdicts it against the cited
raw/sources, the same as a prose claim. An edge with no supporting source is a finding.
Briefing a sub-agent to draw one
A sub-agent has none of the main session's wiki context, so a map it returns is only as good as its brief. This follows the bulk-ingest discipline: the sub-agent proposes, the orchestrator is the sole writer that embeds the result.
Give the sub-agent:
- This whole recipe - the when/when-not test, the palette, the edge vocabulary, the format. It is the spec.
- The source material - the paths to the articles (and their
raw/sources) the map is built from, with instruction to read them in full, plus the scope: which concepts are in, which are out. - The home - current article (load-bearing, needs a
map-sourcesmarker) or archive (snapshot). - Authority to decline. Tell it to return
NO-MAPwith a one-line reason when a diagram would not earn its place. The value gate binds the sub-agent too.
The sub-agent returns the fenced mermaid block, the map-sources marker (for a current-article map), and one line on the value the map adds - or NO-MAP. If uv is available it runs scripts/lint_mermaid.py --require-edge-labels --max-nodes 12 over its draft first and clears any error before returning. It never writes to wiki/, index.md, or log.md. The orchestrator checks the proposal against this recipe, then embeds it and bumps updated.
Worked example
A synthesis map for an archive page answering "why are long context windows practical?" Two paths converge on the outcome, and the superseded view is shown dashed and grey:
flowchart LR
arch["Transformer Architectures"]:::focus
eff["Attention Efficiency"]:::current
cost["Attention Memory Cost"]:::stale
out(["Long context is practical"]):::archive
arch -->|"enables long-range modelling"| out
arch -->|"naive cost is quadratic"| cost
cost -->|"superseded by"| eff
eff -->|"removes the memory penalty"| out
classDef focus fill:#cfe2ff,stroke:#2f6fb0,stroke-width:2px,color:#0d2a44;
classDef current fill:#e8eef6,stroke:#4a5b6e,color:#16202c;
classDef stale fill:#ececec,stroke:#9aa0a6,stroke-dasharray:4 3,color:#5f6368;
classDef archive fill:#fdebcf,stroke:#c8862a,color:#5a3e12;It earns its place: two paths (modelling benefit, memory penalty removed) converge on one outcome, and it shows the supersession that the prose only states. A linear chain of the same articles would not have.
Critique: examining the reasoning in a source or article
How to subject a piece of content to critical-thinking analysis - argument structure, hidden assumptions, logical issues, bias risk, internal consistency - and report what holds up and what does not. This is the reasoning-quality counterpart to Audit. Where Audit asks "do the cited raw/ sources support this article's claims?" (external fidelity), Critique asks "does the reasoning itself hold up?" (internal soundness), independent of whether any source backs it. Critique deliberately does not fact-check empirical claims against the world; that is Audit's job, or the user's. It is read-only and reports its findings; it never rewrites prose (the same authority boundary as Audit and Lint's heuristic checks).
When to use this
- The user asks to critique, scrutinise, or stress-test the reasoning in a source or an article ("is this argument sound?", "what is this assuming?", "where is the bias here?").
- During Ingest, when a source is persuasive or argumentative rather than factual - an opinion piece, a vendor's case for its product, a strategy memo - and you want the reasoning risks on record before compiling it as if it were settled knowledge. Report them; let the user decide what to do. A common outcome is to attribute the claim rather than assert it, or to log an open question in
gaps.md. - During Query, when the user asks you to scrutinise an answer or the reasoning behind a wiki position rather than just retrieve it.
- Before acting on an article's recommendation in a real decision.
It is opt-in and never automatic. It operates on whatever the user points at: a raw/ source, a wiki/ article, or content pasted into the conversation. It does not require raw/ to exist.
The analysis
Keep the signal-to-noise ratio high: preserve the load-bearing reasoning and the specific flaws that matter, and do not pad the report. Work through the content in this order.
1. Understand the argument first. State it as the author would accept. If you cannot, you are not ready to critique - read again. 2. Identify the core claim(s). What is actually being asserted? Separate the conclusion from the points that support it. 3. Examine the evidence offered. Is it sufficient, relevant, and from credible sources? Judge the support the argument supplies, not whether the claim is true in the world. 4. Spot logical issues. Fallacies, unsupported leaps, circular reasoning, false dichotomies, appeals to authority or emotion, hasty generalisations. Empirical claims need evidence; normative claims need justified principles; definitional claims need consistency. 5. Surface hidden assumptions. What must be true for the argument to hold that the author never states? 6. Consider what is missing. Alternative explanations, contradictory evidence, unstated limitations. 7. Assess internal consistency. Does the argument contradict itself? 8. Weigh the burden of proof. Who needs to prove what? Is the evidence proportional to how significant or surprising the claim is? 9. Check for competing priorities. Were priorities asserted that are in unacknowledged conflict with each other?
Output structure
Report in conversation using these sections.
## Summary - one sentence stating the core claim and your overall assessment of its strength.
## Key Issues - bullet the most significant problems, each with a brief note on why it matters. Where an argument is weak, say briefly how it could be strengthened; this separates fixable flaws from fundamental ones. Omit the section entirely if there are no real problems.
## Questions to Probe - two to five questions that would clarify ambiguity, test a key assumption, or reveal whether the argument survives scrutiny. Frame them as questions a decision-maker should ask before acting.
## Bottom Line - one or two sentences: overall verdict and the actionable takeaway.
Guidelines
- Assume good faith. At worst people are misinformed or mistaken, not dishonest. Be charitable but rigorous.
- Apply the "so what" test. Even a real flaw only matters if it affects the conclusion or the decision at hand. Prioritise those; do not manufacture disagreement or nitpick.
- Critique the reasoning, not the person.
- Do not fact-check empirical claims unless they are obviously implausible or internally contradictory - that boundary keeps Critique distinct from Audit.
- Distinguish "flawed" from "wrong". Weak reasoning does not make a conclusion false, and a sound-looking argument can still reach a bad conclusion.
- Acknowledge the limits of your own analysis. Flag where your critique rests on an assumption or where you lack the domain context to judge.
- If the argument is sound, say so plainly. Do not invent criticism to fill the template.
- Be direct and concise. State problems without hedging.
Many targets at once
To critique every article in a topic, or several sources together, dispatch one sub-agent per target in parallel, the way Audit fans out per source (references/audit.md). Give each sub-agent one target, this protocol, and the output structure; have it return the four sections. Sub-agents read only - they never edit the wiki. The orchestrator collects the reports and presents them grouped by target, weakest reasoning first.
What Critique writes
Nothing, by default - like Audit, it is a report. With the user's go-ahead it may:
- Crystallise the analysis as a
type: archivepage citing the critiqued article or source, the same way a query answer is crystallised (see Query in SKILL.md). Useful when the critique is itself a durable conclusion worth keeping. - Open a gap. A flagged unstated assumption or an unanswered question the critique surfaced can become a
questionentry inwiki/gaps.md, if evidence backs recording it (references/gaps.md). - Inform an Ingest edit. If the critique was run on a source mid-ingest, its findings may change how the article is written - attributing a contested claim to its source rather than asserting it, or noting the conflict inline with an evidence chain. The user directs that; Critique itself only reports.
Always append the one-line critique entry to wiki/log.md (format in SKILL.md).
Why no score
The verdict is the four-section report, not a number. A "reasoning quality: 0.7" invents precision the analysis cannot back, the same reason the rest of the skill refuses confidence scores. Point at the specific issue a reader can weigh, not at a float.
Distilling an external source into the wiki
How to extract the valuable content from a verbose external source - a meeting transcript, call notes, a long document or thread that lives outside the wiki - and keep a high-signal extract in raw/ instead of the whole thing. The user wants the substance summarised, not the source retained in full.
When to use this
Use it when all three hold: the source lives outside the wiki (a file the user names, a paste, a link), it is verbose enough that keeping it verbatim is not worth it, and the user wants the valuable content extracted rather than the source preserved. Typical phrasing is "extract the useful content from this transcript and add it to the wiki".
- If the user wants the full source kept faithfully, use
references/high-fidelity-ingest.mdinstead: same atom discipline, but the verbatim source stays inraw/. - If the source is a rich format (PDF, slides, docx), convert it to markdown first per
references/rich-format-ingest.md, then distil that markdown.
What changes about raw/
Normally a raw/ file is the verbatim source - the immutable ground truth Audit checks the wiki against. A distilled extract is not that. It is already a derived artefact, an LLM's reading of a source that is being discarded. Mark it so, and be honest about the weaker guarantee:
- Frontmatter carries
fidelity: distilled. A verbatim raw omits the field, or setsfidelity: verbatim. original:records what happened to the source:external(it still exists, untouched, outside the wiki) ordiscarded(not retained anywhere - it had been placed inraw/and was deleted after the review gate, or it was an ephemeral paste).
The trade is real. Once the source is gone, Audit can only check that an article claims no more than the extract supports; it can no longer confirm the extract itself reflects the original. The verification that matters therefore happens once, here, at ingest, against the source while it is still present. That is what the review gate below is for.
Detecting a changed source
A distilled extract keeps no copy of the source, so there is nothing to diff against later. To catch a source that has changed since you last extracted from it - and to spot a re-extraction the user has forgotten they already did - record a fingerprint when the source is a persistent, addressable thing (a file, a document, a URL), and check for one before you start.
- Capture, where the environment can compute one. Record
source_sha256(a hash of the source bytes at extraction, e.g.shasum -a 256 <file>) and, when the medium exposes it,source_modified(the source's own last-modified or last-edited date). The hash is the definitive signal; the date is a softer fallback for a source you cannot hash cleanly. Omit both for an ephemeral paste or anything that will not persist - there is nothing to re-check. - Check before re-extracting. First look for an existing raw whose
sourcenames this source. If one exists and carries asource_sha256, recompute the current source's hash: - unchanged -> it has already been extracted; tell the user and stop rather than producing a duplicate.
- changed -> the source has moved on since the last extract; proceed, and treat the result as an update or supersession of the prior extract (the supersession flow in SKILL.md), noting what is new.
- no fingerprint on the old extract (it predates this) -> you cannot be sure; say so and let the user decide whether to re-extract.
Distil by removing, not by summarising
The failure mode is context collapse: a summary compresses many specific statements into one general sentence and the specifics evaporate. Avoid it by treating distillation as subtraction, not paraphrase. Cut filler and repetition; keep every distinct durable atom in the source's own words. The extract is shorter because the noise is gone, not because the meaning was generalised.
Safe to drop: greetings, scheduling and logistics, tech troubleshooting ("can you hear me"), off-topic personal chat, filler words and false starts, and any point already captured being restated.
Looks like filler but is signal - keep it: hedging and uncertainty ("probably", "we think", "not sure"), dissent and objections that did not win, who said or committed to what, the rationale for a decision and the alternatives rejected, exact numbers, dates, names and versions, conditionals ("if X then Y"), parked items, open questions, and action items with their owners. These are exactly what a naive summary discards, and they are usually why the source was worth reading.
Distil "we'll probably move to Postgres in Q3, though Sam flagged the auth-DB migration cost" to a line that keeps the hedge, the owner of the objection, and the quarter - not to "the team decided to adopt Postgres".
The errors are not symmetric. Leaked filler is cheap - the review gate catches it and it costs a few wasted lines. A dropped specific is expensive - once the source is gone there is nothing to recover it from, and the review gate cannot restore what it never saw. So when you are unsure whether a passage is filler or signal, keep it. Be ruthless only with what is unmistakably noise (the "safe to drop" list above is the test); everything else survives to the review.
The steps
1. Convert if needed. Rich format to markdown first (references/rich-format-ingest.md); the converted markdown is working material to distil from, not the raw file you keep. Defer that protocol's "delete the original binary" step until the review gate passes - the reviewer still needs the source. 2. Extract atoms. Pull the durable items into a flat list - decisions, claims, numbers, entities, conditionals, open questions, action items - noting where each sits in the source. This is the references/high-fidelity-ingest.md atom step; the list is the checklist that catches what writing-from-memory drops. 3. Render source-shaped. Write the extract the way the source ran (agenda items, chronology, threads), not by wiki concept: one source, one extract. Keep terms, figures, and epistemic status. Call out decisions, action items, and open questions explicitly; an open question the wiki cannot answer also belongs in wiki/gaps.md (references/gaps.md). 4. Anchor the heavy claims now. For the claims the wiki will lean on, lift the key sentence as a verbatim quote with its locator (timestamp, section, page) into the extract while the source is still in front of you. After the source is gone the extract is the only anchor, so these quotes must be exact. 5. Hand off to a reviewer (next section) and fix what it finds. 6. Save and dispose. Write the extract to raw/<topic>/ with fidelity: distilled, following the naming rules in SKILL.md. For a source that will persist, record its source_sha256 (and source_modified if available), computed while the source is still present (see "Detecting a changed source"). Leave an external source untouched (original: external). Only when the source had already been placed in raw/ do you delete it, along with any binary you converted from it, and only after the reviewer passes (original: discarded). This is the same verified-then-discard gate references/rich-format-ingest.md uses for binaries. 7. Compile to `wiki/` as normal, citing the distilled extract on the article's Raw line.
The review gate (separate sub-agent)
When you judge the extract done, do not trust your own read of it - hand off to a fresh named sub-agent for a critical review. A self-review, or a fork that inherits this conversation, carries the extractor's blind spots with it; an independent reader holding the source does not. This review is mandatory, and it is the gate that licenses discarding the source, so it must run while the source is still available.
Give the reviewer:
- the full source text (or its path) and the distilled extract;
- the keep and drop lists above, so it judges against the same bar;
- a clear goal: find anything durable that was dropped, softened, overstated, mis-attributed, or generalised from a specific; confirm every inline quote is verbatim and its locator correct; flag any filler that leaked in.
Ask it to return findings, not a rewrite. It reads only; it never edits the wiki or the extract.
verdict: pass | revise
findings:
- type: dropped | softened | overstated | misattributed | quote-drift | filler-leak
severity: high | low
detail: <what was wrong, and where in the source - quote the passage>Apply the high-severity findings, re-run the reviewer if the changes were substantial, and treat the extraction as done only on pass. Then, and only then, dispose of the source.
In bulk ingest
When distilling many sources at once, slot the review between extract and compile: each source runs extract, then critical review, then proposal, with the reviewer a different sub-agent from the extractor, and the orchestrator compiles serially as in references/bulk-ingest.md. The reviewer's pass is per source; the orchestrator still owns the cross-source dedup, supersession, and cascade.
Tips for extracting and distilling content
- You may need to use tools outside the Sandbox if the source file is on the user's local machine.
Gaps: tracking what the wiki does not yet cover
wiki/gaps.md is the register of known unknowns. If index.md is "what we know" and log.md is "what we did", gaps.md is "what we don't know yet". It is a maintained markdown file at the wiki/ root, the same level as the index and the log, and it follows the same rules: plain markdown, relative links, a greppable prefix, and git as the audit trail.
A gap is a first-class but lightweight citizen. It uses the same lifecycle grammar as the rest of the wiki: filtered at capture, ranked by evidence rather than a score, closed by a resolution link rather than deleted, and found by grep plus the lint heuristics that already exist. No new field types, no database, no background process.
What is and is not a gap
Two kinds carry the weight:
- `wanted` - a concept that articles reference or mention but that has no page of its own. The genuine "dangling node": an edge points at something that was never written.
- `question` - a known unknown. A source raised it without answering, or a user asked it and the wiki had no answer.
Not a gap:
- An orphan page (a page nothing links to) is a connectivity problem, not missing knowledge. The article exists; it needs a See Also, not a gap entry. Orphans stay in Lint where they are.
- A broken link to a page that should exist is a Lint repair (find the same-named file and fix the path), not a gap. Only a reference to a concept that genuinely has no article becomes a
wantedgap. - Anything outside the wiki's subject. A question the wiki was never meant to answer is not a gap in it. Filter these out at capture.
Entry format
Group entries by topic, mirroring index.md. Within a topic, list open entries first, then resolved ones. Each entry is a level-3 heading with a greppable prefix, followed by evidence lines:
# Knowledge Gaps
Known unknowns. Open gaps are ranked by evidence of demand, never by a score.
## machine-learning
### [open] question | How does FlashAttention-2 improve on the original?
- Raised by: [Attention Efficiency](machine-learning/attention-efficiency.md)
- Asked: 2026-05-20, 2026-06-02
### [open] wanted | Online softmax
- Referenced by: [Attention Efficiency](machine-learning/attention-efficiency.md)
- Noted: 2026-05-10
### [resolved] question | Is attention's quadratic memory cost a hard limit? -> [Attention Efficiency](machine-learning/attention-efficiency.md) (2026-05-27)grep "^### \[open\]" wiki/gaps.md lists every open gap, the same way the log's ## [ prefix lists recent activity. The heading is ### [<status>] <kind> | <title>, where status is open or resolved and kind is wanted or question. A resolved entry appends -> [Article](path) (YYYY-MM-DD) to its title line and keeps no evidence lines; the link is the record.
Links inside gaps.md use the same topic/article.md form as index.md (the file sits at the wiki/ root). Quote-style markdown links, not wikilinks, so it renders on GitHub.
Evidence, not a score
This is where a gap earns the same discipline as a claim. Never write priority: high or a number. State the support, which a reader can check:
- Referenced by - the articles that point at the missing concept. This comes straight from grep, so it is verifiable and cheap to refresh rather than hand-maintained.
- Asked - the dates a query missed on this gap. Each miss appends a date. A gap asked five times outranks one asked once, and the dates prove it.
- Raised by - the article or raw source that surfaced an open question.
- Noted - the date the gap was first recorded.
The user sorts open gaps by this evidence to decide what to research or ingest next. The register answers "what should I read about next" with facts, not a guessed ranking.
Capture: where gaps come from
Gaps are recorded only during operations the user runs. There is no crawler. Each existing operation already touches the natural capture point.
Ingest. While compiling:
- A load-bearing open question the source raises but does not answer goes into
gaps.mdas aquestion, instead of being buried in article prose. (High-fidelity ingest already pulls open questions out as atoms; this is where the durable ones land - seereferences/high-fidelity-ingest.md.) - A forward reference to a concept that has no article yet is a
wantedgap, recorded as you write the link. - Conversely, if the ingest creates the article that answers an existing gap, close it (see Lifecycle). Filling a gap and forgetting to close it leaves a false unknown on the register.
Query. The strongest signal, because a missed query is demonstrated demand:
- When the wiki cannot answer, or answers only partially, propose recording it. If a matching gap exists, append today's date to its
Askedline; otherwise create aquestionentry withRaised bythe query. - Propose, do not auto-write: the user confirms, and only for questions inside the wiki's subject. A plain query still writes nothing on its own; the gap is added with the user's go-ahead.
Lint. Lint already detects gaps but reports them into the chat, where they evaporate. Give the findings a durable home, split along Lint's existing two-tier authority (references/lint.md):
- Deterministic, safe to write: auto-close a
wantedgap whose article now exists, resolve gap links, and prune resolved gaps on retention. (Creating a gap is not deterministic - deciding a mentioned concept warrants a page is judgement.) - Heuristic, propose only: "concept mentioned often but no page" and thin coverage are proposed as
wantedgaps, and an openquestionan article now answers is proposed for closing. The user confirms; never auto-authored into articles.
Lifecycle: gaps close, they do not vanish
This is supersession applied to absence. A filled gap is marked [resolved], linked to the article that closed it, and dated. It is kept, not deleted, because "we did not know X until article Z filled it on date Y" is worth keeping, the same reason a superseded page is kept.
- Closing. Change
[open]to[resolved], drop the evidence lines, and append-> [Article](path) (date). Awantedgap auto-closes deterministically once an article of that name exists. Aquestioncloses when the article that answers it is written and linked, which is judgement, so it happens at ingest time or when Lint proposes it. - Retention. Resolved entries are pruned on the same git-backed rule as
log.md: when the wiki is a git repo, keep recent resolved entries and let git carry the rest, leaving a recovery marker. If the wiki is not a git repo, do not prune. Open gaps are never pruned.
Filter at capture
The one rule that keeps gaps.md from rotting into an endless TODO list: record only gaps with evidence behind them. A passing mention is not a wanted page; a concept referenced by an article, or asked about in a query, is. An idle "we could also cover X" is not a question; an unknown a source or a user actually raised is. This is "filter at ingest, not in retention" applied to gaps: decide what is worth tracking when it arrives, so cleanup later is rare.
What this never does
- No priority numbers or confidence floats. Evidence only.
- No background scanning or autonomous writes. Capture happens inside ingest, query, and lint, all user-invoked.
- No new dependencies, database, or embeddings. One markdown file, grep, and the heuristics Lint already runs.
- No deleting resolved gaps outside git-backed retention. The history is the point.
- No auto-authoring an article to fill a gap. Lint surfaces and proposes; the user directs the fill, the same boundary as every other heuristic check.
High-fidelity ingest for long-form and noisy sources
How to compile a transcript, chat log, long article, or interview into the wiki without silently dropping or softening the detail that makes it worth keeping. Compiling a long source straight to prose is where load-bearing claims, exact numbers, and named entities quietly disappear. These steps are a checklist against that.
When to use this
Reach for it when one compile pass could lose detail: meeting and call transcripts, chat and Slack logs, long articles and threads, interview or research notes. Skip it for short, clean, single-claim sources (a release note, a definition, a one-page post); the normal Compile in SKILL.md already handles those, and the extra discipline is overhead there.
The steps
1. Extract atoms before prose. Read the source once and pull the durable items into a flat list first: decisions, commitments, claims, numbers, named entities, open questions, action items. Note where each came from. Only then write the article from that list. The atom list is the checklist that catches what writing-from-memory drops. An open question the source raises but does not answer, and the wiki cannot either, belongs in wiki/gaps.md as a question entry rather than buried in article prose where it is forgotten (references/gaps.md).
2. Right-size the unit. Do not force a sprawling source into one page. A meeting that covered three decisions across two topics becomes the articles those decisions belong to (merge or new, per SKILL.md), not a single "meeting notes" dump. One raw file can legitimately feed several wiki articles.
3. Preserve exact terms, numbers, and epistemic status. Keep the source's own terminology, figures, and hedging. "We will probably move to Postgres in Q3" is not "the team decided to move to Postgres." Do not harden a maybe into a decision, round away a load-bearing number, or flatten a disagreement into consensus. Distil the wording; preserve the meaning and the certainty.
4. Anchor load-bearing claims to the source. For a claim the wiki will lean on (a decision, a commitment, a surprising or contested fact), make it checkable. The Raw line already links the source file; for the heaviest claims, also quote the key sentence inline next to its raw link, and point at where in the source it lives - a section heading, a page, a transcript timestamp, the date of a post - so a reader can verify it without re-reading the whole source:
> "We're standardising on Postgres for all new services from Q3." ([Planning call](../../raw/infra/2026-05-03-planning-call.md), [00:12:30])This is a prose practice, not a required field. Reserve it for claims that carry weight; quote-anchoring everything just rebuilds the transcript. The locator is also what lets an audit (references/audit.md) check the claim against the exact spot rather than the whole file.
5. Triage explicitly, and say so. Long noisy sources are mostly filler. Decide what is durable knowledge versus chatter. "Nothing here is new" or "restates a known article" is a valid outcome: keep the raw file, fold anything real in as added evidence to an existing claim, and do not spawn a thin page. Compiling noise is worse than compiling nothing.
6. Faithfulness self-review. After writing, re-read the source once against your article and ask: did any load-bearing claim, number, or named entity get dropped, softened, or overstated? Fix before finishing. This second pass is cheap and catches exactly the drift long sources cause.
Keep the raw file faithful
The raw file is the safety net you anchor back to, so do not over-clean it. Strip only secrets and PII (per SKILL.md); leave speaker labels, timestamps, and structure intact. In a transcript those are signal: they tell you who committed to what and when.
In bulk ingest
When extractor sub-agents handle transcripts (see references/bulk-ingest.md), the same discipline applies to the proposal each returns: the claims list is the atom extraction, evidence is the anchor, and net_new is the triage. Apply steps 1, 3, and 5 inside each extractor; the orchestrator handles right-sizing and the faithfulness pass at compile time.
Lint: the full check list
Health checks on the wiki, in two tiers with different authority. Deterministic problems are fixed automatically; anything needing judgement is reported, never silently rewritten. You do not rewrite article prose on your own authority. The two-tier boundary and the post-lint log entry live in SKILL.md; this file is the enumerated checks each tier runs.
Deterministic checks (auto-fix)
Run the structural detections with the bundled helper rather than improvising a script: uv run scripts/lint_wiki.py <project-root> reports the frontmatter, index, links, raw, and local findings below (read-only; --checks selects a subset, --json for machine output, exit 1 when anything is found). It detects; you apply the fixes described here. If uv is unavailable, fall back to the grep and file-tool checks - and never heredoc a one-off script through the shell, since ! gets backslash-escaped and corrupts the code. The other deterministic checks - See Also, log retention, the wiki skill file's links, concept-map freshness and map-sources resolution, and the gap register - are not scripted; do them with the file tools and grep. Concept-map mermaid syntax has its own validator (see the Concept maps check).
Index consistency - compare wiki/index.md against actual wiki/ files (excluding README.md, index.md and log.md):
- File exists but missing from index -> add an entry with
(no summary). Use the frontmatterupdateddate if present, otherwise the file's last modified date. - Index entry points to a nonexistent file -> mark it
[MISSING]. Do not delete; let the user decide.
Internal links - for every markdown link in article bodies (including Sources lines), excluding Raw links and README.md/index.md/log.md:
- Target missing -> search
wiki/for a file of the same name. Exactly one match: fix the path. Zero or several: report.
Raw references - every Raw link must point to an existing raw/ file:
- Target missing -> search
raw/for a file of the same name. Exactly one match: fix. Zero or several: report.
Frontmatter - every article must have well-formed frontmatter:
- Missing required field (
title,type,topic,created,updated,status) -> fill what is derivable (topic from folder, dates from file or index), report the rest. status: stalebut nosuperseded_by, or no supersession callout -> report (do not guess the replacement).superseded_bypoints to a nonexistent file -> report.
See Also - within each topic directory: add obviously missing cross-references between related articles; remove links to deleted files.
Wiki skill file - if a root SKILL.md exists (the query-only skill, references/templates/wiki-skill-template.md), its links into wiki/ must resolve: a missing target gets the same fix-or-report treatment as an internal link (search wiki/ for a same-named file, fix a single match, report zero or several). Do not touch its name or description; those are judgement (heuristic tier).
Log retention - keep wiki/log.md bounded, but only when the wiki is a git repo (git is then the canonical history). If the log holds more than ~12 months of entries, remove the oldest, keeping everything from the last 12 months and at least the most recent 20 entries, and leave one marker line under the # Wiki Log heading: <!-- Older entries trimmed; full history in git: git log -p wiki/log.md -->. Preserve the heading and the format comment. If the wiki is not a git repo, never trim - the log is then the only history, so report its size instead.
Concept maps - for mermaid blocks in articles (rules in references/concept-map.md):
- Validate syntax with the bundled validator when
uvis available:uv run scripts/lint_mermaid.py --require-edge-labels --max-nodes 12 <files>. It is dependency-free. Ifuvis not installed, skip scripted validation and check the block by eye - never block the lint on a missing tool. A reported error (unbalanced brackets, unclosed label, empty block, undefined style class) means the diagram will not render or breaks a rule; fix it or report it. map-sourcespaths must resolve to existing articles, the same as an internal link: search for a same-named file, fix a single match, report zero or several.- Freshness: for a map in a
current(non-archive) article, if anymap-sourcesarticle'supdatedis newer than the host article'supdated, annotate the block<!-- stale-map: <source> updated YYYY-MM-DD after host -->. Annotate only; redrawing is judgement, left to the user. Skiptype: archiveandstatus: stalepages - their maps are snapshots.
Local-content leak guard - no committed file may link into local/ (references/local-content.md). Scan tracked files (wiki/, raw/, index.md, log.md, gaps.md, README.md, the root SKILL.md and CLAUDE.md) for any markdown link whose target resolves into local/ - for example grep -rnE '\]\(\.{0,2}/?(\.\./)*local/' wiki/ raw/ SKILL.md. Report each as a finding (it is broken for other clones and leaks the path into git); do not rewrite the prose, since the fix - drop the link, or promote the local draft into raw/ + wiki/ - is judgement. local/ itself is never scanned: its internals are exempt from every other lint check.
Gaps register - for wiki/gaps.md (format in references/gaps.md):
- A wiki predating this feature may have no
wiki/gaps.md. Do not create an empty one proactively; it is created at init for new wikis, and otherwise the first time a gap needs recording (heading# Knowledge Gaps). Its absence is not a finding. - Every link in a gap entry (
Raised by,Referenced by, and a resolution target) must resolve, the same as an internal link: search for a same-named file, fix a single match, report zero or several. - Auto-close fulfilled
wantedgaps: if an[open] wantedgap names a concept that now has an article (a file or title match), close it - change[open]to[resolved], drop the evidence lines, and append-> [Article](path) (today). This is mechanical; closing aquestionis judgement and stays in the heuristic tier. - Retention, only when the wiki is a git repo: prune the oldest
[resolved]entries on the same rule as the log, keeping recent ones and leaving git to carry the rest. Never prune[open]entries. If the wiki is not a git repo, do not prune.
Heuristic checks (report only)
Rely on judgement. Report findings; do not auto-fix.
- Factual contradictions across articles that lack a conflict annotation.
- Claims a newer source has superseded but that were never marked stale.
- Orphan pages with no inbound links (no backlinks from other articles). This is a connectivity gap, not a knowledge gap: the fix is a See Also, not a
gaps.mdentry. Do not record orphans in the gap register. - Missing cross-topic references.
- Concepts mentioned often but lacking their own page. Propose each as a
wantedgap inwiki/gaps.md(references/gaps.md); add it only with the user's go-ahead, never auto-author the article. - Open
questiongaps inwiki/gaps.mdthat an existing article now appears to answer. Propose closing them with a resolution link; closing aquestionis judgement, so confirm rather than auto-fix. - Articles that appear to cover more than one distinct concept (often several top-level sections that could each stand alone) - candidates for splitting into linked articles.
- Concept maps that do not earn their place: two-node, purely linear (no node gains a second inbound or outbound edge, so there is no branching or convergence), a restatement of the See Also list, or unlabelled edges. Recommend removing them - a map with no value is worse than none.
- Concept-map edges that look unsupported or contradicted by the articles they connect (verify against sources with Audit).
- Archive pages whose cited source articles have changed substantially since archival. For a deeper version of this check that reads the cited sources and verdicts each claim, see
references/audit.md. - No root
SKILL.md, so the wiki cannot be loaded as a query-only skill. Report it and offer to create one fromreferences/templates/wiki-skill-template.md; do not auto-create, since naming and describing it for the wiki's subject is judgement. ASKILL.mdwhosenameordescriptionis still a template placeholder, or has drifted from what the wiki now covers, is the same kind of finding: report it for the user to refine. - No root
CLAUDE.md, so an agent whose working directory is the wiki repo gets no project-memory orientation and may not know to read the wiki's SKILL.md or activate the llm-wiki skill. Report it and offer to create one fromreferences/templates/wiki-claude-md-template.md; do not auto-create, since the subject line is judgement (the same treatment as the root SKILL.md). ACLAUDE.mdstill carrying a{...}template placeholder is the same kind of finding. - No wiki
.gitignore, or one that does not excludelocal/, when the wiki is a git repo orlocal/exists. Offer to write or amend it fromreferences/templates/wiki-gitignore-template.md; merging the singlelocal/line into a user-maintained file is safe once confirmed, but do not silently rewrite the rest of their ignore rules.
Local content: personal notes kept out of git
An optional local/ directory at the project root holds personal markdown that lives in your clone only and never reaches the remote: meeting prep, half-formed ideas, drafts, working notes, and private sources you cannot or do not want to commit. It is a sibling of raw/ and wiki/, and the wiki .gitignore excludes it (references/templates/wiki-gitignore-template.md).
local/ is a scratch bench, not part of the compiled knowledge base. It carries none of the raw->wiki discipline: no required frontmatter, no index row, no log entry, no supersession. Write whatever you like, however you like.
The one rule: link direction
This is the whole safety story, so it is the rule to get right.
- `local/` may link into `wiki/` and `raw/`. Those files exist in every clone, so the link always resolves. A local note that references shared articles is the normal, intended case.
- No committed file may link into `local/`. A
wiki/article, the index, the log,gaps.md, the README, or the rootSKILL.mdpointing atlocal/...is a broken link for anyone else who clones the repo, and it leaks the path and filename into git history. Lint flags any such link (the leak guard,references/lint.md).
Put differently: shared content must read as complete and correct to someone who has never seen your local/ directory, because most people who clone the wiki never will.
Obsidian backlinks are fine here. When a local note links to a wiki article, Obsidian shows that backlink while you view the article, but it is computed live and never written into the committed file, so nothing leaks.
Structure
Start flat and freeform: any subdirectories and filenames you like under local/. There is no enforced layout.
When a note is tied to a date or an event - meeting prep, a daily note, a dated draft - prefix the filename with the date, the same idiom raw/ uses: local/prep/2026-06-04-scott-meeting-prep.md. It keeps notes sortable and easy to find later. A hint, not a rule: local/ is yours, so date what benefits from it and name the rest however suits you.
If you want the same discipline the wiki uses (a private source compiling into a private article with provenance), you can mirror the split inside local/ as local/raw/ and local/wiki/ and follow the normal ingest format by hand. That is an option for people who want it, not the default. Everything stays inside local/ and inside your clone either way.
How the operations treat local/
- Exempt from the managed machinery.
local/is outsideindex.md,log.md,gaps.md, cascade updates, and audit. None of those scan it or record it. - Query scans
local/when it exists, alongside the wiki, and labels any hit clearly aslocal/ (uncommitted)so a personal note is never mistaken for shared knowledge. - Ingest does not touch
local/by default. Personal notes are something you write, not something the skill compiles. - Lint ignores the internals of
local/(no orphan, frontmatter, or link checks in there), but runs the leak guard over committed files and offers a wiki.gitignoreif one is missing.
Promotion path
local/ is the drafting bench; wiki/ is the committed record. When a local note matures into knowledge worth sharing, promote it: run it through a normal ingest so a real source lands in raw/ and a compiled article in wiki/, with provenance and an index entry. Do not link the wiki to the local draft; rewrite it across the boundary. Keep or delete the local copy as you like once it is promoted.
Setup
local/ is created the first time you store something there, not at init, so empty wikis stay empty. The exclusion comes from the wiki .gitignore written at init (references/templates/wiki-gitignore-template.md). For a wiki that predates this, add local/ to its .gitignore (lint offers to write the template if there is none), then confirm with git status that local/ shows nothing before you trust it. If the wiki is not in git, local/ is moot - nothing is committed anyway - but the same link-direction rule still keeps shared articles self-contained.
Knowledge Base Index
{OPTIONAL note - if the vault is opened in Obsidian with the Dataview plugin, sections can be auto-generated from article frontmatter. The hand-maintained version below is canonical and works without any plugin.}
{topic-name}
{One-line description of this topic.}
| Article | Summary | Updated |
|---|---|---|
| {Article Title} | {One-line summary} | {YYYY-MM-DD} |
| {Stale Article} | [Stale] {One-line summary} | {YYYY-MM-DD} |
| {Archived Article} | [Archived] {One-line summary} | {YYYY-MM-DD} |
{another-topic}
{One-line description of this topic.}
| Article | Summary | Updated |
|---|---|---|
| {Article Title} | {One-line summary} | {YYYY-MM-DD} |