In August I wrote that Karpathy’s LLM wiki works, and that a weekly lint pass “recovers most of” the dead links and orphan pages a wiki piles up. That was wrong. The lint ran every week after that, and it recovered nothing.
Here is the log. My vault runs a scheduled checker every Sunday that counts pages, dead wikilinks and orphans. The last column strips out matches that were never links, which I’ll get to below.
| Week | Pages scanned | Dead wikilinks (raw) | Orphan pages | Actually broken |
|---|---|---|---|---|
| Aug 2 | 0 | 0 | 0 | 0 |
| Aug 9 | 0 | 0 | 0 | 0 |
| Aug 16 | 261 | 116 | 117 | 109 |
| Aug 23 | 264 | 120 | 117 | 113 |
| Aug 30 | 264 | 120 | 117 | 113 |
| Sep 6 | 267 | 120 | 118 | 113 |
| Sep 13 | 283 | 153 | 117 | 136 |
| Sep 20 | 293 | 153 | 117 | 139 |
| Sep 27 | 303 | 155 | 118 | 141 |
| Oct 4 | 317 | 169 | 124 | 145 |
| Oct 11 | 327 | 170 | 124 | 146 |
| Oct 18 | 334 | 170 | 124 | 146 |
The first two rows are a separate embarrassment. The checker was pointed at a folder I had retired in a migration, so it scanned zero pages and reported a clean wiki. The post claiming lint works went out on August 13, four days after the last zero-page run and three days before the first real one.
From August 16, when it scanned the real vault, to October 18, pages grew 28% and actually broken links grew 34%. That’s roughly 0.42 per page at the start and 0.44 at the end: the rate held steady. What never happened is the thing lint is supposed to cause. Across ten weekly runs, the broken-link count never went down once, and orphans ended at 124, up from 117. Detection ran on schedule every week. Nobody repaired anything.
So the missing line item in Karpathy’s pattern isn’t the lint. Lint is cheap. It’s the repair, and the repair turns out to be mostly decisions a script can’t make.
A repair script could fix none of 185 on its own
In September I added a repair tool. It finds every [[link]] whose target note doesn’t exist and tries to match it to a real note: first case-insensitive, then fuzzy. It rewrites only the safe cases, where the link differs from a real filename by capitalization or spacing.
I ran it today in dry-run mode. It took 2.7 seconds.
vault-repair: 185 dead wikilinks — 0 confident fixes, 4 fuzzy suggestions, 181 unresolved
~ 200-knowledge/context/recipe-context.md: [[recipes/classic-meatloaf]] ≈ [[classic-meatloaf]]
Zero safe fixes. Four suggestions, all the same mistake: a recipe linked by folder path instead of note name. The other 181 have no candidate at all.
(The weekly checker said 170 on Sunday; the repair script says 185 today. Different tools on different days, and I haven’t diffed the two lists, so I can’t tell you yet which explains the gap.)
Most dead links are names the agent was told to write
I sorted all 185 by what they point at.
| What the link is | Count |
|---|---|
| A name or topic with no note behind it, mostly people, companies and services (41 of them in archived daily logs) | 154 |
| A CONFIRM placeholder my draft pipeline leaves in old blog drafts | 17 |
| Example syntax inside a third-party README I saved | 7 |
| A folder-path link: 4 to recipes that exist, 3 to index pages that don’t | 7 |
The big row is the interesting one. My operating file tells the agent to wikilink every person, company and service the first time it comes up, so a later page about the same entity connects back. That rule works. It’s also a dead-link generator. Every new name gets brackets the moment it’s written, and nothing creates the card behind it.
Schwab is linked six times. Plaid three. Most of the rest are names that came up once or twice in a daily log, each wrapped in brackets and pointing at nothing.
Karpathy’s original gist names this exact finding. His lint step looks for “important concepts mentioned but lacking their own page.” Finding them was never the hard part. Each one is a question only the wiki’s owner can answer: does this name deserve a card, or should the brackets go? A name mentioned once in a call note probably doesn’t need a page. An institution that holds your money does.
The bottom three rows are noise, and they say something too. The repair script’s link pattern matches anything inside double brackets:
LINK_RE = re.compile(r"\[\[([^\]|#]+)(?:#[^\]|]*)?(?:\|[^\]]*)?\]\]")
So my content pipeline’s own review markers count as broken links, and so do the [[wikilinks]] examples in the READMEs of nvk/llm-wiki and Ar9av/obsidian-wiki that I saved for reference. A dead-link count is a count of bracket pairs, not of broken knowledge. 24 of the 185 were never links in the first place, and the weekly checker counts them too. On August 16 it counted 7 of those. By October 18 it counted 24, because my draft pipeline had started leaving CONFIRM markers in saved drafts. That’s why the raw column in the table above grew faster than the real one.
Auto-created stubs move the number, not the problem
The obvious fix: have the agent create a stub card whenever it writes a new link. The dead-link count goes to zero overnight.
That trades one lint finding for another. A stub with a title and no content is an orphan in everything but name. Nothing useful links into it, and nothing in it is worth reading. I already carry 124 orphans. Stubs would add up to 154 more and make the checker look healthier while the wiki gets no more useful.
It also defeats the point of the card. An entity card is worth having because it’s the one place a fact about that entity lives. A stub promises that place exists and then holds nothing. The next session that reads it learns the name and nothing else.
Where this stops mattering
A small wiki in one domain probably won’t hit this. My guess, and it’s only a guess, is that it stays manageable while there are few enough names to card each one as it arrives. Mine broke down once it spanned several domains and the daily logs mentioned people faster than anyone curated them.
A team with someone whose job is curating the wiki won’t hit it either. That person is the missing line item.
Budget the decisions, not the lint
If you’re rolling Karpathy’s pattern out to a team, the lint is the part you can automate and forget. Count the other thing: how many new names enter the wiki each week, and who decides whether each one gets a card.
My count today is 154 open decisions, built up over ten weekly lint runs nobody acted on. The script fixed none and suggested 4. The rest need an owner, and the weekly report is only useful if someone reads it on Monday.