<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Beever AI</title>
    <description>The latest articles on DEV Community by Beever AI (@beeverai).</description>
    <link>https://dev.to/beeverai</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3896513%2Fcd0981f2-139a-4b83-be53-fa2aa95a5faf.png</url>
      <title>DEV Community: Beever AI</title>
      <link>https://dev.to/beeverai</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/beeverai"/>
    <language>en</language>
    <item>
      <title>LLM Wiki vs RAG: a different approach to team-chat memory</title>
      <dc:creator>Beever AI</dc:creator>
      <pubDate>Fri, 24 Apr 2026 18:12:18 +0000</pubDate>
      <link>https://dev.to/beeverai/llm-wiki-vs-rag-a-different-approach-to-team-chat-memory-4m91</link>
      <guid>https://dev.to/beeverai/llm-wiki-vs-rag-a-different-approach-to-team-chat-memory-4m91</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkpo5xehuqn2ppdy2z798.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkpo5xehuqn2ppdy2z798.png" alt=" " width="800" height="454"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Retrieval-augmented generation became the reflex answer for &lt;em&gt;"my LLM needs to know about my data."&lt;/em&gt; Chunk it, embed it, retrieve top-k on query, stuff it in the prompt. It works so well on documents that engineers now apply it to everything — PDFs, wikis, code, support tickets, and, increasingly, team chat.&lt;/p&gt;

&lt;p&gt;RAG is the wrong tool for chat.&lt;/p&gt;

&lt;p&gt;At &lt;a href="https://beever.ai" rel="noopener noreferrer"&gt;Beever AI&lt;/a&gt; we spent the last months building an alternative and just released it as open source. &lt;a href="https://github.com/Beever-AI/beever-atlas" rel="noopener noreferrer"&gt;Beever Atlas&lt;/a&gt; is an &lt;strong&gt;LLM Wiki&lt;/strong&gt; — not a RAG system — that ingests Slack, Discord, Microsoft Teams, Mattermost, and Telegram conversations into a structured, browsable, auto-maintained wiki and knowledge graph. This post explains what an LLM Wiki is, what it can answer that RAG cannot, and the design decisions behind our implementation.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is an LLM Wiki?
&lt;/h2&gt;

&lt;p&gt;An LLM Wiki is a structured, LLM-maintained knowledge artefact derived from a conversational corpus. It is &lt;em&gt;not&lt;/em&gt; a retrieval preprocessing step. It is the artefact itself — browsable by humans, queryable by agents, versioned, and cited back to its sources.&lt;/p&gt;

&lt;p&gt;Seven differences worth naming:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Primary output.&lt;/strong&gt; RAG surfaces prompt-time retrieval results. An LLM Wiki produces a standing artefact (the wiki and the knowledge graph).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;What breaks when retrieval breaks.&lt;/strong&gt; RAG hallucinates. An LLM Wiki is still readable as-is.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Consumed by.&lt;/strong&gt; RAG: LLMs, mostly. LLM Wiki: humans &lt;em&gt;and&lt;/em&gt; LLMs both.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Freshness cost.&lt;/strong&gt; RAG re-indexes on every write. An LLM Wiki re-consolidates affected topics only.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Dedup.&lt;/strong&gt; RAG does it per-query, ranking-dependent. An LLM Wiki does it at extraction time, structurally.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Citations.&lt;/strong&gt; RAG reconciles sources post-hoc and can drift. An LLM Wiki carries citations forward from extraction.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Multi-hop questions.&lt;/strong&gt; RAG is poor at them. An LLM Wiki makes them first-class via the graph.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Karpathy outlined the idea in a widely-shared thread earlier this year. We took it seriously and built a production implementation.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why RAG falls down on conversations
&lt;/h2&gt;

&lt;p&gt;Chat isn't documents. Four specific failure modes:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Same fact, said dozens of times.&lt;/strong&gt; Someone announces &lt;em&gt;"we're moving to Postgres on March 15"&lt;/em&gt; in &lt;code&gt;#engineering&lt;/code&gt;. Twelve people ack. Four people quote it in later threads. Three retrospectives cite it. The same fact now exists as 20+ near-duplicate chunks. Chunk-based retrieval surfaces one somewhat arbitrarily, or several near-duplicates that crowd out unrelated relevant context.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Time-ordered, not topic-grouped.&lt;/strong&gt; In a document, related content sits adjacent. In chat, a feature decision, a bug report, and a lunch plan can be interleaved across five minutes.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Structure lives outside the text.&lt;/strong&gt; Meaningful metadata is not in the message body: author, thread parent, reactions, platform, mentions, attachments. Embedding the body only throws away half the signal.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Answer instability.&lt;/strong&gt; Ask the same question a week apart. Different chunks rank highest depending on recent message volume and minor embedding perturbations. You get subtly different answers — corrosive to user trust.&lt;/p&gt;

&lt;h2&gt;
  
  
  What an LLM Wiki can answer that RAG can't
&lt;/h2&gt;

&lt;p&gt;This is the part of the design that most people miss when they first see the architecture. A good vector retriever can handle &lt;em&gt;"what did we decide about onboarding?"&lt;/em&gt; just fine. The capabilities that separate an LLM Wiki from RAG show up when the question is &lt;strong&gt;relational, temporal, or multi-hop&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;em&gt;"Who decided we're moving to Postgres, and did anything supersede that decision?"&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;"Which projects does the billing service block, and who owns them?"&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;"Show me every decision Alan announced in Q1 that was later reversed."&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;"Which technologies are members of team A working with that are still flagged experimental?"&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;"What got decided in threads that mention the SOC2 audit?"&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Each of these requires walking a relationship — decision supersession, team membership, thread mentions, status attributes — that chunk-based retrieval fundamentally can't express. In Beever Atlas the knowledge graph in Neo4j holds those relationships. The Cypher traversal used in the codebase for decision-chain queries looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cypher"&gt;&lt;code&gt;&lt;span class="k"&gt;MATCH&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="py"&gt;d:&lt;/span&gt;&lt;span class="n"&gt;Entity&lt;/span&gt; &lt;span class="ss"&gt;{&lt;/span&gt;&lt;span class="py"&gt;type:&lt;/span&gt; &lt;span class="s1"&gt;'Decision'&lt;/span&gt;&lt;span class="ss"&gt;})&lt;/span&gt;
&lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;d.channel_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;$channel_id&lt;/span&gt;
   &lt;span class="ow"&gt;OR&lt;/span&gt; &lt;span class="ow"&gt;EXISTS&lt;/span&gt; &lt;span class="ss"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;MATCH&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="ss"&gt;[&lt;/span&gt;&lt;span class="nc"&gt;:MENTIONED_IN&lt;/span&gt;&lt;span class="ss"&gt;]&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="py"&gt;ev:&lt;/span&gt;&lt;span class="n"&gt;Event&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;ev.channel_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;$channel_id&lt;/span&gt;
      &lt;span class="ss"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;OPTIONAL&lt;/span&gt; &lt;span class="k"&gt;MATCH&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="py"&gt;person:&lt;/span&gt;&lt;span class="n"&gt;Entity&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="ss"&gt;[&lt;/span&gt;&lt;span class="nc"&gt;:DECIDED&lt;/span&gt;&lt;span class="ss"&gt;]&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;OPTIONAL&lt;/span&gt; &lt;span class="k"&gt;MATCH&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="ss"&gt;[&lt;/span&gt;&lt;span class="nc"&gt;:SUPERSEDES&lt;/span&gt;&lt;span class="ss"&gt;]&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="py"&gt;old:&lt;/span&gt;&lt;span class="n"&gt;Entity&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;OPTIONAL&lt;/span&gt; &lt;span class="k"&gt;MATCH&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="py"&gt;newer:&lt;/span&gt;&lt;span class="n"&gt;Entity&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="ss"&gt;[&lt;/span&gt;&lt;span class="nc"&gt;:SUPERSEDES&lt;/span&gt;&lt;span class="ss"&gt;]&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;WITH&lt;/span&gt; &lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="ss"&gt;,&lt;/span&gt;
     &lt;span class="nf"&gt;collect&lt;/span&gt;&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="k"&gt;DISTINCT&lt;/span&gt; &lt;span class="n"&gt;person.name&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="n"&gt;decided_by&lt;/span&gt;&lt;span class="ss"&gt;,&lt;/span&gt;
     &lt;span class="nf"&gt;collect&lt;/span&gt;&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="k"&gt;DISTINCT&lt;/span&gt; &lt;span class="n"&gt;old.name&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt;    &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="n"&gt;supersedes&lt;/span&gt;&lt;span class="ss"&gt;,&lt;/span&gt;
     &lt;span class="nf"&gt;collect&lt;/span&gt;&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="k"&gt;DISTINCT&lt;/span&gt; &lt;span class="n"&gt;newer.name&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt;  &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="n"&gt;superseded_by&lt;/span&gt;
&lt;span class="k"&gt;RETURN&lt;/span&gt; &lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="ss"&gt;,&lt;/span&gt; &lt;span class="n"&gt;decided_by&lt;/span&gt;&lt;span class="ss"&gt;,&lt;/span&gt; &lt;span class="n"&gt;supersedes&lt;/span&gt;&lt;span class="ss"&gt;,&lt;/span&gt; &lt;span class="n"&gt;superseded_by&lt;/span&gt;
&lt;span class="k"&gt;LIMIT&lt;/span&gt; &lt;span class="n"&gt;$limit&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is the kind of query a Q&amp;amp;A agent's router hands off to the graph path when a question's shape demands it.&lt;/p&gt;

&lt;h2&gt;
  
  
  The shape of a fact and an entity
&lt;/h2&gt;

&lt;p&gt;Before showing the pipeline, the data shapes that hold everything together:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Atomic fact&lt;/strong&gt; — a single self-contained claim with a source message, author, timestamp, and thread context:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"text"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"The team is migrating from MySQL to Postgres on March 15"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"source_message_id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"slack:C08TX:1712500000001100"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"author"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"alan5543"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"timestamp"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2026-03-01T14:22:00Z"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"thread_parent"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"entities"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"MySQL"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Technology"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Postgres"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Technology"&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"relationships"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"source"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Team"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"target"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Postgres"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"MIGRATING_TO"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"confidence"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0.92&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"valid_from"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2026-03-01T14:22:00Z"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"valid_until"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"source_message_id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"slack:C08TX:1712500000001100"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Two details to flag:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Every relationship has temporal props&lt;/strong&gt; — &lt;code&gt;confidence&lt;/code&gt;, &lt;code&gt;valid_from&lt;/code&gt;, &lt;code&gt;valid_until&lt;/code&gt;, &lt;code&gt;source_message_id&lt;/code&gt;. This is how we answer &lt;em&gt;"as of when"&lt;/em&gt; questions and how later decisions supersede earlier ones without destroying history.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Entity scope&lt;/strong&gt; — some entity types (Person, Technology, Project, Team) merge globally across channels. Others (Decision, Meeting, Artifact) merge only within a channel scope. Scope-aware MERGE prevents two different channels' "Q1 planning decisions" from collapsing into each other, while still letting "Alan" mean the same person everywhere.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;String-level dedup is done with Jaro-Winkler similarity (via APOC) inside the scope; semantic dedup is done with embedding cosine on &lt;code&gt;Entity.name_vector&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  How the wiki gets built — six ADK stages
&lt;/h2&gt;

&lt;p&gt;Ingestion runs as a pipeline of Google ADK &lt;code&gt;LlmAgent&lt;/code&gt; steps, using Gemini 2.5 Flash for extraction. Six stages:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Preprocessor&lt;/strong&gt; — normalises platform-specific message shapes into a single &lt;code&gt;NormalizedMessage&lt;/code&gt; with author, timestamp, thread context, attachments, platform metadata.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Fact Extractor&lt;/strong&gt; — pulls atomic facts with channel + author + timestamp attached. Bounded output via &lt;code&gt;MAX_FACTS_PER_MESSAGE&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Entity Extractor&lt;/strong&gt; — LLM-driven with a flexible type schema (Person / Decision / Project / Technology / Team / Meeting / Artifact / …). Type vocabulary isn't frozen; new types can be added without a migration.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cross-batch Validator&lt;/strong&gt; — dedupes entities and relationships across batch boundaries. This is where scope-aware MERGE and Jaro-Winkler similarity live.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Relationship Graph&lt;/strong&gt; — materialises bidirectional relationships (&lt;code&gt;DECIDED ↔ DECIDED_BY&lt;/code&gt;, &lt;code&gt;BLOCKED_BY ↔ BLOCKS&lt;/code&gt;, and so on) with the temporal props above.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Persister&lt;/strong&gt; — transactional-outbox write to Weaviate + Neo4j + MongoDB, with media attribution preserved. The outbox pattern means a partial failure doesn't leave the stores inconsistent.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Periodically, a separate &lt;strong&gt;consolidation agent&lt;/strong&gt; clusters related facts and synthesises them into topic pages — the "wiki" users browse in the dashboard. Consolidation is idempotent and checkpointed: you re-run it on a subset without rebuilding from scratch.&lt;/p&gt;

&lt;h2&gt;
  
  
  Dual memory: why Weaviate &lt;em&gt;and&lt;/em&gt; Neo4j
&lt;/h2&gt;

&lt;p&gt;Facts live in two stores because no single store wins both query shapes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Weaviate&lt;/strong&gt; — 3-tier semantic memory (channel-level summaries, topic-level synopses, fact-level detail). Hybrid BM25 + vector retrieval. Good for &lt;em&gt;"what did we decide about X?"&lt;/em&gt; — any question whose answer is a semantic lookup over fact text.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Neo4j&lt;/strong&gt; — entities, decisions, episodic links, media attributions. Good for &lt;em&gt;"who decided this and why?"&lt;/em&gt; — any question that requires walking a relationship.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A &lt;strong&gt;query router&lt;/strong&gt; picks semantic, graph, or both per question. The router is a small LLM classifier, not a rule engine. Rule engines fail on novel phrasings; a classifier trades a few milliseconds of routing latency for resilience to queries we haven't seen before.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;flowchart LR
    Q[Question] --&amp;gt; R[Query Router&amp;lt;br/&amp;gt;LLM classifier]
    R --&amp;gt;|semantic| W[Weaviate&amp;lt;br/&amp;gt;channel / topic / fact]
    R --&amp;gt;|graph| N[Neo4j&amp;lt;br/&amp;gt;entity + rel traversal]
    R --&amp;gt;|both| W
    R --&amp;gt;|both| N
    W --&amp;gt; M[Merge + dedup by fact_id]
    N --&amp;gt; M
    M --&amp;gt; A[Answer agent&amp;lt;br/&amp;gt;ADK SkillToolset]
    A --&amp;gt; S[SSE stream&amp;lt;br/&amp;gt;response + citations]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;MongoDB holds the wiki page cache, ingestion state, and the transactional outbox. Redis holds sessions. Nothing interesting happens in either — they're operational plumbing.&lt;/p&gt;

&lt;h2&gt;
  
  
  The MCP surface: same memory, two audiences
&lt;/h2&gt;

&lt;p&gt;The dashboard is one surface. The &lt;strong&gt;MCP (Model Context Protocol) server&lt;/strong&gt; is the other. Sixteen tools are exposed to external agents like Claude Code, Cursor, or any MCP-capable client:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;search_by_topic&lt;/code&gt;, &lt;code&gt;search_channel_facts&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;get_decision_timeline&lt;/code&gt;, &lt;code&gt;find_supersessions&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;graph_traverse&lt;/code&gt;, &lt;code&gt;resolve_entity&lt;/code&gt;, &lt;code&gt;find_mentions&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;list_channels&lt;/code&gt;, &lt;code&gt;read_wiki_section&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;…and more for ingestion status, media lookup, and policy.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The meaningful shift here is that the team memory becomes &lt;strong&gt;reusable context&lt;/strong&gt;, not a siloed app. An IDE-resident coding agent can ask &lt;em&gt;"what did the team decide about the auth library?"&lt;/em&gt; with the same guarantees the dashboard gives a human — citations back to source messages, scope-aware resolution, permission-aware access (roadmap, below).&lt;/p&gt;

&lt;h2&gt;
  
  
  What this costs
&lt;/h2&gt;

&lt;p&gt;Honest accounting: ingestion is slower and more expensive than RAG. You pay the LLM twice — once for extraction, once for consolidation. Using Gemini Flash keeps both bounded. Consolidation runs sparsely (once per topic cluster) and amortises across many messages.&lt;/p&gt;

&lt;p&gt;The tradeoff is explicit: &lt;strong&gt;you pay more ingestion cost to get a standing artefact instead of ephemeral retrieval results.&lt;/strong&gt; For team-chat corpora with heavy repetition, high conversational noise, and relational/temporal queries, an LLM Wiki reliably wins on answer quality, citation fidelity, browsability, and the types of question it can even entertain. For already-structured documents, classic RAG is still the right tool.&lt;/p&gt;

&lt;h2&gt;
  
  
  A concrete query path
&lt;/h2&gt;

&lt;p&gt;Someone asks &lt;em&gt;"who decided we're moving to Postgres, and has anything superseded that decision?"&lt;/em&gt;:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The router classifies this as &lt;strong&gt;both&lt;/strong&gt; — it needs fact retrieval &lt;em&gt;and&lt;/em&gt; graph traversal, since there's a decider and a supersession chain.&lt;/li&gt;
&lt;li&gt;Weaviate retrieves the top facts about Postgres migration from the fact tier.&lt;/li&gt;
&lt;li&gt;Neo4j runs the decision-chain traversal shown earlier, returning &lt;code&gt;decided_by&lt;/code&gt;, &lt;code&gt;supersedes&lt;/code&gt;, and &lt;code&gt;superseded_by&lt;/code&gt; collections.&lt;/li&gt;
&lt;li&gt;Results merge, dedup by &lt;code&gt;fact_id&lt;/code&gt;, and pass to the answer agent.&lt;/li&gt;
&lt;li&gt;The agent streams back via SSE:&lt;/li&gt;
&lt;/ol&gt;

&lt;blockquote&gt;
&lt;p&gt;Alan announced the migration from MySQL to Postgres on March 1, 2026 [1], with cutover scheduled for March 15 [1]. The decision was ratified in the March 3 engineering sync [2] and has not been superseded since.&lt;/p&gt;

&lt;p&gt;[1] alan5543 in #engineering, 2026-03-01 14:22&lt;br&gt;
[2] alan5543 in #engineering-sync, 2026-03-03 10:00&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The citations come straight from the fact records surfaced in steps 2 and 3. There's no separate "find the source" step that can drift from what the agent actually retrieved.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where we sit, and what's defensible
&lt;/h2&gt;

&lt;p&gt;Most team-memory products are &lt;strong&gt;vector-only&lt;/strong&gt; — Glean, Notion AI, various OSS "LLM wiki" clones built on a single embedding store. Beever Atlas is the first OSS product we're aware of putting a real knowledge graph under team-chat memory.&lt;/p&gt;

&lt;p&gt;The graph isn't cosmetic. It's load-bearing for a specific class of query — multi-hop, temporal, scope-aware — that vector retrieval fundamentally can't serve. It's also the substrate on which a &lt;strong&gt;permission spine&lt;/strong&gt; can be built: mirroring Slack Enterprise Grid ACLs as graph-level access rules means permissions get enforced at query time, not papered over with app-tier filters. That's on our roadmap and we think it's the right shape for enterprise deployment.&lt;/p&gt;

&lt;h2&gt;
  
  
  The rest of the stack
&lt;/h2&gt;

&lt;p&gt;The full system runs locally via &lt;code&gt;docker compose&lt;/code&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Python backend — FastAPI + Google ADK agents&lt;/li&gt;
&lt;li&gt;TypeScript bot bridge — Slack / Discord / Teams / Mattermost / Telegram webhooks with platform-specific signature verification&lt;/li&gt;
&lt;li&gt;React dashboard — wiki view, interactive Cytoscape knowledge graph, streaming Q&amp;amp;A with live citations&lt;/li&gt;
&lt;li&gt;Weaviate, Neo4j, MongoDB, Redis&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Platform credentials (bot tokens) are encrypted at rest with AES-256-GCM. All data stays in databases you control. The app sends no telemetry anywhere — LLM calls go through API keys you configure in your own &lt;code&gt;.env&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Try it
&lt;/h2&gt;

&lt;p&gt;A &lt;code&gt;make demo&lt;/code&gt; target brings up the full stack pre-loaded with a public Wikipedia corpus (Ada Lovelace + Python history, CC-BY-SA 3.0). Pre-computed fixtures ship in the repo, so seeding runs without any API keys. Asking questions via the Q&amp;amp;A agent needs a free-tier Gemini API key — Ollama support for fully-local inference is on the roadmap.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone https://github.com/Beever-AI/beever-atlas
&lt;span class="nb"&gt;cd &lt;/span&gt;beever-atlas
make demo
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-X&lt;/span&gt; POST http://localhost:8000/api/channels/demo-wikipedia/ask &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Authorization: Bearer dev-key-change-me"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Content-Type: application/json"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;'{"question":"Who was Ada Lovelace?"}'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You'll see a streaming SSE response with six citations linking back to the source Wikipedia articles.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Links&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Repository: &lt;a href="https://github.com/Beever-AI/beever-atlas" rel="noopener noreferrer"&gt;github.com/Beever-AI/beever-atlas&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Documentation: &lt;a href="https://docs.beever.ai/atlas" rel="noopener noreferrer"&gt;docs.beever.ai/atlas&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Demo video: &lt;a href="https://youtu.be/VJ81Uxyjxb0" rel="noopener noreferrer"&gt;youtu.be/VJ81Uxyjxb0&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Beever Atlas is developed by Beever AI Limited in Toronto, Ontario, and released under the Apache 2.0 license. The LLM Wiki concept was inspired by Andrej Karpathy's earlier-2026 thread on LLM Knowledge Bases; we took the idea seriously and built the implementation.&lt;/p&gt;

&lt;p&gt;Contributions welcome. Issues especially — we want to hear the edge cases where a vector-only system would have worked and our graph overhead turned out not to pay for itself.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>llm</category>
      <category>rag</category>
      <category>llmwiki</category>
    </item>
  </channel>
</rss>
