The bet: a wiki the AI maintains and the human validates
In April 2026, Andrej Karpathy published a short text, the “LLM Wiki”. Three layers: raw sources you never edit, a Markdown wiki written by the model, and a schema file that sets the rules. Three operations: ingest, query, lint. The thesis fits in one sentence: humans abandon their wikis because maintenance is tedious, and with an LLM the maintenance cost goes to zero.
I took him at his word, but for a different use than the readings he had in mind: the steering register of a freelancer. About twenty projects, client and personal, with their status, next action and the decisions taken. The starting point was ordinary: documentation scattered across Notion, Obsidian, a drive and conversations with the AI, plus a healthy distrust of hallucinations.
What got built in one evening, on September 28:
- a Git repository on my self-hosted forge, opened in Obsidian, with a
CLAUDE.mdacting as a constitution; - an
inbox/fed by two agents, a daily one (the one that maintains this blog) and a weekly sync from Notion; they are only allowed to drop captures there; /ingest, with a human in the loop, to merge those captures into the pages;- a dependency-free Python lint, run by a cluster CronJob every Monday, report on Telegram.
The truth rules are what I keep as the best part. Every fact carries a source and a date. A ”?” beats a guess. When information is missing, the answer is “Not in the wiki”, never an improvisation. And a five-step delivery scale: specified → coded → tested → pre-prod → verified in service, the last one requiring the output of the proving command to be pasted into the page. A test receipt, applied to documentation.
The return on investment came within twenty-four hours: an administrative follow-up forgotten for weeks, two reference documents that contradicted each other, a sent document nobody could tell which version had gone out, and nine actions sorted by priority. None of the previous tools had produced that.
The numbers at day 4: the wiki was not keeping up
On October 2, I did what you do with any system you just put into production: count.
| Measure | Value |
|---|---|
| Pages | 30, of which 20 projects and 4 decisions |
| Versioned lines | 24,086, of which 1,689 of Markdown (7 %) |
| Open points ”? / to confirm” | 42 |
| Wiki commits | 8 on Sept 28–29 · 0 on Sept 30 and Oct 1 · 2 on Oct 2 |
| Infra repo commits on Oct 2 | 17 |
/ingest, /query, /lint typed as commands | 0 |
October 2 is a good full-scale test. That day the GitOps repository receives 17 commits: three sites and the blog move to a new deployment pattern, one application is removed and redeployed under another name, two tools move out to their own repositories. The wiki receives 2 commits. The new application has no page. The pages of the migrated sites say nothing about the migration. The same day, my assistant’s automatic memory modifies 6 files, including a complete sheet on the new application.
The 93 % of lines that are not Markdown? An Obsidian query plugin, installed the first evening, used on no page. And the most-cited page of the wiki was not the portfolio but the migration catalogue: the scaffolding was still holding up the building.
The feed chain: four links, four failures
The daily agent had seen everything, though. On October 1, its log notes that an active project’s page is behind. On the 2nd, it finds two projects without a page and one page even more outdated. And it dropped nothing in the inbox. Walking back up the chain, I found not one failure but four, stacked, each hiding the next.
le lanceur lisait 8 % et autorisait ; le skill relisait sur 15 min, ne trouvait rien, et sautaitthe launcher read 8 % and allowed; the skill re-read over 15 min, found nothing, and skipped
une capture coûte quelques lignes ; seul l'article de blog mérite d'attendre le quotaa capture costs a few lines; only the blog article deserves to wait for quota
à 3 items par run derrière l'arriéré blog et docs, le wiki aurait attendu plus d'une semaineat 3 items per run behind the blog and docs backlog, the wiki would have waited over a week
les captures restaient sur le PC, invisibles de la forge et du lint du clustercaptures stayed on the PC, invisible to the forge and to the cluster lint
Link 1, quota. The agent runs on my subscription, not on an API key; before writing anything it reads the consumption published by a small collector. The PowerShell launcher read that series over a 48-hour window and found 8 %: green light. The skill re-read the same series over a 15-minute window, fell into a collection gap, and concluded “empty answer, caution”. Two windows for one measurement.
Link 2, caution. Unreadable quota, the run switched to “detection only”. Sensible for writing a blog article, the expensive step. Absurd for a ten-line capture that costs almost nothing. The rule did not tell them apart.
Link 3, the queue. “Project” items were processed like any other: three items per run, oldest first. The six pending project items sat at ranks 22 to 33 of 33, behind a backlog of articles and doc drifts. Even with the valve open, the wiki would have waited more than a week.
Link 4, the commit. The founding decision said: the agent drops files, “Obsidian Git handles the rest”. The plugin was configured properly, backup every 15 minutes. It produced zero commits since the wiki was created, because Obsidian was simply not open on that PC. A dropped capture would have stayed a local file, invisible to the forge and to the cluster lint.
The weekly lint, meanwhile, was impeccable. Non-root pod, read-only filesystem, no capabilities, no git: it fetches an archive of the repository through the forge API. It checked the wiki’s form: frontmatter, links, declared dates. It did not know an application existed without a page. The one that knew lived in another system.
The lint that cried wolf
In passing, three defects of the lint itself, because they are instructive.
The open-points counter detected ? and “to confirm” separately. But the wiki’s convention writes ”? to confirm”: every point was counted twice. The 42 open points were really 22. Better still: the page describing the knowledge system pasted the lint output as proof of commissioning, output that contains the string ”? / to confirm”. The lint was detecting itself. The proof ritual was polluting the signal.
The only red item, a public URL answering 530 because the server is not installed yet, was known and accepted. With no way to acknowledge it, every Monday report opened with “red: to fix”.
And the verification date was stored twice, in the portfolio and in each page: two discrepancies out of twenty after four days.
Batch 1: fix the feed before adding features
The whole of batch 1 fits in half a day and four moves, each covered by a test that failed before going green.
- One quota window, 48 hours, read the same way by the launcher and the skill.
- Unreadable quota → captures only, never “nothing” again. Article writing stays subject to quota.
- Project items go first, outside the three-item cap, ten at most per run.
- The launcher commits the captures. A PowerShell script, no LLM, that adds only the new
inbox/YYYY-MM-DD-*.mdfiles, pushes the main branch, rebases while preserving work in progress if the remote moved, and does nothing if the repository is not onmain. Twenty-five checks against a real throwaway git repository: rebase, push refused then retried on the next run, wrong branch.
And for the lint: ”? to confirm” counted once, code and quotations ignored, a connu_jusqu_au: field that acknowledges a known URL failure until a date, and a new check: a history entry that says “verified” without verifie_le moving is flagged.
The founding decision was replaced by a new one, as the wiki demands of itself: you do not reopen a decision, you write another one with remplace:.
Batch 2: measure instead of declare
Batch 1 reopened the valve. Batch 2 tackles the real problem: a verifie_le is a declaration, and a declaration goes stale silently.
Coverage. Each page claims its repositories in the frontmatter: depots: [repo-name, other]. The lint lists the forge’s repositories through the API, with the read-only token already mounted in the pod. Any non-archived repository pushed within the last 30 days that no page claims comes out red: “project without a page”. Repositories without a project are declared on a dedicated page, with the reason. First reading: 22 active repositories, all claimed.
Freshness. Same field: if a repository received commits after verifie_le, the page comes out yellow, “N commits since verification”. First reading: 5 pages to re-verify, including a “parked” page whose repository had received more than 50 commits since its verification date. Exactly what the agent had seen the day before, but computed every Monday by the cluster, without a single model call.
Two robustness details that an independent review raised and the tests now cover: an API error on a single repository must not cancel the whole check (each failing repository comes out alone in yellow), and pagination beyond 50 repositories is verified by mutation, deleting the loop to watch the test fail.
The portfolio is generated. A script rebuilds the portfolio tables between two HTML markers, from statut, a new action: field and verifie_le. The drifting duplicate disappears, and so does the query plugin: 20,875 lines gone.
/ingest goes through a PR. An ingest/… branch, a pull request opened by a script (in UTF-8 JSON: the forge API rejects a curl body whose accents are mangled), a CI job on the NAS runner that runs the 47 tests, checks that the portfolio is up to date and runs the lint without network. I merge from my phone. “The AI maintains, the human validates” stops being an end-of-session ritual and becomes a mechanism.
Day 5: the chain runs, and catches what I missed
October 3, 12:30, first complete run after the repair.
| Step | Oct 2 | Oct 3 |
|---|---|---|
| Quota read | 8 %, then “empty” | 35 %, session 3 % |
| Processing | skipped | 12 items in 8 min |
| Project items processed | 0 | 9 of 9, first |
| Captures dropped | 0 | 5 |
| Commit on the forge | none | ”inbox: 5 capture(s)”, 2 seconds after the run |
Four of the nine items were closed without a capture, with an exact line reference to the page that already covered the fact: deduplication works. The five remaining captures are sourced (commits, kubectl, curl, docker ps), each with an integration suggestion per page.
Two of them fix gaps in my own manual catch-up from the day before: a service deployed on October 1 and a new infrastructure map, both forgotten. A third replaces a ”? to confirm” with a docker ps output. That is the expected added value: the wiki no longer depends on what I remember to write.
The first /ingest as a PR followed within the hour: green CI, merge, empty inbox, 0 red in the lint.
What I take away
Karpathy is right, and it is subtler than it looks. Writing costs almost nothing anymore. What costs is triggering the writing. Since the wiki was created, none of the three commands had been typed. The rule “every session ends with /ingest” is a ritual, and a ritual always loses against a side effect. My assistant’s automatic memory was winning because it writes itself during the work, not after.
Knowledge accumulates, state expires. The LLM Wiki model targets knowledge that accumulates: readings, concepts. I store in it a state that expires every day. A project status looks more like a metric than a note: it has to be measured, and the most honest measurement is the git repository itself.
Test the chain, not the links. Each link worked “in principle”. No test crossed the whole chain, from detector to commit on the forge. The question I failed to ask on September 28: “if the agent finds something tomorrow at noon, where is the commit at 12:45?”
A permanent red is an invisible red. The lint produced the same red item every week for a known cause. By the second report, nobody reads it anymore. Acknowledging with an expiry date costs one line of frontmatter and saves the signal.
Tests caught what reviews missed. The BOM that PowerShell 5.1 slips into a JSON file, the leading space that Out-String().Trim() eats from git status --porcelain output, the # of a URL mistaken for a frontmatter comment: three real bugs, found by tests written before the code, against real throwaway git repositories and a fake API server.
One honest open question remains: a read-only agent is soon to answer questions from this wiki. Before plugging it in, I want a set of twenty questions, five of them with no answer in the wiki, and to measure how often the system correctly answers “Not in the wiki”. The anti-hallucination promise will become a number. Or not.