Every week, brand and GEO monitoring teams run hundreds of queries against ChatGPT 5.5, Perplexity, and Google AI Overviews to understand how their brand is represented in AI-generated answers. Every week, those observations disappear. Monday's finding — that ChatGPT 5.5 has started citing a competitor as the preferred enterprise solution for your category — is invisible to the analyst running Friday's queries. The problem is not that the monitoring is inadequate. It is that the intelligence generated by monitoring never accumulates.
On April 4, 2026, Andrej Karpathy published a gist titled "LLM Wiki" — a text-only architectural sketch of a pattern in which an LLM incrementally builds and maintains a persistent, structured knowledge base from raw sources. Within weeks, a community of implementations had appeared. What none of them addressed is the most commercially tractable application of the pattern: using it as the compounding intelligence layer for brand and GEO monitoring. This article fills that gap. It is the first published implementation of Karpathy's LLM Wiki pattern applied specifically to brand citation monitoring and Generative Engine Optimisation.
What Karpathy's LLM Wiki actually is
The gist (hash ac46de1ad27f92b28ac95459c782c07f6b8c964a, single revision since creation) contains no code. Karpathy is explicit: "This document is intentionally abstract." It describes a three-layer architecture, three operations, and two special files. The central claim: "The knowledge is compiled once and then kept current, not re-derived on every query." This is the distinction from RAG — which retrieves raw chunks on every query — that has animated the "RAG is dead / RAG is fine" debate across multiple Show-HN posts during April–May 2026.
The three operations that drive the pattern:
log.md in the format ## [YYYY-MM-DD] ingest | Source Title. Log entries are append-only and grep-able by design.qmd (github.com/tobi/qmd) — a local hybrid BM25/vector + LLM re-ranking CLI — for local deployments.eslint is to a codebase.The lineage Karpathy draws is precise: Vannevar Bush's Memex (1945) — the imagined machine that would let researchers traverse an associative trail of knowledge. "The part he couldn't solve was who does the maintenance. The LLM handles that." The insight is that every previous knowledge management system — from wikis to Zettelkasten — failed at scale because human maintenance is too expensive. The LLM removes that bottleneck.
The intelligence accumulation gap in GEO monitoring
Current GEO and brand monitoring tools — whether custom pipelines or commercial platforms — share a structural limitation: they measure, they do not accumulate. A query run against ChatGPT 5.5 today produces a data point. A query run next week produces another data point. The connection between them — the same competitor mentioned in the same context across six weeks, the aspect sentiment for "enterprise support" shifting consistently downward, the emergence of a new framing around your product — lives in spreadsheets, dashboards, or nobody's head.
The Karpathy pattern is the architectural fix. Rather than discarding each monitoring session's output after aggregation, the Ingest operation compiles it into a persistent wiki: entity pages per brand, per platform, per competitor, per aspect — updated on every run, cross-referenced, and queryable without re-running the original monitoring. After six months of daily Ingest operations, the wiki contains structured institutional knowledge about how your brand is represented across AI platforms that no individual analyst accumulated manually and no dashboard was designed to capture.
In software, you compile source code once and run the binary repeatedly. In GEO monitoring, you compile raw LLM observations into structured wiki pages once (per ingest cycle), and query the compiled knowledge repeatedly — without re-running the original monitoring prompts. The cost of answering "how has our brand sentiment on ChatGPT 5.5 trended over the last 90 days across the 'enterprise security' aspect?" drops from "re-run 90 days of queries" to "read the brand/acme/aspect-security.md page."
Adapting the three layers for brand intelligence
The practical adaptation requires specifying what goes in each layer for a GEO monitoring context.
Raw Sources are your monitoring run outputs: JSON responses from LLM APIs, citation URLs extracted from Perplexity responses, structured exports from AEO tools, competitor mention logs. These are immutable once written — append a new directory per run date, never overwrite.
The Wiki is a directory tree of brand intelligence pages. Here is a production-ready structure:
wiki/ index.md # Content catalogue, organised by category log.md # Append-only ingest log entities/ brands/ acme-corp.md # Full brand profile: visibility, sentiment, framing competitor-x.md platforms/ chatgpt-5-5.md # Platform behaviour, citation patterns, model drift notes perplexity.md google-aio.md aspects/ enterprise-security.md # Aspect-level sentiment across all brands and platforms pricing-perception.md citations/ 2026-05/ # Monthly citation records, one file per platform per query class sentiment/ weekly-digest.md # LLM-synthesised weekly sentiment summary sources/ 2026-05-16/ # Immutable raw output from today's monitoring run chatgpt-5-5-responses.json perplexity-responses.json
The Schema is a BRAND.md file — the CLAUDE.md equivalent for your brand wiki. It tells the LLM what conventions to follow during Ingest, what the aspect taxonomy is, how to score sentiment, and what the cross-reference rules are.
# Brand Intelligence Wiki — Schema ## Sentiment scoring Use a 1–5 Likert scale per aspect. Always emit a justification span: the verbatim substring from the source that drove the score. Example frontmatter for a brand entity page: --- brand: Acme Corp last_updated: 2026-05-16 platforms_monitored: [chatgpt-5-5, perplexity, google-aio] aspects: enterprise_security: {score: 4, trend: stable, last_seen: 2026-05-15} pricing_perception: {score: 2, trend: declining, last_seen: 2026-05-16} customer_support: {score: 3, trend: improving, last_seen: 2026-05-14} --- ## Cross-reference rules - Every brand page links to its platform pages and vice versa - Every claim includes [source: sources/YYYY-MM-DD/filename.json#line] - Time-bounded facts use format: "as of YYYY-MM-DD" ## Aspect taxonomy Recognised aspects: enterprise_security, pricing_perception, customer_support, product_quality, integration_ecosystem, compliance_certifications, leadership_stability, esg_commitments ## Log format ## [YYYY-MM-DD] ingest | {platform} | {query_class} | {n} mentions extracted
The ingest pipeline in production
The ingest pipeline runs after each monitoring cycle — daily for priority prompts, weekly for the long-tail corpus. It takes a raw platform response, extracts structured brand mentions, gates each claim through a hallucination check, and writes verified facts to the wiki.
import anthropic, json, pathlib from datetime import date def ingest_monitoring_run( platform: str, query: str, response_text: str, wiki_path: pathlib.Path, ) -> None: """ Ingest one LLM platform response into the brand wiki. Extracts mentions → gates hallucinations → updates entity pages. """ client = anthropic.Anthropic() # Step 1: Extract structured brand mentions extraction = client.messages.create( model="claude-opus-4-7-20260416", max_tokens=2048, system="You are a brand intelligence analyst. Extract structured data only.", messages=[{"role": "user", "content": f""" Analyse this LLM platform response and extract every brand mention. Return a JSON array. Each element must have: - brand: exact brand name as it appears - position: "primary_recommendation" | "secondary" | "mentioned" | "dismissed" - overall_sentiment: integer 1-5 - aspects: dict mapping aspect name -> {{score: 1-5, justification_span: str}} - key_claims: list of specific factual assertions made about this brand - citation_url: URL cited alongside this mention, or null Platform: {platform} Query: {query} Response: {response_text} Return JSON array only. No prose."""}] ) mentions = json.loads(extraction.content[0].text) # Step 2: Gate each mention through hallucination check verified = [] for mention in mentions: confidence = _selfcheck_nli( mention["key_claims"], platform, query, client ) mention["confidence"] = confidence mention["needs_review"] = confidence < 0.70 verified.append(mention) # Step 3: Update wiki entity pages for mention in verified: _update_brand_page(mention, platform, wiki_path) # Step 4: Append to log.md (grep-able, append-only) n_clean = sum(1 for m in verified if not m["needs_review"]) log_line = ( f"## [{date.today()}] ingest | {platform} | {query[:50]}... | " f"{n_clean}/{len(verified)} mentions verified\n\n" ) with open(wiki_path / "log.md", "a") as f: f.write(log_line) def _update_brand_page(mention: dict, platform: str, wiki_path: pathlib.Path): brand_slug = mention["brand"].lower().replace(" ", "-") page_path = wiki_path / "entities/brands" / f"{brand_slug}.md" # Read existing page or initialise it existing = page_path.read_text() if page_path.exists() else "" client = anthropic.Anthropic() updated = client.messages.create( model="claude-opus-4-7-20260416", max_tokens=4096, messages=[{"role": "user", "content": f""" Update this brand intelligence wiki page with new monitoring data. Follow the BRAND.md schema. Mark time-bounded claims with "as of {date.today()}". Flag needs_review claims with a ⚠️ prefix. Keep all existing verified data. Existing page: {existing or "(new page)"} New monitoring data from {platform}: {json.dumps(mention, indent=2)} Return the complete updated Markdown page only."""}] ) page_path.parent.mkdir(parents=True, exist_ok=True) page_path.write_text(updated.content[0].text)
The hallucination gate — do not compile what the model made up
The most dangerous property of the LLM Wiki pattern for brand monitoring is also its most powerful: the LLM writes to the wiki. A hallucinated claim about your brand — wrong pricing, a misattributed certification, an invented partnership — compiled into a wiki page becomes a persistent fact that contaminates every future query and every future ingest cycle. In RAG, a hallucination affects one session. In a wiki, it compounds.
The solution is a write gate based on SelfCheckGPT (Manakul, Liusie & Gales, EMNLP 2023, arXiv:2303.08896). The principle: sample the same source query N times at elevated temperature, then use an NLI model to check whether each extracted claim appears consistently across samples. Claims that appear in only some samples are likely confabulations. Claims that appear consistently are grounded in the model's training data and are safer to commit.
from transformers import pipeline import numpy as np # Load once at module level; DeBERTa-MNLI is the standard NLI model _nli = pipeline( "text-classification", model="cross-encoder/nli-deberta-v3-small", device=-1, # CPU; use 0 for GPU ) def _selfcheck_nli( claims: list[str], platform: str, original_query: str, client: anthropic.Anthropic, n_samples: int = 5, ) -> float: """ SelfCheckGPT-NLI variant. Returns a float 0–1: fraction of claims that are consistently supported across N stochastic re-samples. """ if not claims: return 0.5 # no claims → medium confidence # Generate N alternative samples at temperature 0.7 samples = [] for _ in range(n_samples): r = client.messages.create( model="claude-opus-4-7-20260416", max_tokens=512, system="Answer concisely about the brand mentioned.", messages=[{"role": "user", "content": f"What does {platform} typically say about brands in this context?\n" f"Query: {original_query}"}], ) samples.append(r.content[0].text) # For each claim, measure NLI entailment against all samples claim_confidences = [] for claim in claims: scores = [] for sample in samples: result = _nli( f"{sample} [SEP] {claim}", truncation=True, max_length=512 ) entail_score = next( (r["score"] for r in result if r["label"] == "ENTAILMENT"), 0.0 ) scores.append(entail_score) claim_confidences.append(np.mean(scores)) # Return mean confidence across all claims return float(np.mean(claim_confidences))
The 0.70 threshold is a starting point, not a universal rule. For claims about certifications, regulatory status, or pricing — where a false positive has compliance or commercial consequences — raise it to 0.85. For claims about general market positioning — lower-stakes framing observations — 0.65 may be sufficient. Claims below threshold are written to the wiki with a ⚠️ prefix and a needs_review: true flag in the frontmatter, making them queryable but visually distinct until a human confirms them.
For a cheaper first-pass gate before the NLI check, a semantic entropy probe — distilled from Farquhar et al.'s semantic entropy work (Nature 630(8017), 2024) — can eliminate obviously consistent claims at near-zero cost, reserving the NLI computation for ambiguous cases only.
The lint operation — keeping the wiki honest over time
Ingest builds the wiki. Lint maintains its integrity. In a brand monitoring context, lint catches four problems that ingest cannot: contradictions between platform pages (ChatGPT 5.5 characterises your pricing as "mid-market" while the Perplexity page says "enterprise-tier"); temporal claims without validity dates that are now stale; orphan entity pages that exist but are never referenced; and aspect pages that have not received an update in more than 30 days — a signal that monitoring coverage has drifted.
def lint_brand_wiki(wiki_path: pathlib.Path) -> list[dict]: """ Run the Lint operation across the full brand intelligence wiki. Returns a list of flagged issues, sorted by severity. """ client = anthropic.Anthropic() # Collect all wiki pages pages = [] for path in wiki_path.rglob("*.md"): if path.name not in ("log.md", "index.md"): pages.append({ "path": str(path.relative_to(wiki_path)), "content": path.read_text() }) wiki_dump = "\n\n---\n\n".join( f"# {p['path']}\n{p['content']}" for p in pages ) result = client.messages.create( model="claude-opus-4-7-20260416", max_tokens=4096, messages=[{"role": "user", "content": f""" You are auditing a brand intelligence wiki. Today is {date.today()}. Identify ALL issues across these categories: 1. CONTRADICTION — conflicting factual claims between pages 2. STALE_CLAIM — time-bounded fact older than 30 days without an update 3. ORPHAN_PAGE — page with no inbound links from other pages 4. COVERAGE_GAP — aspect page not updated in > 30 days 5. MISSING_SOURCE — factual claim with no [source: ...] citation 6. MISSING_PAGE — entity mentioned in 3+ pages but lacking its own page Return a JSON array. Each issue: {{ "type": "CONTRADICTION|STALE_CLAIM|ORPHAN_PAGE|COVERAGE_GAP|MISSING_SOURCE|MISSING_PAGE", "severity": "high|medium|low", "page": "relative/path/to/page.md", "description": "specific, actionable description of the problem", "suggested_action": "what the next ingest or manual edit should do" }} Wiki content: {wiki_dump[:80000]} Return JSON array only."""}] ) issues = json.loads(result.content[0].text) return sorted( issues, key=lambda x: {"high": 0, "medium": 1, "low": 2}[x["severity"]] )
Run Ingest after every monitoring cycle (daily or near-daily for priority platforms). Run Lint weekly — not after every ingest. Lint reads the entire wiki; running it daily doubles costs with negligible additional benefit, because contradictions and orphans accumulate over days, not hours. Schedule Lint to run on Monday mornings, producing a prioritised issue queue for the week ahead.
Choosing a memory backend
Karpathy's pattern is deliberately storage-agnostic. For most brand intelligence wikis, plain Markdown files on disk — the native pattern — are the right starting point. The upgrade path depends on scale and retrieval requirements.
| Backend | Storage model | Temporal facts | Retrieval | Best fit for brand wiki |
|---|---|---|---|---|
| Plain Markdown (Karpathy-native) |
Files on disk, git-versioned | Manual — date in page content | qmd (BM25 + vector, local) |
Teams <5 brands, full auditability, zero ops overhead. Start here. |
| Mem0 (April 2026 algorithm) |
Vector + entity collection, multi-signal retrieval | No validity windows; entity deduplication only | Semantic + BM25 + entity fusion; 6,956 tokens / retrieval on LoCoMo | High-volume fact accumulation across many brands and platforms. +29.6 pts on temporal queries vs. prior algorithm (per Mem0, arXiv:2504.19413). |
| Zep / Graphiti | Bi-temporal knowledge graph (Neo4j / FalkorDB) | Full start/end validity bounds per fact — automatic invalidation | Semantic + BM25 + graph traversal hybrid | Brand facts with explicit expiry: pricing tiers, certifications, regulatory status, contract terms. Structural advantage wherever "as of" qualification matters (arXiv:2501.13956). |
| Cloudflare Agent Memory |
Edge-distributed; Durable Objects + Vectorize | Event timestamps; no bi-temporal model | Reciprocal Rank Fusion over 5 parallel channels | Multi-region deployments; teams needing sub-200ms retrieval at the edge. Private beta as of April 17, 2026. Five operations: ingest, remember, recall, list, forget. |
One architecture worth noting: LLM Wiki v2 (April 26, 2026, by rohitg00) adds a consolidation pipeline on top of the base pattern — staged promotion from a "candidates" buffer to the main wiki, confidence scoring per fact, and lifecycle governance across working, episodic, semantic, and procedural memory tiers. For production brand intelligence at scale, this is closer to the right architecture than the base gist.
The tiered memory structure within the wiki
The expo-llm-wiki community implementation (github.com/equationalapplications/expo-llm-wiki) introduced a three-tier naming that maps well to the brand monitoring use case:
Seven practical tips before you build
## [YYYY-MM-DD] ingest | Title format precisely because it is grep-able. In a brand monitoring wiki, the log is your evidence chain: when a negative sentiment shift appears in a Wisdom tier page, grep "competitor-x" log.md shows you every ingest event that touched it, with dates and source identifiers. This matters when a legal or communications team asks "when did we first detect this characterisation?" Log entries are append-only — never edit or backfill them.git log -p wiki/entities/brands/acme-corp.md shows you exactly when each claim was introduced and which source triggered it. This is the audit trail that a communications or legal team will ask for the first time something goes wrong — and having it ready changes the response from reactive to authoritative.- Karpathy, A. (April 4, 2026). "LLM Wiki." GitHub Gist, hash
ac46de1ad27f92b28ac95459c782c07f6b8c964a. Single revision. Retrieved May 2026. - rohitg00 (April 26, 2026). "LLM Wiki v2." GitHub Gist. Production-focused extension adding lifecycle management, confidence scoring, and consolidation tiers.
- Chhikara et al. (ECAI 2025). "Mem0: Building Production-Ready AI Agents with Scalable Long-Term Memory." arXiv:2504.19413. Baseline evaluation of Mem0 on LoCoMo (66.9%) vs. OpenAI memory (52.9%).
- Mem0 Engineering Team (April 1, 2026 / updated May 15, 2026). "State of AI Agent Memory 2026." mem0.ai/blog. April 2026 algorithm: single-pass hierarchical extraction + multi-signal retrieval. LoCoMo 91.6%, LongMemEval 93.4%. +29.6 pts on temporal queries, +23.1 pts on multi-hop vs. prior algorithm. Benchmark framework: github.com/mem0ai/memory-benchmarks.
- Maharana et al. (ACL 2024). LOCOMO benchmark. arXiv:2402.17753. Snap Research / UNC Chapel Hill. Reference benchmark for long conversational memory evaluation.
- Rasmussen, P., Paliychuk, P., Beauvais, T., Ryan, J., Chalef, D. (Zep AI, January 2025). "Zep: A Temporal Knowledge Graph Architecture for Agent Memory." arXiv:2501.13956. Graphiti: bi-temporal validity model, DMR benchmark 94.8%. Zep blog: "Is Mem0 Really SOTA in Agent Memory?" — Zep at 75.14% J-score vs. 65.99% reported in Mem0 paper. Note: methodological dispute unresolved; treat all vendor LOCOMO scores as directional.
- Cloudflare (April 17, 2026). "Cloudflare Agent Memory" — private beta announcement, Agents Week 2026. Technology: Durable Objects, Vectorize, Workers AI. Five operations: ingest, remember, recall, list, forget. Retrieval: Reciprocal Rank Fusion over five parallel channels.
- Anthropic (April 16, 2026). Claude Opus 4.7 release. 1M-token context window; $5 / 1M input tokens, $25 / 1M output tokens. Important: new tokenizer generates up to 35% more tokens for the same text (per Anthropic documentation). Source: platform.claude.com/docs.
- Manakul, P., Liusie, A. & Gales, M.J.F. (EMNLP 2023). "SelfCheckGPT: Zero-Resource Black-Box Hallucination Detection for Generative Large Language Models." arXiv:2303.08896. ALTA Institute, University of Cambridge. Five variants: BERTScore, MQAG, n-gram, NLI, LLM-Prompting.
- Farquhar, S., Kossen, J., Kuhn, L., Gal, Y. (June 2024). "Detecting hallucinations in large language models using semantic entropy." Nature 630(8017), 625–630. DOI: 10.1038/s41586-024-07421-0. OATML, University of Oxford. Semantic clustering of answer distributions for confabulation detection.
- expo-llm-wiki (github.com/equationalapplications/expo-llm-wiki). Three-tier architecture: Fact Tier (Immutable Truth), Working Memory Tier (recency-weighted), Wisdom Tier (accessCount-weighted). MIT licence. TypeScript/SQLite, MCP server included.
- Nayak, P. (Level Up Coding, April 2026). "Beyond RAG: How Andrej Karpathy's LLM Wiki Pattern Builds Knowledge That Actually Compounds." Implementation reference: RAG-on-top-of-wiki with
--savequery feedback loop. - qmd — github.com/tobi/qmd. Local hybrid BM25/vector + LLM re-ranking search over Markdown files. CLI and MCP server. Recommended by Karpathy in the original gist for Query operations.