<?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: kgaidev</title>
    <description>The latest articles on DEV Community by kgaidev (@kgaidev).</description>
    <link>https://dev.to/kgaidev</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.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4033763%2F00179adc-fab9-4243-9857-f17ac2ae902d.png</url>
      <title>DEV Community: kgaidev</title>
      <link>https://dev.to/kgaidev</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/kgaidev"/>
    <language>en</language>
    <item>
      <title>How to actually share Claude Code memory with your team</title>
      <dc:creator>kgaidev</dc:creator>
      <pubDate>Wed, 19 Aug 2026 01:16:19 +0000</pubDate>
      <link>https://dev.to/kgaidev/how-to-actually-share-claude-code-memory-with-your-team-4d2k</link>
      <guid>https://dev.to/kgaidev/how-to-actually-share-claude-code-memory-with-your-team-4d2k</guid>
      <description>&lt;p&gt;Every developer on your team runs Claude Code against the same codebase. And every one of those agents learns the same lessons separately. Alice's agent works out why the payments module talks to the ledger the way it does. Bob's agent, one desk over, rediscovers it next week from scratch. Nothing compounds.&lt;/p&gt;

&lt;p&gt;We build kgai, a decision-memory plugin for Claude Code, so read this knowing where we stand. But most of what follows is about the problem, because the problem is worth understanding even if you never touch our tool.&lt;/p&gt;

&lt;h2&gt;
  
  
  The CLAUDE.md trap
&lt;/h2&gt;

&lt;p&gt;Search "share Claude Code memory with your team" and the answer you'll mostly find is commit your CLAUDE.md to git. That advice is genuinely right, for part of the job. CLAUDE.md is loaded into every session, git distributes it to everyone, done.&lt;/p&gt;

&lt;p&gt;So teams start stuffing it with everything. Coding standards, sure. But then also why you picked Postgres over DynamoDB, why the retry logic looks weird, why the queue-based import got abandoned in March. It feels like memory. For a few weeks it even works.&lt;/p&gt;

&lt;p&gt;Then three things happen.&lt;/p&gt;

&lt;p&gt;The file bloats. CLAUDE.md goes into the context of every single session, whole. Every decision you add is a tax on every future conversation, including the 95 percent of conversations that decision is irrelevant to. So people start trimming.&lt;/p&gt;

&lt;p&gt;It goes stale. Nobody deletes from a shared instructions file with confidence, because nobody's sure who still depends on which line. Decisions that were reversed months ago sit next to current ones with no marker saying which is which.&lt;/p&gt;

&lt;p&gt;And it merge-conflicts, because it's one file with the whole team appending to it, plus agents that helpfully edit it mid-session. You end up resolving conflicts in prose, which git is bad at and humans hate.&lt;/p&gt;

&lt;p&gt;None of this means CLAUDE.md is bad. It means it's being asked to do a second job it's the wrong shape for.&lt;/p&gt;

&lt;h2&gt;
  
  
  Policy is not history
&lt;/h2&gt;

&lt;p&gt;CLAUDE.md is policy. Rules you want enforced right now, in every session. Use pnpm. Don't touch the generated files. Run the linter before committing. Policy should be small, current, and hand-curated, and a file in git is exactly the right shape for it.&lt;/p&gt;

&lt;p&gt;Decision history works the other way round. It only grows, most of it is irrelevant to any given task, and its value shows up at retrieval time. You don't want 400 past decisions sitting in your context window. You want the three that touch the module the agent is about to change, surfaced right before it changes it.&lt;/p&gt;

&lt;p&gt;Policy gets enforced, decisions get retrieved. Every attempt to make one file do both turns your instructions file into a landfill.&lt;/p&gt;

&lt;p&gt;So keep your CLAUDE.md. Make it shorter. Put the history somewhere built for history.&lt;/p&gt;

&lt;h2&gt;
  
  
  What team decision memory actually needs
&lt;/h2&gt;

&lt;p&gt;Write down the requirements and the list is short.&lt;/p&gt;

&lt;p&gt;Append-only records. When a decision gets reversed, the old one shouldn't be edited or deleted. The new one should supersede it by an explicit link, and the old one stays, with the reason it died. "We tried X and it cost us a day" is worth more than X quietly missing.&lt;/p&gt;

&lt;p&gt;Recall that knows what's in force. History is kept, but by default the agent should only see decisions that currently apply. Superseded ones surface when you're auditing why direction changed, not when the agent is writing code.&lt;/p&gt;

&lt;p&gt;Retrieval by area, not wholesale loading. Ask about the invoice module, get the decisions that shape the invoice module.&lt;/p&gt;

&lt;p&gt;Sync that can't merge-conflict. This one is non-negotiable for teams. Multiple people record decisions in parallel, and increasingly their agents do it for them, mid-session, without asking. Any design where two writers can collide on the same file will collide daily.&lt;/p&gt;

&lt;h2&gt;
  
  
  The gap is real, and it's on the public record
&lt;/h2&gt;

&lt;p&gt;claude-mem is the best-known memory plugin for Claude Code, and it's good at what it does. Its memory lives in a local SQLite file on each machine. Team sharing keeps coming back in its tracker. Issue &lt;a href="https://github.com/thedotmack/claude-mem/issues/2420" rel="noopener noreferrer"&gt;#2420&lt;/a&gt; asks for a pluggable MySQL backend for team-shared memory, &lt;a href="https://github.com/thedotmack/claude-mem/issues/1415" rel="noopener noreferrer"&gt;#1415&lt;/a&gt; asks for Postgres, &lt;a href="https://github.com/thedotmack/claude-mem/issues/1981" rel="noopener noreferrer"&gt;#1981&lt;/a&gt; asks for Turso. The author of #2420 put the pain plainly. Every engineer starts from scratch, and the "collective memory never compounds across the team."&lt;/p&gt;

&lt;p&gt;All three were closed without the feature shipping, one of them explicitly as not planned.&lt;/p&gt;

&lt;p&gt;There is a paid cloud sync now, and it's worth being precise about it: per its docs it replicates your memory across your own devices through a per-user sync hub. Multi-device, not multi-person. That's not a knock on the maintainers. Single-user memory is their core product, and multi-writer sync is a genuinely different problem, closer to distributed systems than to prompt engineering. But if you came in with the team use case, claude-mem itself still doesn't ship it. What does exist is a third-party project, &lt;a href="https://github.com/lopadova/claude-mem-sync" rel="noopener noreferrer"&gt;claude-mem-sync&lt;/a&gt;, which adds team sharing on top with a Claude Code plugin and a GitHub Action, and the fact that the community is building this themselves tells you the demand is real.&lt;/p&gt;

&lt;p&gt;The general-purpose memory layers (mem0, Graphiti, Cognee) can be bent toward it. You'll be running shared infrastructure and building the decision model yourself, though. We wrote up that landscape honestly in &lt;a href="https://dev.to/kgaidev/why-mem0-graphiti-and-cognee-dont-quite-solve-shared-decision-memory-for-claude-code-3g7g"&gt;a separate article&lt;/a&gt;, including what those tools are better at than we are.&lt;/p&gt;

&lt;h2&gt;
  
  
  How we approached it
&lt;/h2&gt;

&lt;p&gt;kgai starts from the requirements list above and works backward.&lt;/p&gt;

&lt;p&gt;A decision is an immutable, content-addressed event in an append-only log, carrying what changed, why, and what was rejected. Capture is automatic. While you work, the plugin records structural decisions on its own, and a hook catches the case where the model edits code but forgets to record. Trivial edits record nothing, so the graph stays signal instead of noise.&lt;/p&gt;

&lt;p&gt;The sync design is the part that answers the team question. Every writer gets their own shard of the log, and sync pushes write-once objects to an S3 bucket you own. One writer per file means two teammates, or ten agents, recording in parallel can never produce a textual conflict. There's nothing to merge, ever. Each machine replays the shared log into the same graph, deterministically, and you can verify that with &lt;code&gt;kg export --canonical&lt;/code&gt; on two machines and compare digests. Sync also runs on its own in the background, so nobody has to remember to push what they recorded.&lt;/p&gt;

&lt;p&gt;Genuinely contradictory decisions, where two people decided the same thing two different ways, don't get silently last-writer-won. They surface as a branch via &lt;code&gt;kg conflicts&lt;/code&gt;, you resolve it by recording one decision that supersedes both, and the branch and its resolution stay in history.&lt;/p&gt;

&lt;p&gt;Sync is opt-in and the bucket is yours. Any S3-compatible store works, including MinIO and R2. There's no server of ours in the path and your code never leaves your machines. On the numbers side, we've measured a store of 1,000,000 decisions across 30 writers' shards, and a decision lookup still answers in about 100 ms. That figure is for the decision lookup specifically. Recall and free-text search are slower.&lt;/p&gt;

&lt;h2&gt;
  
  
  What kgai doesn't do
&lt;/h2&gt;

&lt;p&gt;Git remotes are implemented but experimental. They haven't been through the same testing as S3, so S3 is the path we'd actually recommend to a team today.&lt;/p&gt;

&lt;p&gt;Search is lexical. There are no embeddings and no vector index, which keeps the install at zero infrastructure, but it also means phrasing matters more than it would with semantic search. A contextual-search index for large stores is on the roadmap, not shipped.&lt;/p&gt;

&lt;p&gt;It's not general agent memory. Preferences, conversation history, arbitrary facts about a user, none of that. The tools in the article linked above do that better, and we'd point you at them for it.&lt;/p&gt;

&lt;p&gt;And it's a Claude Code plugin today. An MCP endpoint for other agents is roadmap, not product.&lt;/p&gt;

&lt;h2&gt;
  
  
  Trying it
&lt;/h2&gt;

&lt;p&gt;Two commands to install.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;claude plugin marketplace add kgaidev/kgai
claude plugin &lt;span class="nb"&gt;install &lt;/span&gt;kgai@kgai-marketplace
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It runs local-first from that point, no account, no server. When you want the team on one memory, point a project at a bucket you own.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kg init &lt;span class="nt"&gt;--remote&lt;/span&gt; s3://your-bucket/team-kg
kg &lt;span class="nb"&gt;sync&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can also set one global default remote with &lt;code&gt;kg remote --global&lt;/code&gt;, so new projects sync without per-project setup.&lt;/p&gt;

&lt;p&gt;If you skip the tool entirely, this is the part that still holds. Your CLAUDE.md is policy, and it's good at that. Team memory is a retrieval problem over an append-only history, and no amount of markdown discipline turns one into the other.&lt;/p&gt;

&lt;p&gt;kgai is MIT licensed and the code is at &lt;a href="https://github.com/kgaidev/kgai" rel="noopener noreferrer"&gt;github.com/kgaidev/kgai&lt;/a&gt;. Docs, the benchmark, and what still doesn't work well are on &lt;a href="https://kgai.dev/?ref=devto-team-memory" rel="noopener noreferrer"&gt;kgai.dev&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>claude</category>
      <category>devtools</category>
      <category>productivity</category>
    </item>
    <item>
      <title>Why mem0, Graphiti and Cognee don't quite solve shared decision memory for Claude Code</title>
      <dc:creator>kgaidev</dc:creator>
      <pubDate>Thu, 30 Jul 2026 17:49:49 +0000</pubDate>
      <link>https://dev.to/kgaidev/why-mem0-graphiti-and-cognee-dont-quite-solve-shared-decision-memory-for-claude-code-3g7g</link>
      <guid>https://dev.to/kgaidev/why-mem0-graphiti-and-cognee-dont-quite-solve-shared-decision-memory-for-claude-code-3g7g</guid>
      <description>&lt;p&gt;You are three months into a codebase with Claude Code. You ask it to add search. It suggests Elasticsearch. Your team evaluated Elasticsearch in the spring, rejected it on cost, and moved on. Nothing in the repo says so, the person who made that call is on another team now, and the agent has no way to know. So you relitigate it, again.&lt;/p&gt;

&lt;p&gt;This is the part of AI-assisted development that nobody's tooling is quite solving. The agent writes code fluently. What it cannot do is remember why your code is the way it is, what your team already tried, and what got ruled out. That knowledge lives in people's heads and dead chat threads, and every new session starts from zero.&lt;/p&gt;

&lt;p&gt;The obvious move is to bolt on a memory layer. There are good ones. mem0, Graphiti and Cognee are the three you will run into first. They are all worth knowing. But if what you actually want is a shared record of your team's decisions wired into your coding agent, each of them solves a related problem, not that one, and getting them to do your job means taking on their complexity. Here is the honest version of why.&lt;/p&gt;

&lt;h2&gt;
  
  
  What these tools are built for
&lt;/h2&gt;

&lt;p&gt;All three are memory layers for agents and applications. Their job is to remember facts about a user or an agent, and to track how those facts change over time. That is a real and hard problem, and they are good at it. It is just a different problem from recording the decisions a team makes while building software.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;mem0&lt;/strong&gt; is the easiest to reach for. It is a vector-first memory layer, Apache-2.0, with a hosted platform and a clean Claude Code integration over MCP that captures and recalls automatically. The catch for our use case is what it stores and how. It distills text into user-scoped facts, and when a new fact contradicts an old one it reconciles them by updating or removing the old fact. For personalization that is exactly right. For decision history it is the wrong shape, because the thing you most want to keep, the reason approach A was rejected, is the thing that gets overwritten.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Graphiti&lt;/strong&gt;, from the team behind Zep, is the richest of the three and the closest in spirit to what decision memory needs. It is a graph-first framework that builds a temporal knowledge graph. When new information contradicts an old fact it does not delete the old edge, it marks it invalid and keeps the time boundaries, so you can ask what was true then and what is true now. It also lets you define your own entity and edge types. That temporal, non-destructive model is genuinely the right primitive. The cost is operational. You run a graph database (Neo4j, FalkorDB or Neptune), an LLM and an embedding pipeline, and you ingest data as structured episodes. It is powerful, and it is a lot to stand up and keep running.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Cognee&lt;/strong&gt; sits in between. It is an open-source memory engine, Apache-2.0, that turns data into a knowledge graph and can run anywhere from a single Postgres instance to a full graph-plus-vector stack. It has a Claude Code plugin and supports custom ontologies. What it does not have is built-in versioning or supersession of facts, so the part where a decision replaces an earlier one, with the earlier one preserved, is something you would build yourself.&lt;/p&gt;

&lt;h2&gt;
  
  
  The two gaps for team decision knowledge
&lt;/h2&gt;

&lt;p&gt;Strip away the differences and the same two gaps show up in all three.&lt;/p&gt;

&lt;p&gt;The first is semantic. None of them models a decision as a first-class thing. There is no built-in notion of a decision, its rationale, the alternatives that were considered and rejected, or a link from a new decision to the one it supersedes. You can approximate some of this by defining a custom ontology, most cleanly in Graphiti, but you are building the model, not using one.&lt;/p&gt;

&lt;p&gt;The second is operational. These are memory layers for facts, and to make one serve a whole team you have to run a shared, multi-author backend that everyone reads and writes, with some notion of review. That means a vector store, or a graph database, or both, plus an LLM doing extraction on every write, plus the service that fronts it. For a team that wanted its decisions to stop getting relitigated, that is a real infrastructure project before the first decision is even recorded.&lt;/p&gt;

&lt;p&gt;None of this is a knock on the tools. It is what happens when you use a general memory layer for a specific job it was not designed for.&lt;/p&gt;

&lt;h2&gt;
  
  
  What decision memory actually needs
&lt;/h2&gt;

&lt;p&gt;Write down what the coding-team use case really requires and the list is short and specific:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A decision as an immutable record, not a fact that gets edited in place&lt;/li&gt;
&lt;li&gt;The rationale attached to it, so the why survives the person who made the call&lt;/li&gt;
&lt;li&gt;Supersession as a first-class link, so a reversal keeps the old decision and the reason it died&lt;/li&gt;
&lt;li&gt;Rejected approaches and dead ends kept on purpose, because "we tried X, it cost us a day, here is why we stopped" is worth more than X quietly missing&lt;/li&gt;
&lt;li&gt;A shared store the whole team and their agents read and write&lt;/li&gt;
&lt;li&gt;All of it inside the coding loop, recalled before the agent touches an area and captured as decisions are made&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That is a narrower target than "remember everything about the user," and narrowing it is what lets you skip most of the machinery.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where kgai is different
&lt;/h2&gt;

&lt;p&gt;We build kgai, so treat this as the interested party's account, but the design follows directly from that list.&lt;/p&gt;

&lt;p&gt;kgai is not a general memory layer, and that is the point. It records one thing, the structural decisions your team makes while coding, as an immutable graph. Every decision carries its rationale. When a decision is reversed the new one supersedes the old one by an explicit link, and the old one stays in history with the reason it died. Dead ends are kept on purpose. Recall returns only the decisions that are currently in force, so the agent reads the current picture before it changes code, and the superseded ones stay available when you are auditing why direction changed. The first issue ever filed on our own repo was that recall was handing back superseded decisions, which taught us the hard way that keeping dead ends and serving them are two separate problems.&lt;/p&gt;

&lt;p&gt;The operational story is the part that differs most from the tools above. kgai is local-first. The store lives inside your project directory. There is no vector database, no graph server, no embedding pipeline, and no service to operate. It installs as a Claude Code plugin in two commands. Capture happens in the session and a hook at the end of the turn catches anything the model forgot to record. The graph is rebuilt deterministically from the log, so the same decisions produce the same graph on every teammate's machine. Team sync is opt-in, over an S3 bucket you own, and it is conflict-aware rather than last-writer-wins. Git-remote sync is supported too but still experimental, so S3 is the path I would lean on today. Since 1.0 you can also set one machine-wide default remote with &lt;code&gt;kg remote --global&lt;/code&gt;, so each new project syncs without per-project setup. On a store of a million decisions across thirty writers, a decision lookup answers in about a hundred milliseconds. kgai hit 1.0 in July 2026, and from that release the on-disk log format, the &lt;code&gt;kg&lt;/code&gt; CLI surface and the JSON output shapes follow semver, so a breaking change to any of them means a major version bump. It is MIT licensed.&lt;/p&gt;

&lt;p&gt;The honest tradeoff is the flip side of the scope. If you want an agent to remember arbitrary facts, conversation history, or a user's preferences across products, kgai does not do that and mem0, Graphiti and Cognee do. Use them for that. kgai is for the case where the thing you keep losing is your team's decisions, and where standing up a memory service to hold them is more than you want to run.&lt;/p&gt;

&lt;h2&gt;
  
  
  Which to reach for
&lt;/h2&gt;

&lt;p&gt;If you need general agent or personal memory over changing facts, these are strong, and Graphiti in particular has the most serious model of time and history. If you specifically want your team's decisions, their rationale, their reversals and their dead ends to survive, recalled inside Claude Code without operating a backend, that narrower shape is what kgai is built for.&lt;/p&gt;

&lt;p&gt;The plugin is open source, stable as of v1.0.0, and installs in two commands. Details, the benchmark, and what still does not work well are on &lt;a href="https://kgai.dev/?ref=medium-compare" rel="noopener noreferrer"&gt;kgai.dev&lt;/a&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;claude plugin marketplace add kgaidev/kgai
claude plugin &lt;span class="nb"&gt;install &lt;/span&gt;kgai@kgai-marketplace
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>ai</category>
      <category>claude</category>
      <category>devtools</category>
      <category>opensource</category>
    </item>
    <item>
      <title>Storing decisions instead of memory: the design behind kgai</title>
      <dc:creator>kgaidev</dc:creator>
      <pubDate>Sat, 18 Jul 2026 21:26:56 +0000</pubDate>
      <link>https://dev.to/kgaidev/storing-decisions-instead-of-memory-the-design-behind-kgai-26dk</link>
      <guid>https://dev.to/kgaidev/storing-decisions-instead-of-memory-the-design-behind-kgai-26dk</guid>
      <description>&lt;p&gt;Coding agents have a specific failure mode on long-lived codebases. Every few sessions the agent re-proposes something the team already evaluated and rejected. It reads the code, sees a slow search query, and suggests Elasticsearch. The reason Elasticsearch was rejected months ago exists only in a chat thread, so from the agent's point of view the question was never settled.&lt;/p&gt;

&lt;p&gt;Humans on the team hit the same wall in slower motion. &lt;code&gt;git blame&lt;/code&gt; tells you who changed a line and when, the PR tells you what was merged, but neither records why the other approach lost. The reviewer who knew leaves the team, and six months later someone re-litigates the whole thing in a new PR.&lt;/p&gt;

&lt;p&gt;This post describes how kgai (&lt;a href="https://github.com/kgaidev/kgai" rel="noopener noreferrer"&gt;https://github.com/kgaidev/kgai&lt;/a&gt;, MIT) approaches that as a data problem inside the dev workflow, and which properties fall out of the design. No prior knowledge of knowledge graphs is assumed.&lt;/p&gt;

&lt;h2&gt;
  
  
  The data model: boxes and arrows
&lt;/h2&gt;

&lt;p&gt;A knowledge graph here means nothing more than a map of things and connections. The things are the parts of a codebase as you'd sketch them in a design review:&lt;/p&gt;

&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fop6hh7xrug3mk80mnqcb.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fop6hh7xrug3mk80mnqcb.png" alt="Elements of a codebase connected by labeled links, with properties on the side" width="800" height="320"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Each box is an element. Elements carry properties, like &lt;code&gt;search-api.retry_policy = "idempotency-key + backoff"&lt;/code&gt;. That's the entire vocabulary: elements, links, properties. It lives in &lt;code&gt;&amp;lt;project&amp;gt;/.kgai/store&lt;/code&gt;, next to the code it describes, one store per repo.&lt;/p&gt;

&lt;p&gt;The graph itself is not the interesting part. The interesting part is where it comes from.&lt;/p&gt;

&lt;h2&gt;
  
  
  Decisions as the source of truth
&lt;/h2&gt;

&lt;p&gt;A bank doesn't store an account balance as a number that gets edited. It stores a list of transactions, and the balance is derived by summing them. A transaction, once recorded, is never modified. Corrections are new transactions.&lt;/p&gt;

&lt;p&gt;kgai applies the same structure to a codebase's architecture. The current shape (the graph above) is the derived value. The recorded facts are decisions, captured during the session in which they were made:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;✓ recorded "Search retries use idempotency keys + exponential backoff"
    why: fixed 3x retry double-charged a request during a provider brownout
    sets search-api.retry_policy = "idempotency-key + backoff"
    supersedes "Simple 3x retry is enough"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A decision states what changed, why, and which elements it touches. The queryable graph is computed by replaying the decision log from the beginning. Deleting the graph and replaying the log yields byte-identical results, so the log is the truth and the graph is a disposable cache.&lt;/p&gt;

&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fpnufl0yo6d21dshn4zyx.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fpnufl0yo6d21dshn4zyx.png" alt="An append-only decision log replayed into a derived graph" width="800" height="366"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This is event sourcing, the same pattern financial systems use. Applied here, the "account" is the reasoning behind a repo.&lt;/p&gt;

&lt;p&gt;Supersession instead of edits&lt;br&gt;
A decision is never updated. A change is expressed as a new decision that supersedes the old one. The old decision remains in the log, marked superseded:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;kg &lt;span class="nb"&gt;history&lt;/span&gt; &lt;span class="s2"&gt;"feature:search-api"&lt;/span&gt;
feature:search-api — 2 decisions, oldest first

  2026-05-02  Simple 3x retry is enough                                superseded
      why: provider timeouts are rare, simplest thing that works

  2026-07-16  Search retries use idempotency keys + backoff            ● current
      why: fixed 3x retry double-charged a request during a brownout
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fej1plkak1re9xewmlr1z.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fej1plkak1re9xewmlr1z.png" alt="A superseded decision pointing to the current one, history keeps both, context serves one" width="800" height="297"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Two properties follow.&lt;/p&gt;

&lt;p&gt;Rejected paths stay recorded. When a teammate opens a PR that swaps the retry logic back to something simpler, the review comment writes itself: the graph holds the incident that killed that approach. The same applies to QA reading unexpected behavior, or to the new hire asking why the API boundary sits where it sits. The answer is one query away instead of one departed colleague away.&lt;/p&gt;

&lt;p&gt;Recall stays clean. When an agent asks what's decided about an area, it receives only the current head decisions. Superseded decisions are reachable through history but are not injected into the model's context. This matters in practice: a language model given two contradictory rationales will sometimes follow the outdated one. Serving only the current state removes that failure mode while keeping the full record.&lt;/p&gt;

&lt;h2&gt;
  
  
  Idempotence and what it means for a dev team
&lt;/h2&gt;

&lt;p&gt;An operation is idempotent when performing it twice has the same effect as performing it once. An elevator button is idempotent.&lt;/p&gt;

&lt;p&gt;In kgai a decision's identity is a hash of its content. Recording the same decision twice, from two machines, in any order, converges to a single record, because identical content produces an identical id. There is no sequence counter to coordinate and no last-writer-wins overwrite.&lt;/p&gt;

&lt;p&gt;The consequence for a team: every dev's agent appends to its own log file, and sync is a union of logs over plain git or an S3 bucket. Textual merge conflicts cannot occur, because nothing is ever edited in place. Every machine replays the combined log and arrives at the same graph deterministically. Nobody maintains a wiki, nobody merges anybody's notes.&lt;/p&gt;

&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Frwyhwjnrgbxo7qafadg0.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Frwyhwjnrgbxo7qafadg0.png" alt="Two developers' logs synced through git or S3 into byte-identical graphs" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The only conflict that can exist is a semantic one. Two devs on two branches genuinely decided the same thing differently, say Alice put session state in Redis while Bob kept it in-process. Both decisions stand in the log and the element then has two current heads, which kg conflicts reports, typically surfacing at review time. Resolution is one more decision that supersedes both. The disagreement and its resolution both remain in history, which is occasionally more useful than the resolution itself.&lt;/p&gt;

&lt;h2&gt;
  
  
  Performance characteristics
&lt;/h2&gt;

&lt;p&gt;An append-only log grows forever, which sounds like a scaling problem. It isn't, because queries never touch the log. Reads go to the derived graph, which lives in an embedded property graph database (Kuzu) inside the project directory. Writes are file appends. Rebuilds stream the log through a bulk loader rather than applying events one at a time.&lt;/p&gt;

&lt;p&gt;Measured on stores larger than a real team produces, one million decisions across fifty thousand elements written by thirty concurrent users:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;store size&lt;/th&gt;
&lt;th&gt;everyday sync&lt;/th&gt;
&lt;th&gt;cold clone&lt;/th&gt;
&lt;th&gt;full rebuild&lt;/th&gt;
&lt;th&gt;lookup&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;20k decisions&lt;/td&gt;
&lt;td&gt;&amp;lt; 0.5 s&lt;/td&gt;
&lt;td&gt;~3 s&lt;/td&gt;
&lt;td&gt;~1.5 s&lt;/td&gt;
&lt;td&gt;~60 ms&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;100k decisions&lt;/td&gt;
&lt;td&gt;&amp;lt; 0.5 s&lt;/td&gt;
&lt;td&gt;~12 s&lt;/td&gt;
&lt;td&gt;~6 s&lt;/td&gt;
&lt;td&gt;~60 ms&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;1M decisions&lt;/td&gt;
&lt;td&gt;~2 s&lt;/td&gt;
&lt;td&gt;&amp;lt; 2 min&lt;/td&gt;
&lt;td&gt;&amp;lt; 1 min&lt;/td&gt;
&lt;td&gt;~100 ms&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Focfyn0fgkk0l8u54h48w.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Focfyn0fgkk0l8u54h48w.png" alt="Lookup latency stays flat from 20k to 1M decisions" width="800" height="297"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Cold clone is the onboarding path: a new teammate pulls the full decision history and has a queryable graph in seconds on a normal-sized store. These are single-run wall-clock numbers from our harness on our hardware, not percentiles. The raw runs are archived in the repo. Query latency stays flat with history size because the graph holds only current state.&lt;/p&gt;

&lt;p&gt;The read path contains no vector search and no LLM call. Retrieval is scoped by element and path identifiers, so recall is deterministic and adds no token cost beyond the decisions themselves.&lt;/p&gt;

&lt;h2&gt;
  
  
  Capture is enforced, not requested
&lt;/h2&gt;

&lt;p&gt;Decisions enter the log during normal coding sessions. Today that's wired into Claude Code as a plugin, and the engine is a single CLI, so any agent environment that can run a command can use it. When a session that edited code ends, a hook blocks the agent until it either records the structural decision it made or explicitly states there was none. This is deterministic by design. In testing, unprompted capture by the model alone proved unreliable, so the capture step is enforced at the hook level. Trivial changes (renames, formatting, bug fixes) record nothing, which keeps the log at decision granularity rather than becoming a diary.&lt;/p&gt;

&lt;p&gt;Before modifying an area, the agent queries the graph for decisions relevant to the files it's about to touch. The Elasticsearch case from the beginning then resolves differently: the agent finds the rejection and its reasoning, and works within it. So does the next dev who asks.&lt;/p&gt;

&lt;h2&gt;
  
  
  Boundaries
&lt;/h2&gt;

&lt;p&gt;The design has edges worth knowing. Free-text search over a very large store scans the corpus (about 1.4 s at 100k decisions), an index for that is planned. A 1M-decision log is roughly 790 MB on disk. Prebuilt engine binaries exist for Linux and macOS, not Windows.&lt;/p&gt;

&lt;p&gt;Everything runs locally. Sync targets are a git remote or an S3 bucket the team owns. The engine, plugin and benchmark harness are MIT: &lt;a href="https://github.com/kgaidev/kgai" rel="noopener noreferrer"&gt;https://github.com/kgaidev/kgai&lt;/a&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>programming</category>
      <category>opensource</category>
      <category>softwaredesign</category>
    </item>
  </channel>
</rss>
