<rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Ai-Memory | AkitaOnRails.com</title><link>https://akitaonrails.github.io/en/tags/ai-memory/</link><description>Fabio Akita's blog — tech, career, and assorted geek topics. English edition.</description><generator>Hugo -- gohugo.io</generator><language>en</language><lastBuildDate>Mon, 19 Oct 2026 23:20:51 +0000</lastBuildDate><atom:link href="https://akitaonrails.github.io/en/tags/ai-memory/index.xml" rel="self" type="application/rss+xml"/><item><title>AI-MEMORY 2.0 - The Best Memory System for Agents and Teams</title><link>https://akitaonrails.github.io/en/2026/09/02/ai-memory-2-0-best-memory-system-for-agents-and-teams/</link><guid isPermaLink="true">https://akitaonrails.github.io/en/2026/09/02/ai-memory-2-0-best-memory-system-for-agents-and-teams/</guid><pubDate>Wed, 02 Sep 2026 11:00:00 -0300</pubDate><description>&lt;p&gt;&lt;strong&gt;TL;DR:&lt;/strong&gt; &lt;a href="https://github.com/akitaonrails/ai-memory/releases/tag/v2.0.0"target="_blank" rel="noopener"&gt;ai-memory 2.0 is out&lt;/a&gt;, with the open OKF format, local embeddings turned on by default, and real support for several agents and a whole team working on the same project in parallel. The full pitch is below.&lt;/p&gt;
&lt;p&gt;Back in July I published &lt;a href="https://akitaonrails.github.io/en/2026/07/20/whats-new-ai-memory-switch-agents-without-losing-session/"&gt;What&amp;rsquo;s New in My AI-MEMORY&lt;/a&gt;, where I showed off &lt;code&gt;ai-memory run&lt;/code&gt;: switching from Claude Code to Codex without losing your line of work. That day we were on version 1.17.1.&lt;/p&gt;</description><content:encoded><![CDATA[<p><strong>TL;DR:</strong> <a href="https://github.com/akitaonrails/ai-memory/releases/tag/v2.0.0"target="_blank" rel="noopener">ai-memory 2.0 is out</a>, with the open OKF format, local embeddings turned on by default, and real support for several agents and a whole team working on the same project in parallel. The full pitch is below.</p>
<p>Back in July I published <a href="/en/2026/07/20/whats-new-ai-memory-switch-agents-without-losing-session/">What&rsquo;s New in My AI-MEMORY</a>, where I showed off <code>ai-memory run</code>: switching from Claude Code to Codex without losing your line of work. That day we were on version 1.17.1.</p>
<p>Today <strong>2.0</strong> shipped. And this time I&rsquo;m not going to rehash how the hooks work or how a session turns into a wiki page. That&rsquo;s already in the earlier posts. Here I want to talk about where ai-memory landed against the competition, what 2.0 brings, and why it earned the jump to a &ldquo;2&rdquo;.</p>
<p>If you&rsquo;ve never heard of the project, the summary is short. ai-memory is a long-term memory server for your coding agents. It captures what happened in the session, consolidates it into Markdown pages, and hands the right context to the next agent, whatever the harness or the machine.</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/20260902132131_screenshot-2026-09-02_13-20-02.png" alt="ai-memory 2.0 web browser showing the wiki’s project list, with the pre-migration OKF backup notice and cards for several projects like ai-memory, akitaonrails-hugo, and others"  loading="lazy" /></p>
<p>This is the web interface that comes with it, handy for auditing what the agents wrote and for browsing between projects. Notice how each project lives separately, with its own page count, all of it coming out of real sessions.</p>
<h2>Why it became 2.0<span class="hx:absolute hx:-mt-20" id="why-it-became-20"></span>
    <a href="#why-it-became-20" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>For me, the first digit of a version carries a commitment.</p>
<p>The 1.x line grew too fast. We went from 1.1 to 1.39 in a little over two months, stacking feature on top of feature in minor releases. It worked for iterating, but it blurred what the numbers meant.</p>
<p>2.0 fixes that. It bundles the few compatibility-breaking changes into a single major, and from here on versioning follows real <a href="https://github.com/akitaonrails/ai-memory/blob/main/CONTRIBUTING.md"target="_blank" rel="noopener">Semantic Versioning</a>. A fix is a patch. A new feature is a minor. Only a format or contract break is a major, and always with warning. The new contributing guide spells that rule out for any PR.</p>
<p>The main break is the new on-disk format. The first time you bring up 2.0, it migrates your wiki on its own. Before touching anything, it compresses your entire data directory into a verified backup with the date in the name. If the backup can&rsquo;t be written and checked, the migration aborts and the server refuses to start. No &ldquo;trust me&rdquo;.</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/20260902131952_screenshot-2026-09-02_13-16-17.png" alt="ai-memory 2.0 dialog announcing that the memory was migrated to the OKF v0.2 format, showing the verified backup path and the rollback steps"  loading="lazy" /></p>
<p>This is the notice that shows up once, right after the migration: it tells you where the backup landed, the file size, and how to roll back if something looks off. Once you confirm everything is fine, you just delete the backup and the reminder disappears.</p>
<h2>OKF: your memory isn&rsquo;t locked inside ai-memory<span class="hx:absolute hx:-mt-20" id="okf-your-memory-isnt-locked-inside-ai-memory"></span>
    <a href="#okf-your-memory-isnt-locked-inside-ai-memory" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>This is the change that made me happiest.</p>
<p>Starting with 2.0, the ai-memory wiki is, natively, a bundle in the <strong>Open Knowledge Format</strong>, the open format Google published in 2026. Each memory page is a valid OKF file: plain Markdown with standardized metadata. There&rsquo;s no export step that produces a divergent copy. The wiki files already are the OKF files.</p>
<p>In practice that means your memory stopped being a hostage of my project. You can read it all with <code>grep</code>, open it in Obsidian, version it in Git, or hand the bundle to a coworker who uses another OKF-compatible tool. There&rsquo;s even an <code>ai-memory export-okf</code> to package a whole project into a validated tarball.</p>
<p>That was always the thesis: the model and the harness are rented, the project&rsquo;s memory is yours. Now the format backs that up in writing.</p>
<h2>Local embeddings, on by default<span class="hx:absolute hx:-mt-20" id="local-embeddings-on-by-default"></span>
    <a href="#local-embeddings-on-by-default" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Up through 1.x, real semantic search depended on you configuring an embeddings provider. Either you paid for an API and sent every page and every query out, or you spun up an Ollama on the side. Both options have a cost.</p>
<p>2.0 brings a <code>local</code> provider that runs the embeddings model inside the process itself, in pure Rust, with <code>all-MiniLM-L6-v2</code>. No API key, no external server, no GPU, and nothing about your data leaving the box. And now it comes on by default. On the first run it downloads the model (about 87 MB, with a fixed checksum) in the background and turns on hybrid search at the next restart.</p>
<p>The gain is measurable. On the LongMemEval-S benchmark, hit@5 goes from 0.617 with full-text only to 0.779 with the local embeddings. If for some reason you don&rsquo;t want it, an <code>embedding_provider = &quot;none&quot;</code> turns it off.</p>
<p>A detail that matters: I chose <code>candle</code> on purpose, instead of the native runtime the competition uses. That native layer is exactly what caused a recurring kind of crash in other memory projects. I preferred not to inherit the problem.</p>
<h2>Several agents at once, on the same project<span class="hx:absolute hx:-mt-20" id="several-agents-at-once-on-the-same-project"></span>
    <a href="#several-agents-at-once-on-the-same-project" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Here&rsquo;s where the part that drove most of the work before 2.0 begins.</p>
<p>The <code>ai-memory run</code> case I showed in July was sequential: I close Claude, open Codex, keep going. But what about when I leave two or three harnesses open at the same time on the same project? Claude in one tab, Codex in another, OpenCode in a third.</p>
<p>ai-memory handles that without anyone stepping on anyone else. Each memory call figures out on its own which project it belongs to, from the session&rsquo;s directory. The &ldquo;current project&rdquo; pointer is now per actor, so two harnesses in the same checkout each keep their own sense of context. And the project&rsquo;s identity comes from the checkout name. The absolute path on disk doesn&rsquo;t count, so the same project on the laptop and on the desktop lands in the same place.</p>
<p>When two windows write to the same page, the second doesn&rsquo;t erase the first. It creates a new version that becomes the latest, and the previous one stays reachable in the version chain. Writing something identical doesn&rsquo;t create a new version. Every write goes through a single writer, with a queue and backpressure, so a burst doesn&rsquo;t corrupt anything.</p>
<p>This isn&rsquo;t theory. There&rsquo;s an acceptance test calling Claude, Codex, OpenCode, Pi, Crush, and a few others for real, inside a single workstream, covering leases, session adoption, and context handoff between harnesses.</p>
<h2>A whole team on the same project<span class="hx:absolute hx:-mt-20" id="a-whole-team-on-the-same-project"></span>
    <a href="#a-whole-team-on-the-same-project" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>The second scenario is the one that gives the post its title. Here it&rsquo;s several people, a whole team pointing their agents at the same server.</p>
<p>The way to run it is simple. Someone brings up a server, usually a container in a homelab or on a machine on the network, and each person points their agents at that URL. HTTPS goes in front with a reverse proxy, if you want. The database is still a single SQLite.</p>
<p>Everyone sees the same project pages. What one person learned in a session, the other&rsquo;s agent recovers. And each new session gets a briefing with the project&rsquo;s state right at the start. I&rsquo;ll be honest about the term &ldquo;real time&rdquo;. What exists is a shared central store, with immediate reads, plus the briefing at the open. The note a coworker wrote shows up right away for anyone&rsquo;s next query or next session. A session that&rsquo;s already running only gets the news at the next query or the next open, with no interruption mid-flight.</p>
<p>What changes in multi-user mode is attribution. Each write records who did it. There&rsquo;s an audit log and the interface shows &ldquo;edited by so-and-so&rdquo;. That comes in the box, for free. And there&rsquo;s no per-page permission, on purpose. Attribution is there to record authorship; anyone authenticated can write, and the history is what keeps track of who did.</p>
<p>There&rsquo;s an important security distinction between what&rsquo;s shared and what&rsquo;s personal. The pages belong to everyone. But the handoff is a baton with a single owner: exactly one session takes it, and a second <code>accept</code> doesn&rsquo;t steal the baton from anyone. The handoff you left pending isn&rsquo;t delivered to or consumed by a coworker. Likewise, the &ldquo;what I&rsquo;m working on right now&rdquo; slots are per person, so your personal context doesn&rsquo;t leak into the whole team&rsquo;s briefing.</p>
<p>There&rsquo;s also a battery of real concurrency tests covering these cases: simultaneous writes, per-actor isolation under load, the handoff baton that doesn&rsquo;t get stolen, and the personal slots that don&rsquo;t leak.</p>
<h2>Where ai-memory stands against the competition<span class="hx:absolute hx:-mt-20" id="where-ai-memory-stands-against-the-competition"></span>
    <a href="#where-ai-memory-stands-against-the-competition" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Before 2.0 we did another round of research on the 2026 landscape, documented in the repository. It was the basis for deciding what 2.0 needed to cover. Let me summarize the field.</p>
<p>There&rsquo;s <strong>agentmemory</strong>, a TypeScript MCP server tied to a native sidecar and a giant surface of dozens of tools. There&rsquo;s <strong>basic-memory</strong>, in Python, Markdown on disk, but with manual capture: you have to ask it to remember. There&rsquo;s <strong>cognee</strong>, which combines graph, vector, and relational into a heavy pipeline that wants several gigs of RAM. There&rsquo;s <strong>MemPalace</strong>, which went viral with almost 50,000 stars in two weeks over a benchmark number that, once audited, turned out to be inflated, on top of suffering corruption when two writes happen together. And there are the temporal graphs like <strong>Zep</strong>, the &ldquo;memory OS&rdquo; like <strong>Letta</strong> (the old MemGPT), and the fact extractors like <strong>Mem0</strong>.</p>
<p>There&rsquo;s also the native memory that Claude Code itself started turning on by default. I treat that one as the funnel that introduces the category to people. As a competitor it stays limited: tied to one machine, tied to one agent, without real search and without team history.</p>
<p>2.0 closes the gaps the research pointed out. We started publishing a reproducible benchmark with LongMemEval, running the actual server. We got the open OKF format. We got typed links between pages, with <code>causes</code>, <code>fixes</code>, and <code>contradicts</code>, which also feed a contradiction check without spending an LLM. We got queries with <code>as_of</code>, to ask what we knew about a subject on a given date. We got the local embeddings. And we got an optional &ldquo;experience&rdquo; pass that reviews several sessions to find patterns that only show up across the set.</p>
<p>Now the part that matters for whoever&rsquo;s choosing. What ai-memory has that the others don&rsquo;t, all together:</p>
<ul>
<li><strong>It follows you across agents.</strong> More than twenty harnesses feed a single memory, and the handoff here is a real protocol: typed, with an owner, and claimed exactly once.</li>
<li><strong>It follows you across machines.</strong> The memory lives on a server that&rsquo;s yours. The project you dropped on the desktop is the one you pick back up on the laptop.</li>
<li><strong>It works for a team.</strong> Multi-user authentication, per-person attribution, and an audit log come in the box, for free.</li>
<li><strong>Your memory is plain Markdown.</strong> The source of truth is a wiki versioned in Git. The database is a derived index you can rebuild at any moment from the files, with no vector store to babysit and nothing trapped in a binary blob.</li>
<li><strong>It captures the work on its own, quietly.</strong> No &ldquo;remember this&rdquo; ceremony. And the default path runs with zero LLM calls.</li>
<li><strong>It&rsquo;s a single binary.</strong> No sidecar, no three databases to sync. Every write goes through a single writer, with a write ceiling we actually measured, with a real test. That design is exactly what avoided the concurrent-write corruption that took the others down.</li>
</ul>
<p>No competitor delivers this set. Some have one piece or another. ai-memory has the whole package, and now with parity on the items where it used to fall behind.</p>
<h2>2.0 belongs to everyone<span class="hx:absolute hx:-mt-20" id="20-belongs-to-everyone"></span>
    <a href="#20-belongs-to-everyone" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>When I wrote the July post, fifteen people had a merged PR in the project. Today it&rsquo;s around seventy. This stopped being a weekend project a long time ago.</p>
<p>The numbers up to 2.0: more than 1,500 commits, <strong>371 merged pull requests</strong>, and <strong>181 closed issues</strong>. That came from people actually using it and sending fixes, features, and documentation.</p>
<p>I have to give special thanks to <a href="https://github.com/djalmajr"target="_blank" rel="noopener">Djalma Júnior</a>, who on his own passed 50 merged PRs, and to <a href="https://github.com/samirhvbr"target="_blank" rel="noopener">Samir Hanna Verza</a>, with more than 20. Right behind come <a href="https://github.com/lhzapata"target="_blank" rel="noopener">lhzapata</a>, <a href="https://github.com/pedrofjr"target="_blank" rel="noopener">pedrofjr</a>, <a href="https://github.com/mrpaiva"target="_blank" rel="noopener">mrpaiva</a>, <a href="https://github.com/lucasliet"target="_blank" rel="noopener">lucasliet</a>, <a href="https://github.com/lihuiyang1024"target="_blank" rel="noopener">lihuiyang1024</a>, <a href="https://github.com/Murillofilho86"target="_blank" rel="noopener">Murillofilho86</a>, and <a href="https://github.com/matheus-rodrigues00"target="_blank" rel="noopener">Matheus Rodrigues</a>. And there&rsquo;s a long tail of dozens of other people with a merged PR that it would be unfair to try to list in full here.</p>
<p>If you want in on this, the <a href="https://github.com/akitaonrails/ai-memory/blob/main/CONTRIBUTING.md"target="_blank" rel="noopener">contributing guide</a> was rewritten to make everything clear: how to set up the environment, the gates the CI enforces, the CHANGELOG rule, and the versioning policy. A bug fix usually ships fast in the next patch. A small feature, like a new harness or provider, goes into the next minor. There are issues tagged for people just starting out.</p>
<h2>How to get 2.0<span class="hx:absolute hx:-mt-20" id="how-to-get-20"></span>
    <a href="#how-to-get-20" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>The project page has every install method, including AUR, Homebrew, and release binaries:</p>
<ul>
<li><a href="https://github.com/akitaonrails/ai-memory"target="_blank" rel="noopener">ai-memory on GitHub</a></li>
<li><a href="https://github.com/akitaonrails/ai-memory/releases/tag/v2.0.0"target="_blank" rel="noopener">v2.0.0 release notes</a></li>
</ul>
<p>After updating, on the first run let the migration take the backup and convert your wiki to the OKF format. If you use the managed mode, reinstall the hooks for the harnesses you plan to use.</p>
<h2>Conclusion<span class="hx:absolute hx:-mt-20" id="conclusion"></span>
    <a href="#conclusion" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>1.x proved the idea worked. 2.0 is the version I&rsquo;d recommend without an asterisk for someone else to put on a team.</p>
<p>The format is open, so your memory doesn&rsquo;t get locked in. Semantic search runs local, so you don&rsquo;t pay and you don&rsquo;t leak. Several agents and several people work on the same project without running each other over. And the single-binary, single-writer design is what avoids exactly the problems that sank half the competition.</p>
<p>The LLM and the subscription I keep renting from whoever&rsquo;s best that month. The project&rsquo;s memory stays with me, with the team, and now in a format nobody can take away from me.</p>
]]></content:encoded><category>ai-memory</category><category>coding-agents</category><category>open-source</category></item><item><title>What's New in My AI-MEMORY: Switch AI Agents Without Losing the Session</title><link>https://akitaonrails.github.io/en/2026/07/20/whats-new-ai-memory-switch-agents-without-losing-session/</link><guid isPermaLink="true">https://akitaonrails.github.io/en/2026/07/20/whats-new-ai-memory-switch-agents-without-losing-session/</guid><pubDate>Mon, 20 Jul 2026 21:00:00 -0300</pubDate><description>&lt;p&gt;It&amp;rsquo;s been a little over a month since I published &lt;a href="https://akitaonrails.github.io/en/2026/06/16/ai-memory-long-term-memory-karpathy-wiki-self-improvement-hermes-projects/"&gt;ai-memory: long-term memory (Karpathy Wiki) and self-improvement (Hermes) for your projects&lt;/a&gt;. That was June 16. In that post I explained how sessions became Markdown pages, how auto-improve promoted lessons, and why bad memory can be worse than amnesia.&lt;/p&gt;
&lt;p&gt;Version 1.1.0 shipped that same day. Today, July 20, we&amp;rsquo;re at &lt;strong&gt;1.17.1&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Version numbers alone don&amp;rsquo;t mean much, so I counted what actually happened after that post went live: &lt;strong&gt;31 releases, 55 merged pull requests, and 46 closed issues&lt;/strong&gt;. I counted &lt;strong&gt;24 groups of new user-facing features&lt;/strong&gt; in the &lt;a href="https://github.com/akitaonrails/ai-memory/blob/main/CHANGELOG.md"target="_blank" rel="noopener"&gt;CHANGELOG&lt;/a&gt;, ignoring fixes, documentation, and internal details from the same delivery. If I split the new &lt;code&gt;ai-memory run&lt;/code&gt; family into auto-selection, session adoption, Crush support, &lt;code&gt;--yolo&lt;/code&gt;, search, and recovery, we&amp;rsquo;d blow past that number.&lt;/p&gt;</description><content:encoded><![CDATA[<p>It&rsquo;s been a little over a month since I published <a href="/en/2026/06/16/ai-memory-long-term-memory-karpathy-wiki-self-improvement-hermes-projects/">ai-memory: long-term memory (Karpathy Wiki) and self-improvement (Hermes) for your projects</a>. That was June 16. In that post I explained how sessions became Markdown pages, how auto-improve promoted lessons, and why bad memory can be worse than amnesia.</p>
<p>Version 1.1.0 shipped that same day. Today, July 20, we&rsquo;re at <strong>1.17.1</strong>.</p>
<p>Version numbers alone don&rsquo;t mean much, so I counted what actually happened after that post went live: <strong>31 releases, 55 merged pull requests, and 46 closed issues</strong>. I counted <strong>24 groups of new user-facing features</strong> in the <a href="https://github.com/akitaonrails/ai-memory/blob/main/CHANGELOG.md"target="_blank" rel="noopener">CHANGELOG</a>, ignoring fixes, documentation, and internal details from the same delivery. If I split the new <code>ai-memory run</code> family into auto-selection, session adoption, Crush support, <code>--yolo</code>, search, and recovery, we&rsquo;d blow past that number.</p>
<p>Fifteen people had PRs merged during that period, fourteen besides me. Special thanks go to <a href="https://github.com/djalmajr"target="_blank" rel="noopener">Djalma Júnior</a>, who alone had 24 PRs merged, <a href="https://github.com/matheus-rodrigues00"target="_blank" rel="noopener">Matheus Rodrigues</a>, with five, <a href="https://github.com/lhzapata"target="_blank" rel="noopener">lhzapata</a>, with four, <a href="https://github.com/rthiago"target="_blank" rel="noopener">Thiago Silva</a> and <a href="https://github.com/cristianodewes"target="_blank" rel="noopener">Cristiano Dewes</a>, with two each. Nine more contributors had a PR merged. This stopped being &ldquo;a little program I made over a weekend&rdquo; a while ago.</p>
<p>I&rsquo;m not going to dump 55 PRs here. I want to talk about the change that affects my daily use the most: the new <strong><code>ai-memory run</code></strong>.</p>
<h2>The session is part of the project too<span class="hx:absolute hx:-mt-20" id="the-session-is-part-of-the-project-too"></span>
    <a href="#the-session-is-part-of-the-project-too" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Code is the result that survived. It doesn&rsquo;t preserve the entire investigation.</p>
<p>Git shows that you replaced Redis with SQLite. Maybe the commit explains part of it. But where is the Redis experiment? Where is the intermittent bug that only showed up with two workers? Who remembered that the first solution broke on Windows? Why did the team change its mind after three hours? Which workaround was temporary, and which one became the decision?</p>
<p>Much of that exists only in the agent session.</p>
<p>When I program with Claude Code or Codex, the session accumulates the project&rsquo;s operational reasoning: questions, corrections, discarded attempts, test results, surprises, decisions, and changes in direction. The final code shows what stayed. The session explains how we got there.</p>
<p>And an LLM session, at the end of the day, is text. Claude Code writes JSONL. Codex does too. OpenCode uses SQLite. Pi, OMP, and Crush have their own formats and directories. Each harness packages the conversation differently, but the visible content is still messages and tool results.</p>
<p>Why should I leave the most expensive part of the work trapped inside the harness?</p>
<p>Anthropic can change limits, pricing, models, or formats tomorrow. OpenAI can too. An agent can be excellent this week and unbearable the next. I want to swap the engine without throwing away the whole trip.</p>
<p>That has been ai-memory&rsquo;s thesis from the start: <strong>the programmer must remain independent of provider whims</strong>. Models and harnesses are replaceable. The project memory is mine.</p>
<h2>Handoffs solved only half the problem<span class="hx:absolute hx:-mt-20" id="handoffs-solved-only-half-the-problem"></span>
    <a href="#handoffs-solved-only-half-the-problem" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>ai-memory already handled handoffs. I would close Claude Code, the hooks would consolidate the session, and the next Codex would receive a short summary with what had been done, open questions, and next steps.</p>
<p>That still exists and is still useful. Anyone who opens <code>claude</code>, <code>codex</code>, or <code>opencode</code> directly keeps the previous behavior. The new launcher is opt-in.</p>
<p>But a handoff is deliberately lossy compression. It preserves what seems most important at that moment. It isn&rsquo;t meant to carry the entire session or resume each harness&rsquo;s native session. If the summary left out an old attempt that became relevant again two hours later, you have to search the wiki or the records.</p>
<p><code>ai-memory run</code> adds another layer: a <strong>managed workstream</strong>, one line of work that crosses harnesses.</p>
<h2>Claude now, Codex in a little while<span class="hx:absolute hx:-mt-20" id="claude-now-codex-in-a-little-while"></span>
    <a href="#claude-now-codex-in-a-little-while" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Basic usage looks like this:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="nb">cd</span> ~/Projects/meu-projeto
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">ai-memory run claude
</span></span><span class="line"><span class="cl"><span class="c1"># work, then exit Claude Code normally</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">ai-memory run codex --yolo
</span></span><span class="line"><span class="cl"><span class="c1"># Codex continues the same line of work</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">ai-memory run claude --model opus
</span></span><span class="line"><span class="cl"><span class="c1"># return to Claude&#39;s previous native session</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">ai-memory run
</span></span><span class="line"><span class="cl"><span class="c1"># or let ai-memory choose the right harness to continue</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>You don&rsquo;t need <code>--</code> to separate arguments. Everything after the harness name goes to it, with one deliberate exception: <code>--yolo</code> belongs to the wrapper and is translated into the native dangerous option for Claude Code, Codex, OpenCode, Pi, or Crush.</p>
<p>Under the hood, ai-memory doesn&rsquo;t try to convert a Codex file into a Claude file. That would be fragile and would probably break on the next update. Each harness keeps its own native session. The workstream connects those sessions to a portable ledger containing the visible part of the conversation.</p>
<p>Think of it this way:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">Claude native session ─┐
</span></span><span class="line"><span class="cl">Codex native session  ─┼─ workstream ─ portable context
</span></span><span class="line"><span class="cl">OpenCode session      ─┤                 + full search
</span></span><span class="line"><span class="cl">Pi native session     ─┘</span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>The first time Claude enters that workstream, it gets a native session. When you switch to Codex, Codex gets its own native session and receives the portable delta it hasn&rsquo;t seen yet. When you return to Claude, the launcher uses Claude Code&rsquo;s own <code>--resume</code> and delivers only what happened in the other harnesses since the last visit.</p>
<p>This is very different from starting a new chat with a summary pasted into the prompt. Claude returns to its real session. Codex returns to its real session. ai-memory handles continuity between the two.</p>
<p>Managed mode currently supports <strong>Claude Code, Codex, OpenCode, Pi, Crush, and OMP</strong>. General ai-memory support is broader, with MCP and hooks for other clients, but that doesn&rsquo;t mean every client already has a native-session adapter for <code>run</code>. Those are different contracts, and I prefer to make that explicit.</p>
<h2>What goes into the workstream<span class="hx:absolute hx:-mt-20" id="what-goes-into-the-workstream"></span>
    <a href="#what-goes-into-the-workstream" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>When the harness exits, ai-memory reads the tail of the native session without modifying the original store. It imports visible user and assistant messages, completed tool calls with their results, compaction summaries, and a non-mutating Git checkpoint. Every event keeps its origin: Claude, Codex, OpenCode, Pi, Crush, or OMP.</p>
<p>Provider credentials, encrypted records, system and developer prompts, and hidden reasoning stay out. Private formats the adapter doesn&rsquo;t understand stay out too and produce a loss annotation instead of letting the system pretend it imported everything.</p>
<p>Records pass through the sanitizer before entering ai-memory&rsquo;s searchable ledger and immutable JSONL segments. The adapter opens native stores read-only; the harness itself remains the writer.</p>
<p>I don&rsquo;t cram the entire session into the next prompt either. That would recreate the problem the project is trying to solve: too much raw context, too much cost, and too much noise. The next agent gets a size-limited recent delta. If an old decision matters again, the full ledger remains searchable:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">ai-memory workstream-search <span class="s2">&#34;por que desistimos do Redis&#34;</span>
</span></span><span class="line"><span class="cl">ai-memory workstream-search --limit <span class="m">50</span> --json <span class="s2">&#34;migration que falhou&#34;</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Inside an <code>ai-memory run</code>, the workstream ID is already in the environment. The agent doesn&rsquo;t have to discover some UUID.</p>
<p>And the ledger doesn&rsquo;t replace the wiki. It handles operational continuity. Decisions, rules, procedures, and gotchas that need to survive for months still deserve consolidated Markdown pages. A raw session is evidence. A wiki is organized knowledge.</p>
<h2>Can I keep more than one line of work?<span class="hx:absolute hx:-mt-20" id="can-i-keep-more-than-one-line-of-work"></span>
    <a href="#can-i-keep-more-than-one-line-of-work" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Yes. The default workstream is called <code>default</code>, selected by repository and worktree. If I want an independent line for an investigation without contaminating the main work:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">ai-memory run --new investigar-race claude
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># later, continue that line with another harness</span>
</span></span><span class="line"><span class="cl">ai-memory run --workstream investigar-race codex</span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>A lease prevents two windows from writing to the same workstream at once. On a normal exit, the launcher imports the tail of the session and releases it immediately. If someone kills the process without cleanup, the lease expires within 90 seconds and the next run resumes from the last confirmed cursor without duplicating imported events.</p>
<p>One stupid annoyance kept coming back: I would reopen a project after a few days and have no idea whether the newest session was in Claude or Codex. I&rsquo;d guess, open one, realize the context was in the other, close it, and try again.</p>
<p>Now I just run:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">ai-memory run
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># or keep the same auto-selection in YOLO mode</span>
</span></span><span class="line"><span class="cl">ai-memory run --yolo</span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>In an empty workstream, ai-memory looks for local sessions from that checkout in Claude Code, Codex, OpenCode, Pi, and Crush, finds the newest one, and opens the right harness for me. In an established workstream, server memory beats the file timestamp: it returns to the last harness attached to that work instead of accidentally adopting an old session that happened to receive a newer write. OMP remains available when selected explicitly, but it doesn&rsquo;t participate in auto-selection yet.</p>
<p>On the first explicit run, the launcher can also offer existing sessions from the same checkout for adoption. You can start using it without abandoning the chat that was already open before you updated ai-memory.</p>
<h2>Other new features I actually use<span class="hx:absolute hx:-mt-20" id="other-new-features-i-actually-use"></span>
    <a href="#other-new-features-i-actually-use" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>I promised I wouldn&rsquo;t read the entire changelog out loud, but a few changes from this month deserve a mention because they reduce work for the programmer.</p>
<h3>A briefing before the first question<span class="hx:absolute hx:-mt-20" id="a-briefing-before-the-first-question"></span>
    <a href="#a-briefing-before-the-first-question" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>A project can request an automatic briefing at the start of every session:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-toml" data-lang="toml"><span class="line"><span class="cl"><span class="p">[</span><span class="nx">briefing</span><span class="p">]</span>
</span></span><span class="line"><span class="cl"><span class="nx">inject_on_session_start</span> <span class="p">=</span> <span class="s2">&#34;true&#34;</span>
</span></span><span class="line"><span class="cl"><span class="nx">max_chars</span> <span class="p">=</span> <span class="mi">4000</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>ai-memory assembles a package with pinned pages, <code>_rules/</code>, <code>_slots/</code>, and recent titles. The agent starts with the project&rsquo;s rules and basic state instead of spending the first conversation rediscovering the architecture. It&rsquo;s opt-in because it consumes context on every SessionStart, including after a Claude <code>/clear</code>.</p>
<h3>Global preferences and cross-project search<span class="hx:absolute hx:-mt-20" id="global-preferences-and-cross-project-search"></span>
    <a href="#global-preferences-and-cross-project-search" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>Preferences that apply to all my work can now live in the reserved <code>_global</code> scope: coding style, preferred tools, personal rules, and conventions that don&rsquo;t belong to one specific repository. Normal queries already combine that scope with the current project.</p>
<p>For meta-repos that need to query several sibling projects all the time, there is another opt-in:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-toml" data-lang="toml"><span class="line"><span class="cl"><span class="p">[</span><span class="nx">recall</span><span class="p">]</span>
</span></span><span class="line"><span class="cl"><span class="nx">default_global</span> <span class="p">=</span> <span class="s2">&#34;true&#34;</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>With that, <code>memory_query</code> and <code>memory_recent</code> without an explicit scope search every project. I don&rsquo;t turn it on in every repo because gratuitous global search only adds noise.</p>
<h3>Less static instruction, more Agent Skills<span class="hx:absolute hx:-mt-20" id="less-static-instruction-more-agent-skills"></span>
    <a href="#less-static-instruction-more-agent-skills" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>The routing block in <code>CLAUDE.md</code> or <code>AGENTS.md</code> got smaller. Detailed instructions for when to search memory, consolidate, save a decision, or create a handoff moved into managed Agent Skills. One command installs or updates both without trampling the rest of the file:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">ai-memory install-instructions</span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>That reduces drift too. When the protocol changes, I update the managed package instead of hunting down an old prompt copied across forty repositories.</p>
<h3>Privacy before the network<span class="hx:absolute hx:-mt-20" id="privacy-before-the-network"></span>
    <a href="#privacy-before-the-network" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>Each repo can now exclude paths from capture:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-toml" data-lang="toml"><span class="line"><span class="cl"><span class="p">[</span><span class="nx">capture</span><span class="p">]</span>
</span></span><span class="line"><span class="cl"><span class="nx">ignore_paths</span> <span class="p">=</span> <span class="p">[</span><span class="s2">&#34;private/**&#34;</span><span class="p">,</span> <span class="s2">&#34;~/personal-notes/**&#34;</span><span class="p">]</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>When an integration recognizes a file tool and the path matches, the event is discarded locally before spool, queue, network, or server. The limits are clear: this isn&rsquo;t magic DLP, it doesn&rsquo;t understand every shell command, and it doesn&rsquo;t track content quoted in free-form text. But it handles the verifiable case without selling a fake guarantee.</p>
<p>There are also new integrations with Kimi Code, Grok Build CLI, Devin, and Zero, an OpenCode Zen/Go provider, <code>finalize-session</code> for Codex, and workspace-administration improvements. Again: having MCP and a hook doesn&rsquo;t automatically mean having <code>ai-memory run</code>. The <a href="https://github.com/akitaonrails/ai-memory#support-matrix"target="_blank" rel="noopener">README</a> separates those levels.</p>
<h2>Bonus: ai-jail on the outside, YOLO on the inside<span class="hx:absolute hx:-mt-20" id="bonus-ai-jail-on-the-outside-yolo-on-the-inside"></span>
    <a href="#bonus-ai-jail-on-the-outside-yolo-on-the-inside" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Just over a week ago I wrote about <a href="/en/2026/07/11/how-to-protect-yourself-from-agents-deleting-your-stuff/">how I protect myself from agents deleting my stuff</a>. My recommendation remains the same: YOLO mode gives the best experience, provided the system limits the possible damage.</p>
<p><a href="https://github.com/akitaonrails/ai-jail"target="_blank" rel="noopener">ai-jail</a> reached version 1.15.0 and now understands the ai-memory launcher. My favorite way to work has become:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">ai-jail ai-memory run codex --yolo</span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Or, when I want ai-memory to choose which harness should continue:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">ai-jail ai-memory run --yolo</span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Order matters. <code>ai-jail</code> stays on the outside so the launcher and child process remain inside the same sandbox. <code>ai-memory run</code> by itself manages the session, but it doesn&rsquo;t create a sandbox.</p>
<p><code>--yolo</code> gets rid of the harness&rsquo;s approval ceremony. ai-jail handles containment: the current project is read-write, home is replaced with tmpfs, necessary parts of agent state are mounted selectively, and sensitive directories such as <code>.ssh</code>, <code>.gnupg</code>, and <code>.aws</code> stay outside the jail. The new support also keeps ai-memory&rsquo;s local state writable so hooks can maintain spools and cursors between runs.</p>
<p>ai-jail recognizes both the <code>ai-memory</code> layer and the selected harness. If you have Codex-specific global configuration, for example, it still applies when the actual command is <code>ai-memory run codex</code>. Even the status-bar redraw adjustment understands that the child is Codex.</p>
<p>This combination takes care of both annoyances at once: the agent stops asking for confirmation on every command, and the session stops belonging to the agent. You get the speed without handing over your entire home directory.</p>
<h2>One more thing: ai-usagebar grew too<span class="hx:absolute hx:-mt-20" id="one-more-thing-ai-usagebar-grew-too"></span>
    <a href="#one-more-thing-ai-usagebar-grew-too" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>When I published the <a href="/en/2026/05/24/i-built-a-waybar-widget-for-omarchy-to-monitor-llm-usage-ai-usagebar/">original ai-usagebar</a>, it monitored Claude, Codex, Z.AI, and OpenRouter in a Waybar widget or TUI. Version 0.14.0 already covers <strong>eleven usage, spending, or balance integrations</strong>.</p>
<p>Kimi got the two pieces of information that really matter for coding: weekly subscription quota and the rolling five-hour window. Kilo, Novita, Moonshot, and Grok show remaining balance. A separate Anthropic Console integration shows API spending for the month without conflating it with the Claude Code subscription. It makes clear that the Cost API doesn&rsquo;t include Priority Tier.</p>
<p>You can also register multiple Anthropic accounts, see weekly limits for specific models such as Fable, and get a pace marker. The bar doesn&rsquo;t turn red just because it reached 40%; it compares the percentage spent with how much of the window has passed. If I used 40% in 20% of the week, I&rsquo;m moving too fast. That&rsquo;s the useful information.</p>
<p>The project outgrew Waybar. It has a native macOS menu bar app, a GNOME extension, and a standalone TUI. The newest addition is a local Claude Code context monitor: I press <code>c</code>, choose one of the recent sessions, and see how much of the window it has consumed. It reads limited tails from local JSONL files and doesn&rsquo;t invent a percentage when it can&rsquo;t determine the window size.</p>
<p>In my workflow, the three end up working together. <code>ai-usagebar</code> shows which subscription still has room. <code>ai-memory run</code> switches harnesses without throwing away the work. <code>ai-jail</code> lets the chosen one run in YOLO without unrestricted access to the machine.</p>
<h2>Updating<span class="hx:absolute hx:-mt-20" id="updating"></span>
    <a href="#updating" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>The installation pages for all three projects cover every method, including AUR, Homebrew, and release binaries:</p>
<ul>
<li><a href="https://github.com/akitaonrails/ai-memory"target="_blank" rel="noopener">ai-memory</a></li>
<li><a href="https://github.com/akitaonrails/ai-jail"target="_blank" rel="noopener">ai-jail</a></li>
<li><a href="https://github.com/akitaonrails/ai-usagebar"target="_blank" rel="noopener">ai-usagebar</a></li>
</ul>
<p>After updating ai-memory, reinstall the hooks for the harnesses you plan to use in managed mode. The three main ones in my case:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">ai-memory install-hooks --agent claude-code --apply
</span></span><span class="line"><span class="cl">ai-memory install-hooks --agent codex --apply
</span></span><span class="line"><span class="cl">ai-memory install-hooks --agent opencode --apply</span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Crush doesn&rsquo;t need a hook in managed mode; it receives context through a temporary file configured only for the launched process. The <a href="https://github.com/akitaonrails/ai-memory/blob/main/docs/managed-workstreams.md"target="_blank" rel="noopener">managed workstreams documentation</a> covers installation, privacy, recovery, and native arguments for each adapter.</p>
<h2>Conclusion<span class="hx:absolute hx:-mt-20" id="conclusion"></span>
    <a href="#conclusion" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>A month ago, ai-memory could already turn a session into a wiki and hand off to the next agent. Now it can manage the line of work itself: adopt an existing session, keep one native session per harness, carry visible history, resume each client in its own format, and keep the entire ledger searchable.</p>
<p>For me, that&rsquo;s the value. The code contains the implementation that won. The session contains the decisions, failed experiments, gotchas, unexpected bugs, and changes of mind that produced that implementation. Throwing all of it away every time you change providers is wasteful.</p>
<p>A raw transcript doesn&rsquo;t solve the problem by itself either. It&rsquo;s large, repetitive, and expensive to stuff into every context. ai-memory keeps the evidence, delivers only the recent delta, and uses consolidation to turn what deserves to survive into short Markdown pages.</p>
<p>There are still new formats to support, platform rough edges, and plenty of testing ahead. The difference is that there is now a real foundation, with an acceptance test that calls actual harnesses, 14 outside contributors with merged PRs in a little over a month, and daily use pushing the design forward.</p>
<p>I rent LLMs and subscriptions from whoever is delivering the best service today. My project&rsquo;s session stays with me.</p>
]]></content:encoded><category>ai-memory</category><category>coding-agents</category><category>ai-jail</category><category>ai-usagebar</category></item><item><title>ai-memory: long-term memory (Karpathy Wiki) and self-improvement (Hermes) for your projects</title><link>https://akitaonrails.github.io/en/2026/06/16/ai-memory-long-term-memory-karpathy-wiki-self-improvement-hermes-projects/</link><guid isPermaLink="true">https://akitaonrails.github.io/en/2026/06/16/ai-memory-long-term-memory-karpathy-wiki-self-improvement-hermes-projects/</guid><pubDate>Tue, 16 Jun 2026 10:00:00 -0300</pubDate><description>&lt;p&gt;Yesterday I published a post about how &lt;a href="https://akitaonrails.github.io/en/2026/06/14/ai-memory-emergent-architecture-malleable-software/"&gt;ai-memory became a living example of emergent architecture&lt;/a&gt;. That one was more about process: how a small tool I built for myself grew, through real contributions, into a multi-user, multi-platform system with support for several agents and a bunch of edge cases that only appear when real people start using it.&lt;/p&gt;
&lt;p&gt;Today I want to talk about the other side: &lt;strong&gt;what this is useful for day to day&lt;/strong&gt;, and how the project now incorporates an idea inspired by &lt;strong&gt;&lt;a href="https://github.com/NousResearch/hermes-agent"target="_blank" rel="noopener"&gt;Hermes Agent&lt;/a&gt;&lt;/strong&gt;: a self-improvement loop with validation, an audit trail, and an optional manual review mode when you want more control.&lt;/p&gt;</description><content:encoded><![CDATA[<p>Yesterday I published a post about how <a href="/en/2026/06/14/ai-memory-emergent-architecture-malleable-software/">ai-memory became a living example of emergent architecture</a>. That one was more about process: how a small tool I built for myself grew, through real contributions, into a multi-user, multi-platform system with support for several agents and a bunch of edge cases that only appear when real people start using it.</p>
<p>Today I want to talk about the other side: <strong>what this is useful for day to day</strong>, and how the project now incorporates an idea inspired by <strong><a href="https://github.com/NousResearch/hermes-agent"target="_blank" rel="noopener">Hermes Agent</a></strong>: a self-improvement loop with validation, an audit trail, and an optional manual review mode when you want more control.</p>
<p>If you dropped in cold, the sequence so far is:</p>
<ol>
<li>First I wrote about <a href="/en/2026/05/18/ai-agent-memory-karpathy-llm-wiki-agentmemory/">agent memory, Karpathy LLM Wiki, and agentmemory</a>. Back then I was still evaluating the original <a href="https://github.com/rohitg00/agentmemory"target="_blank" rel="noopener"><code>agentmemory</code></a>.</li>
<li>Then I published the main post: <a href="/en/2026/05/23/i-built-memory-system-for-coding-agents-ai-memory/">I built a memory system for coding agents: ai-memory</a>. That one explains the foundation of the project.</li>
<li>In the <a href="/en/2026/05/24/akita-ai-toolkit-ai-jail-ai-memory-ai-usagebar/">AI toolkit post</a>, I placed ai-memory next to <code>ai-jail</code> and <code>ai-usagebar</code>: small tools for real pain points when you use agents every day.</li>
<li>Yesterday came the <a href="/en/2026/06/14/ai-memory-emergent-architecture-malleable-software/">emergent architecture</a> post, showing how the project evolved with contributors.</li>
</ol>
<p>This post is the practical continuation. ai-memory turns long development sessions into a <strong>project wiki</strong> that an agent can query weeks later, without turning you into the human cache for project context.</p>
<h2>The real problem: long sessions become long amnesia<span class="hx:absolute hx:-mt-20" id="the-real-problem-long-sessions-become-long-amnesia"></span>
    <a href="#the-real-problem-long-sessions-become-long-amnesia" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Anyone using <a href="https://docs.anthropic.com/en/docs/claude-code/overview"target="_blank" rel="noopener">Claude Code</a>, <a href="https://github.com/openai/codex"target="_blank" rel="noopener">Codex</a>, <a href="https://opencode.ai/"target="_blank" rel="noopener">OpenCode</a>, <a href="https://cursor.com/"target="_blank" rel="noopener">Cursor</a>, <a href="https://github.com/google-gemini/gemini-cli"target="_blank" rel="noopener">Gemini CLI</a>, or any of these agents knows the cycle. You start a session, explain the project, show the important files, correct a hallucination, find a trap, decide on an architecture, run tests, fail, fix, run again. After two hours, the agent is finally warmed up. It knows what not to do. It knows where the holes are. It knows that one function looks wrong but exists for legacy compatibility. It knows the test only passes if service X is running first.</p>
<p>Then the session ends.</p>
<p>The next day you open another agent, or the same agent in another window, or you switch from Claude Code to Codex because you want to compare. And it starts again. &ldquo;No, this project uses that.&rdquo; &ldquo;No, we already tried that.&rdquo; &ldquo;No, that API does not exist.&rdquo; &ldquo;No, that file is generated.&rdquo; You become the agent&rsquo;s cache.</p>
<p>A large context window only helps up to a point. It belongs to the current session, not to the whole month of work. And raw context is still raw context. Dumping one hundred thousand tokens of logs into a prompt is different from having a short page that says:</p>
<ul>
<li>decision: SQLite is a derived index, markdown is the source of truth;</li>
<li>trap: on Windows, do not trust inode, use our own index;</li>
<li>rule: do not edit <code>content/_index.md</code> by hand, run the generator;</li>
<li>procedure: to publish a new post, write PT first, humanize, validate Hugo, translate only after approval.</li>
</ul>
<p>That is useful memory. Not a transcript. A synthesis.</p>
<h2>The mental model: Karpathy Wiki<span class="hx:absolute hx:-mt-20" id="the-mental-model-karpathy-wiki"></span>
    <a href="#the-mental-model-karpathy-wiki" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>The name I like for this pattern is what Karpathy called an <strong><a href="https://gist.github.com/karpathy/442a6bf555914893e9891c11519de94f"target="_blank" rel="noopener">LLM Wiki</a></strong>: instead of depending on raw history, you maintain a versioned markdown wiki that the agent can query. Small pages, stable names, separated by type of knowledge. The agent does not need to remember everything. It needs to know how to search.</p>
<figure>
  <a href="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/2026/06/15/ai-memory-hermes/architecture-overview.svg">
    <img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/2026/06/15/ai-memory-hermes/architecture-overview.svg" alt="ai-memory architecture diagram: agent clients send hooks and MCP calls to the server, which writes to a markdown wiki and keeps SQLite as a derived index." />
  </a>
  <figcaption>ai-memory architecture overview. The source diagram is in <a href="https://github.com/akitaonrails/ai-memory/blob/main/docs/architecture-overview.svg">docs/architecture-overview.svg</a>.</figcaption>
</figure>
<p>ai-memory implements this with a simple idea: hooks capture what happened, the server organizes that material into a markdown wiki, and agents query that wiki when they need to continue the work.</p>
<p>Some pages are session summaries. Others become decisions, traps, procedures, or project rules. The user does not need to memorize the taxonomy. The point is that knowledge stops being trapped inside the chat window and starts existing as readable files.</p>
<p>Notice that last part: markdown is the source of truth. You can open it in Obsidian, <code>grep</code> it, version it, back it up with <code>rsync</code>, inspect a git diff. SQLite helps with search, but it is a derived index. If I throw the database away tomorrow, the system can rebuild the index from the wiki.</p>
<p>This is where I get stubborn. I want a file I can read, not a black box of embeddings that &ldquo;maybe&rdquo; remembers.</p>
<h2>The base: memory that crosses agents<span class="hx:absolute hx:-mt-20" id="the-base-memory-that-crosses-agents"></span>
    <a href="#the-base-memory-that-crosses-agents" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>From early on, ai-memory solved the main pain: <strong>context that survives the agent you happened to be using</strong>.</p>
<p>You could end a Claude Code session, open Codex in the same directory, and the next agent would receive a short summary of where things stopped, which questions were still open, and which next steps made sense.</p>
<p>On top of that, the agent could query the wiki before answering. Instead of depending only on what still fits in the context window, it could search old decisions, known traps, recent pages, and permanent project rules.</p>
<p>In practice, the agent stops guessing about architecture. It can ask: &ldquo;what did we decide about auth?&rdquo;, &ldquo;did we already try Redis here?&rdquo;, &ldquo;what was the Docker trap in this project?&rdquo; And the answer does not come back as a thousand raw events. It comes back as a wiki page.</p>
<p>In software projects, this matters because the most useful knowledge is usually not &ldquo;which file exists.&rdquo; The agent can find that with <code>grep</code>. The expensive knowledge is <strong>why</strong> something is that way. Why we did not use library X. Why this test is strange. Why the CI config has an exception. Why that refactor was postponed.</p>
<p>That is what long-term memory needs to preserve.</p>
<h2>What came from real use<span class="hx:absolute hx:-mt-20" id="what-came-from-real-use"></span>
    <a href="#what-came-from-real-use" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Yesterday I mentioned some numbers and thanked contributors, but it is worth calling out the newer capabilities because they changed the shape of the project. ai-memory stopped being &ldquo;my local daemon&rdquo; and became something you can run on a homelab or shared server.</p>
<p>The short version of the changes is:</p>
<ul>
<li><strong>It works for one person or a team.</strong> The system now understands users, projects, and workspaces. That makes it possible to run it on a homelab or shared server without mixing clients, repositories, and sessions.</li>
<li><strong>Scoping became predictable.</strong> A <code>.ai-memory.toml</code> file can say which project a directory belongs to. That helps with monorepos, worktrees, consulting, and personal/work separation.</li>
<li><strong>More agents can participate.</strong> Beyond Claude Code, Codex, and OpenCode, there is support for Cursor, Gemini CLI, <a href="https://antigravity.google/docs/hooks"target="_blank" rel="noopener">Antigravity CLI</a>, <a href="https://x.ai/cli"target="_blank" rel="noopener">Grok Build CLI</a>, <a href="https://docs.openclaw.ai/"target="_blank" rel="noopener">OpenClaw</a>, <a href="https://github.com/can1357/oh-my-pi"target="_blank" rel="noopener">Oh My Pi/OMP</a>, <a href="https://code.visualstudio.com/docs/copilot/overview"target="_blank" rel="noopener">VS Code GitHub Copilot</a>, and <a href="https://claude.ai/download"target="_blank" rel="noopener">Claude Desktop</a>. Some have full hooks, others can only query through MCP, but all of them can benefit from the same wiki.</li>
<li><strong>Administration and recovery became less fragile.</strong> Renaming or moving projects, restoring pages, rebuilding the index, using the web UI, and auditing changes are boring to explain, but important once the tool becomes part of daily work.</li>
</ul>
<p>I will not go through every detail here. That is what the <a href="https://github.com/akitaonrails/ai-memory/tree/main/docs"target="_blank" rel="noopener">GitHub documentation</a> is for. The important shift is the category change: this stopped being my local daemon and became shareable project memory.</p>
<p>This came from real use. Djalma Júnior, wlech, Pedro de Freitas Jr, Mauro Couto de Paiva, Gustavo Cateim, Lucas Oliveira, Pablo Winter, azevedo-luis, zanlucathiago, and others pushed the project into cases I had not planned for. That is how software grows without becoming PowerPoint architecture: need pulls the architecture, not the other way around.</p>
<h2>Auto-improve: sessions become memory<span class="hx:absolute hx:-mt-20" id="auto-improve-sessions-become-memory"></span>
    <a href="#auto-improve-sessions-become-memory" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Today, ai-memory has a safe self-improvement loop: when an LLM provider is configured, a background job can review new sessions, separate noise from real learning, and turn useful lessons into durable wiki pages.</p>
<p>That is what matters for the user: you do not need to remember to open a notes file at the end of the day, or manually write &ldquo;session learnings.&rdquo; If the session revealed a decision, a reproducible trap, or a procedure worth repeating, the system can promote it into project memory.</p>
<p>Under the hood, it uses the consolidated session, looks for strong signals, asks an LLM to suggest small edits, validates paths, evidence, size, and confidence, records the proposal in an audit trail, and applies the write through the normal wiki path.</p>
<p>If you want human review before the final write, set <code>[auto_improve] require_approval = true</code>. Then proposals stay pending until someone reviews, approves, or rejects them.</p>
<p>In the architecture diagram above, this sits on the maintenance side, in the work that depends on an LLM provider. It is not in the hot hook path. That is intentional. Hooks need to capture quickly, return 202 or 429, and get out of the way. LLM review is a different class of work.</p>
<p>The important detail: <strong>this does not enter the agent&rsquo;s hot path</strong>.</p>
<p>The user keeps working normally. Hooks capture the session. The handoff stays short and actionable. auto-improve runs as maintenance: it looks back, identifies what deserves to survive, and turns learning into queryable memory. The feature exists to answer one question:</p>
<blockquote>
  <p>&ldquo;What did this session teach us that is worth turning into permanent memory?&rdquo;</p>

</blockquote>
<p>And the answer becomes reusable knowledge, with proposal trail and evidence, not a loose guess inside the prompt.</p>
<p>That may sound small, but it is the difference between useful memory and an agent polluting your project with confident junk. If you let an LLM write a rule every time something goes wrong, in one week your wiki becomes a graveyard of superstition: &ldquo;never use tool X,&rdquo; &ldquo;always run command Y,&rdquo; &ldquo;library Z is broken.&rdquo; Many of those problems were temporary: wrong PATH, expired token, network down, outdated dependency, a bug fixed five minutes later.</p>
<p>Bad memory is worse than no memory. No memory makes you ask. Bad memory gives you false certainty.</p>
<h2>What Hermes Agent is<span class="hx:absolute hx:-mt-20" id="what-hermes-agent-is"></span>
    <a href="#what-hermes-agent-is" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>The inspiration came from <strong>Hermes Agent</strong>, which treats learning as part of the normal agent cycle. After doing the work, it can look back and ask: &ldquo;did this create any memory or skill that will help next time?&rdquo;</p>
<p>What interested me was the separation. The agent does the work first. Then, in the background, it reviews what happened. There is also slower maintenance that looks for stale, duplicated, or low-value knowledge. One loop learns from the session; the other cleans the garden.</p>
<p>That separation avoids the common mistake of creating a magical daemon that changes everything all the time. It sounds powerful, but it becomes impossible to trust. If you want the details, I left them in the <a href="https://github.com/akitaonrails/ai-memory/blob/main/docs/auto-improvement-loop.md"target="_blank" rel="noopener">auto-improvement loop documentation</a>.</p>
<h2>How we adapted Hermes to ai-memory<span class="hx:absolute hx:-mt-20" id="how-we-adapted-hermes-to-ai-memory"></span>
    <a href="#how-we-adapted-hermes-to-ai-memory" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>ai-memory does not copy Hermes literally. Hermes works with memories and skills. ai-memory works with wiki pages. So the adaptation is simple: when a session teaches something useful, the system tries to turn that into a small, readable, queryable page.</p>
<p>The LLM suggests, but the product imposes boundaries. The suggestion needs evidence, a valid path, reasonable size, and minimum confidence. That keeps a messy session from contaminating the whole wiki.</p>
<p>The current shape is this:</p>
<ol>
<li>The session ends and becomes <code>sessions/&lt;id&gt;.md</code>, as before.</li>
<li>A background job reviews eligible completed sessions after the first-run watermark and configured minimum age.</li>
<li>The reviewer looks for decisions, traps, procedures, and rules worth keeping.</li>
<li>The system validates the suggestion and records an audit trail.</li>
<li>By default, the memory enters the wiki; if you want, you can require manual review first.</li>
</ol>
<p>That trail is the missing piece between &ldquo;the LLM suggested it&rdquo; and &ldquo;this became project truth.&rdquo; Project memory cannot be a black box.</p>
<h2>What should become memory<span class="hx:absolute hx:-mt-20" id="what-should-become-memory"></span>
    <a href="#what-should-become-memory" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>This part matters more than the tool: not everything that happens in a session deserves to become permanent memory.</p>
<p>What is worth keeping is whatever helps the next agent work better: a decision with future consequences, a reproducible trap, a procedure that will repeat, an explicit user preference, or an important project pattern.</p>
<p>What is not worth keeping is noise: a test command, a transient error, a failure caused by that day&rsquo;s environment, or a whole session narrative that is already preserved under <code>sessions/</code>.</p>
<p>That filter is the difference between a wiki that helps and a wiki that gets in the way. auto-improve does not exist to capture more things. It exists to <strong>selectively promote</strong> what deserves to move out of the episodic layer and into durable project memory.</p>
<h2>Hooks, MCP, and prompts: the part that makes it usable<span class="hx:absolute hx:-mt-20" id="hooks-mcp-and-prompts-the-part-that-makes-it-usable"></span>
    <a href="#hooks-mcp-and-prompts-the-part-that-makes-it-usable" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>The other half of the system is less glamorous, but it is what makes the thing feel natural. The user works normally. Hooks capture the session cycle. MCP gives the agent a way to query memory. And the instruction block in <code>CLAUDE.md</code> or <code>AGENTS.md</code> teaches when to use all of it.</p>
<p>When the integration is complete, the experience becomes almost invisible: you close one session, open another tool, and the next agent can orient itself. When a client only supports MCP, it can still query the wiki, even if it cannot capture the full lifecycle.</p>
<p>The important detail is not the specific hook format of each tool. That is in the <a href="https://github.com/akitaonrails/ai-memory/blob/main/docs/install.md"target="_blank" rel="noopener">installation documentation</a>. The important part is that ai-memory tries to hide those differences and give the agent a simple behavior: before deciding, consult memory; when it learns something durable, preserve it.</p>
<h2>Why this makes coding sessions smarter<span class="hx:absolute hx:-mt-20" id="why-this-makes-coding-sessions-smarter"></span>
    <a href="#why-this-makes-coding-sessions-smarter" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>The flow I want is this.</p>
<p>You open OpenCode in an old project. Before answering anything serious, it knows to query ai-memory. It finds an existing database decision. It finds a build trap. It finds a handoff from the last agent saying the test failed in <code>PaymentImporter</code>. You do not need to retell the whole soap opera.</p>
<p>During the session, hooks record what happens. At the end, the session becomes a short narrative. If it was a rich session, the auto-improve job can turn the lessons into pages like:</p>
<ul>
<li><code>gotchas/payment-importer-timezone.md</code>;</li>
<li><code>decisions/use-ledger-table-for-reconciliation.md</code>;</li>
<li><code>procedures/run-importer-smoke-test.md</code>.</li>
</ul>
<p>In the default mode, this enters as validated, auditable memory. In manual mode, you inspect the diff, approve, or reject. Next week, another agent can query it and avoid stepping into the same hole.</p>
<p>That is the cycle I want: <strong>work becomes knowledge, knowledge improves the next work</strong>. No prompt religion, no infinite context window, no blind trust in opaque memory.</p>
<h2>Be careful with the word &ldquo;auto&rdquo;<span class="hx:absolute hx:-mt-20" id="be-careful-with-the-word-auto"></span>
    <a href="#be-careful-with-the-word-auto" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>There is a marketing trap here. &ldquo;Self-improvement&rdquo; sounds like science fiction: the agent learns by itself and gets better forever. I do not want to sell that, because it becomes a lie quickly.</p>
<p>What exists today is much more grounded: a job that reviews sessions, suggests memory, validates the suggestion, keeps evidence, and applies through the normal wiki path. If you prefer, there is a manual review mode before the final write. And precisely because it is limited, it is useful. The active prompt and hook latency stay protected. The system observes, filters, validates, and leaves a trail.</p>
<p>That is the right boundary for a system like this right now. Auto-approval only after structural validation and evidence. Human review when the project needs it. Trust is earned with history, not enthusiasm.</p>
<h2>Closing<span class="hx:absolute hx:-mt-20" id="closing"></span>
    <a href="#closing" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>ai-memory started as a simple answer to a simple frustration: I got tired of re-explaining the same project to different agents. In a few weeks it became a versioned wiki, with hooks, MCP, handoff, multi-user mode, multi-workspace support, marker files, support for several CLIs, web UI, recovery, and now a Hermes-inspired self-improvement loop with validation and audit instead of blind faith in the LLM.</p>
<p>The philosophy is still the same: good memory organizes knowledge into small, readable, versioned, citable pages. It turns a long session into a decision, trap, procedure, or rule. It lets the next agent start where the previous one stopped.</p>
<p>If you use agents for real software projects, this is the bottleneck that starts hurting first: continuity. A better model alone will not fix it.</p>
<p>The repo is here: <a href="https://github.com/akitaonrails/ai-memory"target="_blank" rel="noopener">github.com/akitaonrails/ai-memory</a>. If you already use it with an LLM provider configured, update and let auto-improve work in the background on new completed sessions.</p>
<p>If you want manual review before applying, configure:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-toml" data-lang="toml"><span class="line"><span class="cl"><span class="p">[</span><span class="nx">auto_improve</span><span class="p">]</span>
</span></span><span class="line"><span class="cl"><span class="nx">require_approval</span> <span class="p">=</span> <span class="kc">true</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>In manual mode, do not accept everything. That is the point. Read, criticize, approve only what deserves to become memory. In the default mode, follow the audit trail when you want to understand what was promoted and why.</p>
]]></content:encoded><category>ai-memory</category><category>coding-agents</category><category>llms</category></item><item><title>ai-memory: Emergent Architecture and Malleable Software</title><link>https://akitaonrails.github.io/en/2026/06/14/ai-memory-emergent-architecture-malleable-software/</link><guid isPermaLink="true">https://akitaonrails.github.io/en/2026/06/14/ai-memory-emergent-architecture-malleable-software/</guid><pubDate>Sun, 14 Jun 2026 14:00:00 -0300</pubDate><description>&lt;p&gt;About three weeks ago I published the &lt;a href="https://akitaonrails.github.io/en/2026/05/23/i-built-memory-system-for-coding-agents-ai-memory/"&gt;post explaining ai-memory&lt;/a&gt;, my long-term memory system for coding agents. The core idea, for anyone who missed it: give Claude Code, Codex, OpenCode and the rest a shared brain that persists across sessions, a git-versioned wiki with FTS search, cross-agent handoff, and optional LLM consolidation. Every project isolated, running locally or self-hosted, without shipping your context to anybody&amp;rsquo;s cloud.&lt;/p&gt;
&lt;p&gt;So here&amp;rsquo;s the thing. In three weeks this little project grew in a way that deserves a post about the &lt;strong&gt;process&lt;/strong&gt; alone, because it became a living example of something I&amp;rsquo;ve been preaching for years: real software is grown, like a plant. Nobody builds good software piece by piece the way you snap a Lego together. Let me show you the numbers, and mostly the story they tell.&lt;/p&gt;</description><content:encoded><![CDATA[<p>About three weeks ago I published the <a href="/en/2026/05/23/i-built-memory-system-for-coding-agents-ai-memory/">post explaining ai-memory</a>, my long-term memory system for coding agents. The core idea, for anyone who missed it: give Claude Code, Codex, OpenCode and the rest a shared brain that persists across sessions, a git-versioned wiki with FTS search, cross-agent handoff, and optional LLM consolidation. Every project isolated, running locally or self-hosted, without shipping your context to anybody&rsquo;s cloud.</p>
<p>So here&rsquo;s the thing. In three weeks this little project grew in a way that deserves a post about the <strong>process</strong> alone, because it became a living example of something I&rsquo;ve been preaching for years: real software is grown, like a plant. Nobody builds good software piece by piece the way you snap a Lego together. Let me show you the numbers, and mostly the story they tell.</p>
<h2>The numbers, today<span class="hx:absolute hx:-mt-20" id="the-numbers-today"></span>
    <a href="#the-numbers-today" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>ai-memory has, in 24 days of life (from the first commit on May 21 until now):</p>
<ul>
<li><strong>482 commits</strong> on <code>main</code>, averaging 20 a day.</li>
<li><strong>26 people</strong> committed to the repo.</li>
<li><strong>10 Rust crates</strong> in the workspace.</li>
<li><strong>~62.7k lines</strong> of production Rust, plus <strong>~11k lines</strong> of tests in <code>tests/</code>, more than <strong>1,000 test functions</strong>, and 90 <code>#[cfg(test)]</code> modules scattered through the code.</li>
<li><strong>~19.7k lines</strong> of markdown documentation (<code>docs/</code>).</li>
<li><strong>70 pull requests</strong>, of which <strong>59 merged</strong> (84% acceptance).</li>
<li><strong>27 issues</strong>, <strong>100% closed</strong>.</li>
<li>We cut <code>v1.0.0</code> on June 12 and we&rsquo;re already on <code>v1.0.6</code>.</li>
</ul>
<p>Twenty-four days. Hold onto that number, because the interesting part isn&rsquo;t the final size, it&rsquo;s the way it got here.</p>
<h2>How it started: one of everything<span class="hx:absolute hx:-mt-20" id="how-it-started-one-of-everything"></span>
    <a href="#how-it-started-one-of-everything" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>ai-memory was born small and dumb on purpose. In the first two days I nailed down the whole skeleton: workspace bootstrap, MCP server, hook capture, cross-agent handoff, git wiki versioning, an LLM provider trait, embeddings. All of it running for <strong>one user, one machine, one workspace, one architecture</strong> (Linux, basically). No multi-user, no permissions, no scopes, no Windows or macOS support. It was my agent brain, on my machine, for me.</p>
<p>On day 3, when the <a href="https://github.com/akitaonrails/ai-memory"target="_blank" rel="noopener">first external contribution landed</a> (a fix from Lucas Oliveira for OpenAI-compatible provider URLs, PR #6), the project had <strong>102 commits and around 22.9k lines</strong> of source. Already the same 10 crates as today, but with a fraction of the functionality. It was a one-of-everything MVP that worked for me and nobody else.</p>
<p>And this is where most projects die, or worse, where most inexperienced programmers get it wrong.</p>
<h2>The Lego fallacy<span class="hx:absolute hx:-mt-20" id="the-lego-fallacy"></span>
    <a href="#the-lego-fallacy" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>There&rsquo;s a widespread belief, especially among people starting out, that you can design everything a piece of software <strong>will be</strong> before writing the first line. You sit down, plan the entire architecture, break it into neat little pieces with all the folders and layers and interfaces mapped out, and then build it piece by piece. When the last Lego brick clicks in, the software is done. Beautiful on paper.</p>
<p>In practice, it&rsquo;s the fastest road to rotting code. The sooner you crystallize a structure, the sooner it becomes a straitjacket. You predicted an elaborate permission system before having any users? Congrats, now you carry the weight of maintaining an abstraction nobody uses, and that&rsquo;s almost always wrong, because you designed it guessing the future instead of answering a real need. The inexperienced programmer over-engineers at the start, and no matter how much they plan, the result starts to rot fast, because they&rsquo;re solving problems that don&rsquo;t exist yet and getting wrong the ones that do.</p>
<p>I don&rsquo;t believe in software that finishes. I already wrote about this in <a href="/en/2026/03/01/software-is-never-done-4-projects-life-after-deploy-one-shot-prompt-myth/">&ldquo;Software Is Never Done&rdquo;</a>, and it connects straight to the original Agile methodologies, the real ones, before they turned into a corporate post-it ritual. Good software is a clay sculpture: malleable, always wet, that you keep adjusting and reshaping, and that never gets finished. It&rsquo;s clay you mold while it&rsquo;s being used. The Lego tower that one day clicks into place and is done is a fantasy.</p>
<h2>What the contributors built<span class="hx:absolute hx:-mt-20" id="what-the-contributors-built"></span>
    <a href="#what-the-contributors-built" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>And this is where the best part of open-sourcing it comes in. That one-of-everything MVP became a cross-platform, multi-user system because <strong>a lot of people</strong> put their hands on it. I want to thank them by name, because without these people the project would be a fraction of what it is:</p>
<p><a href="https://github.com/djalmajr"target="_blank" rel="noopener"><strong>Djalma Júnior</strong></a> drove a big chunk of the heavy architecture (multi-user, admin, cross-project recall), with 25 merged PRs. <a href="https://github.com/wblech"target="_blank" rel="noopener"><strong>wlech</strong></a> with dozens of commits. <a href="https://github.com/pedrofjr"target="_blank" rel="noopener"><strong>Pedro de Freitas Jr</strong></a> on embeddings and web fixes. <a href="https://github.com/mrpaiva"target="_blank" rel="noopener"><strong>Mauro Couto de Paiva</strong></a> and <a href="https://github.com/CaTeIM"target="_blank" rel="noopener"><strong>Gustavo Cateim</strong></a> drove a big part of the Windows support. <a href="https://github.com/pablowinck"target="_blank" rel="noopener"><strong>Pablo Winter</strong></a>, <a href="https://github.com/lucasliet"target="_blank" rel="noopener"><strong>Lucas Oliveira</strong></a> (author of the first external PR), and <strong>Said Rodrigues</strong>, among many others. Thank you so much, folks.</p>
<p>What those contributions added, the highlights:</p>
<ul>
<li><strong>Real Windows, macOS, and Linux support.</strong> What was Linux-only got macOS bash 3.2 compatibility, an NTFS file index for tracking inodes on Windows, and native per-platform hook commands.</li>
<li><strong>Frontend API (<code>/api/v1</code>) and a customizable web UI.</strong> It stopped being only MCP + CLI and got a real HTTP surface, with clickable wiki links and search by file path.</li>
<li><strong>Multi-user with attribution.</strong> A <code>users</code> table, writer/reader commands, and write attribution in the same SQL transaction as the data (<code>pages.author_id</code> + frontmatter).</li>
<li><strong>Multi-workspace and cross-project recall.</strong> Global search, links between wikis of different projects, and active-project isolation per session and per actor.</li>
<li><strong>More providers and more agents.</strong> Gemini, Copilot via OAuth, OpenAI-compat strict mode; plus support for Antigravity, Grok, and VS Code Copilot on top of the originals.</li>
<li><strong>Operational robustness.</strong> Checkpoint recovery, <code>reindex-from-wiki</code> to rebuild the index from the markdown, self-describing <code>_meta.md</code> manifests.</li>
</ul>
<p>Notice something: none of this was in the original plan. There was no original plan. Each of these features landed because someone needed it, opened an issue or a PR, and the structure gave way to make room. Multi-user wasn&rsquo;t predicted: it emerged.</p>
<h2>And only now did we stop to consolidate<span class="hx:absolute hx:-mt-20" id="and-only-now-did-we-stop-to-consolidate"></span>
    <a href="#and-only-now-did-we-stop-to-consolidate" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Here&rsquo;s the central point of the post. Over these three weeks, the code grew a little messy on purpose. When multi-user support came in, the logic for &ldquo;which workspace and project is this request aiming at&rdquo; ended up <strong>embedded right in the middle</strong> of several handlers in the MCP server, the web API, the admin, scattered and duplicated. Each spot resolved scope its own way. There was duplication. There was code that wasn&rsquo;t pretty. And that&rsquo;s fine, because it was working, and working for a lot of people.</p>
<p>Only <strong>after</strong> the software was already running on dozens of people&rsquo;s machines, across three operating systems, with real multi-user in production, did I stop and say: &ldquo;okay, now is a good time to refactor and rethink the internal wiring.&rdquo; The second-to-last big commit, <a href="https://github.com/akitaonrails/ai-memory"target="_blank" rel="noopener"><code>refactor: centralize scope auth and wiki consistency</code></a>, did exactly that, with 1,239 lines added and 249 removed, creating a central 601-line <code>ScopeResolver</code> and a consolidated <code>ActorContext</code>.</p>
<p>Look at the &ldquo;before.&rdquo; This scope-resolution snippet lived duplicated, with variations, across several methods:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-rust" data-lang="rust"><span class="line"><span class="cl"><span class="c1">// BEFORE: scope logic embedded, repeated in every handler
</span></span></span><span class="line"><span class="cl"><span class="kd">let</span><span class="w"> </span><span class="n">active</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="bp">self</span><span class="p">.</span><span class="n">active_project</span><span class="p">.</span><span class="n">get_for</span><span class="p">(</span><span class="n">actor</span><span class="p">);</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="k">if</span><span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="nb">Some</span><span class="p">(</span><span class="n">name</span><span class="p">)</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">explicit_project</span><span class="p">.</span><span class="n">map</span><span class="p">(</span><span class="kt">str</span>::<span class="n">trim</span><span class="p">).</span><span class="n">filter</span><span class="p">(</span><span class="o">|</span><span class="n">s</span><span class="o">|</span><span class="w"> </span><span class="o">!</span><span class="n">s</span><span class="p">.</span><span class="n">is_empty</span><span class="p">())</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="k">if</span><span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="nb">Some</span><span class="p">((</span><span class="n">active_ws</span><span class="p">,</span><span class="w"> </span><span class="n">_</span><span class="p">))</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">active</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="o">&amp;&amp;</span><span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="nb">Ok</span><span class="p">(</span><span class="nb">Some</span><span class="p">(</span><span class="n">pid</span><span class="p">))</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="bp">self</span><span class="p">.</span><span class="n">reader</span><span class="p">.</span><span class="n">find_project</span><span class="p">(</span><span class="n">active_ws</span><span class="p">,</span><span class="w"> </span><span class="n">name</span><span class="p">.</span><span class="n">to_string</span><span class="p">()).</span><span class="k">await</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="k">return</span><span class="w"> </span><span class="nb">Ok</span><span class="p">((</span><span class="n">active_ws</span><span class="p">,</span><span class="w"> </span><span class="n">pid</span><span class="p">));</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="k">if</span><span class="w"> </span><span class="n">active</span><span class="p">.</span><span class="n">map</span><span class="p">(</span><span class="o">|</span><span class="p">(</span><span class="n">ws</span><span class="p">,</span><span class="w"> </span><span class="n">_</span><span class="p">)</span><span class="o">|</span><span class="w"> </span><span class="n">ws</span><span class="p">)</span><span class="w"> </span><span class="o">!=</span><span class="w"> </span><span class="nb">Some</span><span class="p">(</span><span class="bp">self</span><span class="p">.</span><span class="n">workspace_id</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="o">&amp;&amp;</span><span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="nb">Ok</span><span class="p">(</span><span class="nb">Some</span><span class="p">(</span><span class="n">pid</span><span class="p">))</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="bp">self</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">            </span><span class="p">.</span><span class="n">reader</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">            </span><span class="p">.</span><span class="n">find_project</span><span class="p">(</span><span class="bp">self</span><span class="p">.</span><span class="n">workspace_id</span><span class="p">,</span><span class="w"> </span><span class="n">name</span><span class="p">.</span><span class="n">to_string</span><span class="p">())</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">            </span><span class="p">.</span><span class="k">await</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="k">return</span><span class="w"> </span><span class="nb">Ok</span><span class="p">((</span><span class="bp">self</span><span class="p">.</span><span class="n">workspace_id</span><span class="p">,</span><span class="w"> </span><span class="n">pid</span><span class="p">));</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="k">return</span><span class="w"> </span><span class="nb">Err</span><span class="p">(</span><span class="n">McpError</span>::<span class="n">internal_error</span><span class="p">(</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="fm">format!</span><span class="p">(</span><span class="s">&#34;project &#39;</span><span class="si">{name}</span><span class="s">&#39; not found in the active or default workspace&#34;</span><span class="p">),</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="nb">None</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="p">));</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="nb">Ok</span><span class="p">(</span><span class="n">active</span><span class="p">.</span><span class="n">unwrap_or</span><span class="p">((</span><span class="bp">self</span><span class="p">.</span><span class="n">workspace_id</span><span class="p">,</span><span class="w"> </span><span class="bp">self</span><span class="p">.</span><span class="n">project_id</span><span class="p">)))</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>And the &ldquo;after.&rdquo; The same resolution, now delegated to a single authority in the store crate:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-rust" data-lang="rust"><span class="line"><span class="cl"><span class="c1">// AFTER: one central resolver, one call
</span></span></span><span class="line"><span class="cl"><span class="k">fn</span> <span class="nf">scope_resolver</span><span class="p">(</span><span class="o">&amp;</span><span class="bp">self</span><span class="p">)</span><span class="w"> </span>-&gt; <span class="nc">ScopeResolver</span><span class="o">&lt;</span><span class="nb">&#39;_</span><span class="o">&gt;</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="n">ScopeResolver</span>::<span class="n">new</span><span class="p">(</span><span class="o">&amp;</span><span class="bp">self</span><span class="p">.</span><span class="n">reader</span><span class="p">,</span><span class="w"> </span><span class="bp">self</span><span class="p">.</span><span class="n">workspace_id</span><span class="p">,</span><span class="w"> </span><span class="bp">self</span><span class="p">.</span><span class="n">project_id</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="p">.</span><span class="n">with_writer</span><span class="p">(</span><span class="o">&amp;</span><span class="bp">self</span><span class="p">.</span><span class="n">writer</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="p">.</span><span class="n">with_active_project</span><span class="p">(</span><span class="o">&amp;</span><span class="bp">self</span><span class="p">.</span><span class="n">active_project</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="c1">// ... and each handler becomes this:
</span></span></span><span class="line"><span class="cl"><span class="bp">self</span><span class="p">.</span><span class="n">scope_resolver</span><span class="p">()</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="p">.</span><span class="n">resolve_current_or_project</span><span class="p">(</span><span class="n">explicit_project</span><span class="p">,</span><span class="w"> </span><span class="n">actor</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="p">.</span><span class="k">await</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="p">.</span><span class="n">map</span><span class="p">(</span><span class="n">ai_memory_store</span>::<span class="n">ResolvedScope</span>::<span class="n">as_tuple</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="p">.</span><span class="n">map_err</span><span class="p">(</span><span class="bp">Self</span>::<span class="n">scope_error</span><span class="p">)</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Three different methods that each used to carry 30 lines of embedded logic, with <code>lookup_ids</code>, workspace fallback, and their own error handling, collapsed into one call each. Alongside came the sibling commits: <code>harden multi-user admin auth boundaries</code> and <code>prevent scoped fallback bleed</code>. Centralizing permissions, workspace and user scope, and wiki consistency, all in one place, with a clear rule.</p>
<p>The detail that matters: <code>ScopeResolver</code> wasn&rsquo;t invented at the start of the project by guessing there&rsquo;d be multi-user one day. It was <strong>extracted</strong> from code that already existed, already worked, and had already shown, in practice, which patterns kept repeating. The abstraction came after the usage, not before. I let the structure emerge from the code, and only once it was obvious did I consolidate it.</p>
<h2>The right order: make it work, make it right, make it fast<span class="hx:absolute hx:-mt-20" id="the-right-order-make-it-work-make-it-right-make-it-fast"></span>
    <a href="#the-right-order-make-it-work-make-it-right-make-it-fast" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>This is the summary of everything. There&rsquo;s an old saying, attributed to Kent Beck, that I carry like a mantra: <strong>&ldquo;make it work, make it right, make it fast.&rdquo;</strong> Make it work, then make it right, then make it fast. In that order. Most inexperienced programmers want to make it &ldquo;right&rdquo; and &ldquo;fast&rdquo; before making it &ldquo;work,&rdquo; and so they invent rules with no code to justify the rule.</p>
<p>ai-memory followed the right order without me even thinking much about it. First I made it work for one person, simple scope. Then I made it work one feature at a time, refactoring and hardening the code along the way, but never falling into over-engineering and never rewriting from scratch to fit a preconceived structure. I let the current structures emerge from the code that was being added. That meant living with some duplication and some so-so code for a while, until that moment hit of &ldquo;okay, now it&rsquo;s time to refactor and rethink the wiring.&rdquo; And only now, with the software mature and in use, did I establish better patterns and rules for new code. Rules backed by real code, not by guesswork.</p>
<p>KISS, &ldquo;keep it simple,&rdquo; is about not solving a problem you don&rsquo;t have yet. It has nothing to do with writing little code. It&rsquo;s about letting architecture emerge from the code, not the other way around. You don&rsquo;t design the sculpture and pour the clay into the mold. You take the clay, start shaping, and the form appears as your hands work. The mold, if you ever need one, you build later, around the form that already exists.</p>
<p>Twenty-four days, 482 commits, 26 people, and none of them followed a diagram drawn on day 1. Because there was no diagram on day 1. And that&rsquo;s exactly why it worked.</p>
<p>ai-memory is open source and keeps changing every week: <a href="https://github.com/akitaonrails/ai-memory"target="_blank" rel="noopener">github.com/akitaonrails/ai-memory</a>. Want to help shape the next piece? There&rsquo;s an open issue waiting.</p>
]]></content:encoded><category>ai-memory</category><category>software-architecture</category><category>agile</category></item><item><title>Akita's AI Tips and Toolkit: ai-jail, ai-memory, ai-usagebar</title><link>https://akitaonrails.github.io/en/2026/05/24/akita-ai-tips-toolkit-ai-jail-ai-memory-ai-usagebar/</link><guid isPermaLink="true">https://akitaonrails.github.io/en/2026/05/24/akita-ai-tips-toolkit-ai-jail-ai-memory-ai-usagebar/</guid><pubDate>Sun, 24 May 2026 10:30:00 -0300</pubDate><description>&lt;p&gt;In last week&amp;rsquo;s post, &lt;a href="https://akitaonrails.github.io/en/2026/05/14/wrapping-up-my-ai-marathon-success-or-failure/"&gt;&amp;ldquo;Wrapping Up My AI Marathon: Success or Failure?&amp;rdquo;&lt;/a&gt;, I closed the first phase of my marathon. More than 600 hours of heavy coding-agent use, dozens of projects, hundreds of thousands of lines of code and documentation, and a pile of practical conclusions. Not marketing. Practical.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;ll repeat something important before someone starts cloning all my repositories thinking they are 1.0 products: most of the &lt;code&gt;frank-*&lt;/code&gt; projects on my GitHub are proofs of concept. Experiments. Some work well for me, in my environment, in my workflow. That does not mean they are ready to become a critical dependency in your company tomorrow morning. Want to play, contribute, study? Great. Just don&amp;rsquo;t confuse &amp;ldquo;I published it on GitHub&amp;rdquo; with &amp;ldquo;this is production ready.&amp;rdquo;&lt;/p&gt;</description><content:encoded><![CDATA[<p>In last week&rsquo;s post, <a href="/en/2026/05/14/wrapping-up-my-ai-marathon-success-or-failure/">&ldquo;Wrapping Up My AI Marathon: Success or Failure?&rdquo;</a>, I closed the first phase of my marathon. More than 600 hours of heavy coding-agent use, dozens of projects, hundreds of thousands of lines of code and documentation, and a pile of practical conclusions. Not marketing. Practical.</p>
<p>I&rsquo;ll repeat something important before someone starts cloning all my repositories thinking they are 1.0 products: most of the <code>frank-*</code> projects on my GitHub are proofs of concept. Experiments. Some work well for me, in my environment, in my workflow. That does not mean they are ready to become a critical dependency in your company tomorrow morning. Want to play, contribute, study? Great. Just don&rsquo;t confuse &ldquo;I published it on GitHub&rdquo; with &ldquo;this is production ready.&rdquo;</p>
<p>There are exceptions. <a href="https://github.com/akitaonrails/frankmd"target="_blank" rel="noopener">FrankMD</a>, for example, received a decent amount of contributions, tests, polish, real bug fixes, real use. Today it is much more stable than it was in the first post. Still, the point stands: these projects were born as a vibe-coding lab, not as a 3-year product plan with roadmap, enterprise support, and SLA.</p>
<p>This post is a roundup of what I learned in that lab. A few of my tools, a few habits, a few recommendations. Nothing mystical. No &ldquo;revolutionary new way to program.&rdquo; Old engineering with new tooling.</p>
<h2>First: stop collecting agents<span class="hx:absolute hx:-mt-20" id="first-stop-collecting-agents"></span>
    <a href="#first-stop-collecting-agents" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>If you are a normal developer, you do not need 12 agents, 40 wrappers, 7 orchestrators, and a Kubernetes diagram to choose who gets to write an <code>if</code>.</p>
<p>In practice, focus on <strong>Claude Code</strong>, <strong>Codex</strong>, or <strong>opencode</strong>. That&rsquo;s it.</p>
<p>Yes, Gemini CLI exists. Yes, Cursor exists. Yes, Windsurf, Crush, OpenClaw, Pi, Aider exist, and tomorrow another half-dozen will show up. I tested a bunch. Read my LLM benchmark posts, especially <a href="/en/2026/04/24/llm-benchmarks-parte-3-deepseek-kimi-mimo/">&ldquo;LLM Benchmarks Part 3: DeepSeek, Kimi, MiMo&rdquo;</a>. The conclusion is boring and obvious: today, the best cost-benefit options for heavy programming are <strong>Opus 4.7</strong> and <strong>GPT 5.5</strong> on subsidized Pro/Plus/Max plans. Nothing comes close when the job is spending several hours a day with a real coding agent.</p>
<p>Paying directly for tokens is expensive. Paying for a subsidized monthly plan is much cheaper. That&rsquo;s why I keep alternating between Claude Code and Codex: not because I want &ldquo;multi-agent architecture,&rdquo; but because the plans have limits and I work many hours in a row.</p>
<p>Are DeepSeek v4 and Kimi 2.6 cheaper? Yes. Are they usable? Yes. I like them for several cases. But for <strong>Agile Vibe Coding</strong> the way I&rsquo;ve been advocating since <a href="/en/2026/02/20/zero-to-post-production-in-1-week-using-ai-on-real-projects-behind-the-m-akita-chronicles/">&ldquo;From Zero to Post-Production in 1 Week&rdquo;</a>, they are still lacking. They stumble more on continuity, long refactors, tests, understanding the whole project. Can you use them? Sure. But if the goal is consistent productivity, Opus and GPT are still the bar.</p>
<p>Running an open-source model locally is neat. I played with that a lot in the <a href="/en/2026/03/31/minisforum-ms-s1-max-amd-ai-max-395-review/">Minisforum MS-S1 Max with AMD AI Max+ 395 review</a>. For one-shots, studying, playing with local inference, it&rsquo;s fun. For Agile Vibe Coding all day, every day, it is still not practical. Latency, context, quality, setup maintenance, VRAM, all of it collects tax.</p>
<p>Running multiple LLMs in parallel is not practical either, the whole &ldquo;planner + executor + reviewer + judge&rdquo; routine. I tested that in <a href="/en/2026/04/25/llm-benchmarks-vale-a-pena-misturar-2-modelos/">&ldquo;LLM Benchmarks: Is It Worth Mixing 2 Models?&rdquo;</a>. The idea looks nice on paper. In practice, it increases cost, latency, error surface, and the gain does not pay for the complexity.</p>
<p>The secret is not having a bunch of agents. Forget OpenClaw or Pi for day-to-day programming. The secret is engineering process. XP. Tests. <a href="/en/2026/04/20/clean-code-for-ai-agents/">Clean Code for AI Agents</a>. CI. Pair programming. Constant refactoring. Small code. Automated deploy. Fast feedback.</p>
<p>Tools help. Engineering wins.</p>
<h2>ai-jail: autonomy with a fence<span class="hx:absolute hx:-mt-20" id="ai-jail-autonomy-with-a-fence"></span>
    <a href="#ai-jail-autonomy-with-a-fence" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>The first project I want to highlight is <a href="https://github.com/akitaonrails/ai-jail"target="_blank" rel="noopener">ai-jail</a>. It is a sandbox wrapper to run AI agents with restricted system access. On Linux it uses <code>bubblewrap</code> (<code>bwrap</code>) and Landlock. On macOS it uses <code>sandbox-exec</code>. The idea is simple: the agent sees the environment it needs to work, but does not go rummaging through your whole system.</p>
<p>Do I use it every day? Yes. Do I use it always? No.</p>
<p>When I know I am not doing anything risky, I open <code>claude</code> or <code>codex</code> directly. If I am touching a simple project, just running tests, editing markdown, refactoring local stuff, often I do not bother. In more than 600 hours of intense Agile Vibe Coding, more than half a million lines of code and documentation, I never had one of those folklore cases of an LLM destroying my host system in some unrecoverable way.</p>
<p>And look, I explicitly used agents to configure my Omarchy. ZSH, Hyprland, Waybar, terminal configs, login scripts, all of it. They never did anything I did not ask for.</p>
<p>Those stories of &ldquo;the agent deleted my whole home by itself&rdquo; make me raise an eyebrow. In my experience, when you ask it to delete something dangerous, Claude and Codex ask for confirmation. You have to say yes. If you said yes without reading, that is not LLM black magic. That is user in zombie mode.</p>
<p>Nothing is guaranteed, of course. Hence ai-jail.</p>
<p>My favorite use is combining <code>ai-jail</code> with the harness&rsquo; no-brakes mode:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">ai-jail claude --dangerously-allow-permissions
</span></span><span class="line"><span class="cl">ai-jail codex --dangerously-bypass-approvals-and-sandbox</span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>It sounds contradictory, but it makes sense. I remove the confirmation friction inside the agent, but put a fence at the operating-system level. The agent can work fast inside the project, but the host filesystem is essentially read-only. The current directory is read-write. Whatever I explicitly map with <code>--rw-map</code> is also read-write. The rest is not to be touched.</p>
<p>The ai-jail README sums it up well: it is a sandbox wrapper for agents like Claude Code, GPT Codex, OpenCode, and Crush. On the first run it creates a <code>.ai-jail</code> in the project, which can be committed. It supports <code>--dry-run</code> to see mounts before executing, <code>--lockdown</code> for a stricter mode, <code>--private-home</code> to hide real dotfiles, <code>--mask .env</code> to hide sensitive files inside the project itself, and isolated browser profiles for Chromium/Firefox.</p>
<p>Do not sell this as absolute security. Process sandboxing is not a VM. Kernel bugs exist. Side channels exist. macOS has limitations. The README itself is clear: if you need to isolate a truly hostile workload, use a disposable VM. I do not use ai-jail as &ldquo;military-grade armor.&rdquo; I use it as another layer, good enough for a development workflow.</p>
<p>And even inside the project, everything is Git. I push frequently to GitHub or to my private Gitea. So the realistic worst case is the agent destroying the project directory. Annoying? Yes. Catastrophic? No. I clone again. I come back from the remote. I redo what was local. If <code>.git</code> gets corrupted, I delete everything and clone again.</p>
<p>Secrets also have a copy outside. <code>.env</code>, tokens, keys, everything that matters sits in Bitwarden. <a href="/en/2025/09/10/omarchy-2-0-bitwarden-self-hosted-vaultwarden/">Self-hosted in Vaultwarden</a>, of course. So if I lose the local directory, I did not lose the keys to the kingdom.</p>
<p>The most common risk is not the agent deleting everything. It is you leaking a secret to Git. That happened to me more than once. You run <code>git add .</code>, forget a <code>.env</code>, push to the remote, congratulations. It happens. That&rsquo;s why you must look at <code>git status</code>, <code>git diff --cached</code>, and think before pushing.</p>
<p>Even when it happens, LLMs are very competent at helping rewrite history. I ask them to clean the secret from Git, force-push, review that it disappeared, and then I rotate the key. It is not pretty, but it is manageable.</p>
<p>So yes, I recommend using Claude/Codex with dangerous permissions <strong>inside</strong> ai-jail. Is there a 0.001% chance of an unrecoverable accident? There is. But if you are a good engineer, that should not kill you. I have layers: automatic Btrfs snapshots, restic to my NAS, NAS archiving offsite to AWS Glacier, remote Git, Bitwarden. No tool replaces backups.</p>
<h2>ai-memory: context that survives the harness<span class="hx:absolute hx:-mt-20" id="ai-memory-context-that-survives-the-harness"></span>
    <a href="#ai-memory-context-that-survives-the-harness" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>The second is <a href="https://github.com/akitaonrails/ai-memory"target="_blank" rel="noopener">ai-memory</a>, which I explained in detail in <a href="/en/2026/05/23/i-built-memory-system-for-coding-agents-ai-memory/">&ldquo;I Built a Memory System for Coding Agents: ai-memory&rdquo;</a>.</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/2026/05/23/ai-memory/ai-memory-logo.png" alt="ai-memory project logo: circular pictogram with a stylized chip opening “wings” like libraries/pages on each side, next to the italic ai-memory text."  loading="lazy" /></p>
<p>The motivation is simple: harnesses lose context. Claude Code compacts. Codex compacts. opencode compacts. The session ends. You open another agent and it does not know what happened in the last 4 hours. If you only use one harness, maybe it does not bother you much. If you alternate between Claude and Codex like I do, it gets annoying fast.</p>
<p>I wanted a long-term memory consolidator that worked across different harnesses. Something that allowed handoff between Claude, Codex, and opencode without me manually writing <code>HANDOFF.md</code> every time. Something that captured prompts, tool calls, and session events through hooks, consolidated them into markdown pages, indexed with SQLite/FTS5, and exposed everything through MCP when the agent needed to query it.</p>
<p>Another motivator was what I explained in <a href="/en/2026/04/06/rag-is-dead-long-context/">&ldquo;Is RAG Dead? Long Context, Grep, and the End of the Mandatory Vector DB&rdquo;</a>. For code projects, simple text almost always solves more than fancy vector DB architecture. Markdown, <code>grep</code>, SQLite FTS5, long context, and good files in <code>docs/</code> already take you far. ai-memory follows that line: compile memory into text, leave it on disk, index it simply, and only call an LLM when consolidation is worth it.</p>
<p>ai-memory was not made to be a user-browsable knowledge base. It has a read-only web UI, yes, but that is for auditing and inspection. The memory is optimized for LLM consumption. It is an internal wiki the harness can query when it thinks it needs to. It is a place where I can explicitly ask &ldquo;save this for the next session&rdquo; and expect it to survive longer than Claude or Codex&rsquo;s default compaction.</p>
<p><img src="https://raw.githubusercontent.com/akitaonrails/ai-memory/main/docs/web-projects-home.png" alt="ai-memory web UI homepage showing detected projects, page counts, last activity, and the warning that memory is optimized for LLM consumption, not human-curated documentation."  loading="lazy" /></p>
<p>The README sums it up well: coding agents lose all context when the session ends; ai-memory gives them a shared persistent wiki. Every prompt, tool call, and decision can be captured automatically. At the end of the session, relevant pages are rewritten as coherent narrative. In the next session, another agent can receive a handoff already prepended into the context.</p>
<p>This is useful when you close Claude at 6pm, open Codex the next day in the same directory, and want it to know you were testing session cookies because JWT rotation had run into trouble. Or when you return to a project six weeks later and do not remember why you discarded Redis.</p>
<p>But do not confuse it with canonical documentation. If you did important research you do not want to lose, ask the agent to write markdown in <code>docs/</code> inside the project. Architecture decision, benchmark, library analysis, deploy runbook, anything that must survive with guarantees should become an explicit file in the repo. That is simpler, auditable, and versioned.</p>
<p>ai-memory covers the middle band: transient information that might matter later. A weird bug that appeared. The reasoning that led to a decision. An environment gotcha. A session summary. Things you do not want to turn into official docs yet, but also do not want to throw away.</p>
<p>It is still beta. I use it in personal production, but it needs many more users beating on it. The most polished integrations today are Claude Code, Codex, and opencode. Gemini CLI, OpenClaw, and exotic MCP clients still need more testing. PRs are welcome. Bug reports too. &ldquo;I installed it and it broke on my setup&rdquo; is exactly the kind of feedback that reveals a wrong assumption.</p>
<h2>ai-usagebar: knowing when to switch horses<span class="hx:absolute hx:-mt-20" id="ai-usagebar-knowing-when-to-switch-horses"></span>
    <a href="#ai-usagebar-knowing-when-to-switch-horses" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>As I said above, I prefer using Anthropic and OpenAI&rsquo;s subsidized plans. The problem is that if you do real Agile Vibe Coding, you hit limits. Daily limit. Weekly limit. Session limit. Limit that changes. Limit that does not show up clearly anywhere.</p>
<p>I was using <a href="https://github.com/mryll/claudebar"target="_blank" rel="noopener">claudebar</a>, which is good, but only covers Claude. I wanted to see the main vendors in one place. That became <a href="https://github.com/akitaonrails/ai-usagebar"target="_blank" rel="noopener">ai-usagebar</a>, which I introduced in <a href="/en/2026/05/24/i-built-a-waybar-widget-for-omarchy-to-monitor-llm-usage-ai-usagebar/">&ldquo;I Built a Waybar Widget for Omarchy to Monitor LLM Plan Usage: ai-usagebar&rdquo;</a>.</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/2026/05/24/ai-usagebar/ai-usagebar-waybar.png" alt="Waybar widget showing “cld 29% · 1h 12m” in the top-right corner, with the tooltip open showing the Claude Max 20x plan: Session 29%, Weekly 47%, Sonnet only 0%, Extra usage $0.00 against a $1100 limit, and the last-updated time."  loading="lazy" /></p>
<p>It is a Waybar widget and Rust TUI to monitor Anthropic Claude, OpenAI Codex/ChatGPT, Z.AI GLM, and OpenRouter usage. For Claude and OpenAI, it reads the OAuth credentials the official CLIs already wrote. For Z.AI and OpenRouter, it uses API keys. It shows session percentage, reset, limits, balance, and lets you switch the primary vendor.</p>
<p>The value is banal and therefore useful: I glance at the bar and know whether I should continue in Claude, hand off to Codex, or top up OpenRouter credit. I do not want to discover I hit the weekly limit in the middle of a large refactor.</p>
<p>There is also a standalone TUI:</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/2026/05/24/ai-usagebar/ai-usagebar-tui-openai.png" alt="ai-usagebar-tui on the OpenAI tab running in a terminal: Codex 5h and weekly gauges, Credits block with message-count ranges, Claude / OpenAI / GLM (Z.AI) / OpenRouter tabs at the top, key hints in the footer."  loading="lazy" /></p>
<p>If you do not use Omarchy, Hyprland, or Waybar, you can still run <code>ai-usagebar-tui</code> in any terminal. SSH, tmux, normal terminal, whatever. The bar is convenience. The TUI is the universal form.</p>
<h2>ghpending: GitHub pending stuff without the ritual<span class="hx:absolute hx:-mt-20" id="ghpending-github-pending-stuff-without-the-ritual"></span>
    <a href="#ghpending-github-pending-stuff-without-the-ritual" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>After the marathon, I ended up with dozens of <code>ai-*</code> and <code>frank-*</code> repos on GitHub. That creates an annoying problem: issues and pull requests start appearing. A contributor opens a PR. Someone reports a bug. Someone else sends a suggestion. If I have to open the browser, enter repo by repo, filter tab by tab, I will postpone it. And if I postpone it, I go weeks without answering contributors.</p>
<p>Yes, I could use <code>gh</code>, the official GitHub CLI. I do use it. But I wanted something dumber and faster: a short command to print a digest of everything pending in the repos I chose to monitor. That became <a href="https://github.com/akitaonrails/ghpending"target="_blank" rel="noopener">ghpending</a>, which I described in <a href="/en/2026/05/23/i-built-a-cli-to-check-my-github-pending-stuff-ghpending/">&ldquo;I Built a CLI to Check My GitHub Pending Stuff: ghpending&rdquo;</a>.</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/2026/05/23/ghpending/ghpending-screenshot.png" alt="ghpending terminal output: compact table listing each monitored repo with open issue and pull request counts, latest activity author, and how long ago it happened."  loading="lazy" /></p>
<p>That is it: <code>ghpending add</code> to choose repos, <code>ghpending</code> to see the digest, <code>ghpending list</code>, <code>ghpending rm</code>. Without auth it works with GitHub&rsquo;s 60 req/h anonymous limit. With <code>GITHUB_TOKEN=$(gh auth token) ghpending</code>, it goes up to 5,000 req/h.</p>
<p>The point is not replacing GitHub. It is reducing friction. If I can run one command in the terminal and see &ldquo;there are 3 PRs and 2 issues to look at,&rdquo; I look. If it depends on browser ritual, notifications, and tabs, it waits.</p>
<p>And Claude/Codex are very good at this kind of work. You can ask:</p>
<blockquote>
  <p>&ldquo;Check the open pull requests, review the code, see if it compiles, run the tests, add tests if missing, rebase from master if needed, merge and close.&rdquo;</p>

</blockquote>
<p>Or:</p>
<blockquote>
  <p>&ldquo;Check the open issues, evaluate whether there is a real bug, reproduce it if possible, propose a fix, answer the user.&rdquo;</p>

</blockquote>
<p>They read the PR, understand the diff, run tests, rebase, solve simple conflicts, write the contributor response. You still keep your brain on. You are delegating mechanical work you already know how to do.</p>
<h2>Refactoring: ask explicitly, several times<span class="hx:absolute hx:-mt-20" id="refactoring-ask-explicitly-several-times"></span>
    <a href="#refactoring-ask-explicitly-several-times" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Claude and Codex are very good at refactoring, but do not assume they will do it automatically the way you would. I usually start projects or features with explicit instructions:</p>
<blockquote>
  <p>&ldquo;Use Rust best practices. Avoid unnecessary duplication. Modularize only where it makes sense. Add unit tests for every new feature. Follow <a href="/en/2026/04/20/clean-code-for-ai-agents/">Clean Code</a> principles. Do not create an abstraction before it is needed.&rdquo;</p>

</blockquote>
<p>After a large feature, a large fix, or a few hours of development, I stop and ask:</p>
<blockquote>
  <p>&ldquo;Now that we touched a lot of code, re-evaluate it carefully. Delete dead code. Refactor obvious duplication. Add missing tests. Remove magic numbers. Check if any modules are too large. Do not change behavior without tests.&rdquo;</p>

</blockquote>
<p>Before release:</p>
<blockquote>
  <p>&ldquo;Before publishing this version, do a sanity audit. Look for secret leaks, dangerous permissions, destructive commands, path traversal, unnecessary unwraps, missing validation, and anything that looks like an obvious vulnerability.&rdquo;</p>

</blockquote>
<p>Does that guarantee security? Of course not. Not even close. But it removes a lot of dumb mistakes. It is another layer. I like running this audit with Claude and then with Codex, because each one finds different things. Bugs still pass. Security is process, not a magic ritual.</p>
<h2>Disposable experiments: code got cheap<span class="hx:absolute hx:-mt-20" id="disposable-experiments-code-got-cheap"></span>
    <a href="#disposable-experiments-code-got-cheap" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Before choosing a library, framework, architecture, model, or service, I like creating <code>experiments/</code>.</p>
<p>Example:</p>
<blockquote>
  <p>&ldquo;Before choosing between Qwen and DeepSeek, create a disposable prototype in <code>experiments/</code> for an A/B test. Document the analysis in <code>docs/</code> with result, cost, latency, quality, and recommendation.&rdquo;</p>

</blockquote>
<p>This changed how I decide. Before, many engineering decisions became opinion, feeling, faith in somebody else&rsquo;s benchmark. Now code is cheap. I ask the agent to make two or three versions, run tests, measure, document, throw away what does not work.</p>
<p>Prototyping got genuinely fast. <a href="/en/2026/04/05/turning-youtube-into-a-karaoke-app-frank-karaoke/">Frank Karaoke</a> is a good example: turning YouTube into a karaoke app was the kind of idea I would maybe leave in a mental list for months, waiting for &ldquo;a free weekend&rdquo; that never arrives. Now I can open <code>experiments/</code>, ask for a rough prototype, test the technical path, and decide whether it deserves to become a project. Look at my other 2026 posts about <code>frank-*</code> and <code>ai-*</code> projects: almost all of them started like this, as disposable code that proved something before earning a name.</p>
<p>But cheap prototypes do not mean one-shot. I already wrote in <a href="/en/2026/04/15/how-to-talk-to-claude-code-effectively/">&ldquo;Why LLMs Aren&rsquo;t Giving You the Result You Expect&rdquo;</a>: a good prompt is an iterative conversation. You provide context, show references, point out constraints, read the result, correct direction, ask for a rewrite. If you throw in a vague sentence and expect a finished product, that&rsquo;s on you.</p>
<p>I learned this by taking a beating too. In the <a href="/en/2026/03/05/my-first-vibe-code-failure-frank-yomik/">Frank Yomik</a> post I described my first real vibe-coding failure: when the direction is wrong, insisting on the same prompt just digs the hole deeper. Sometimes you need to reduce scope, isolate the problem, create a test, change strategy. LLM does not turn a bad plan into good engineering.</p>
<p>And there are domains where you need to study along with it. In the <a href="/en/2026/04/23/driveclub-shadps4-e-ia-como-aprender/">DriveClub and shadPS4</a> post, AI almost sent me in every wrong direction because the problem required understanding rendering, gamma, shaders, buffers. The tool helps you explore, but you still decide whether the explanation makes sense. If you do not understand enough to verify, you are just accepting a pretty guess.</p>
<p>That is also why I keep repeating the idea from <a href="/en/2026/03/01/software-is-never-done-4-projects-life-after-deploy-one-shot-prompt-myth/">&ldquo;Software Is Never Done&rdquo;</a>: deploy is not the finish line. The prototype becomes a product when it handles bug reports, maintenance, refactoring, docs, releases, rollbacks, users complaining. LLM helps a lot with that boring cycle. But the cycle still exists.</p>
<p>If it is testable, test it. If it can be measured, measure it. If it cannot be measured, at least write down the assumptions. The important thing is not choosing just because it &ldquo;seems better.&rdquo;</p>
<p>Cheap code also means detachment. Make code to throw away. Make an ugly prototype. Make a disposable benchmark. Ask the agent to document what it learned in <code>docs/decision-qwen-vs-deepseek.md</code>, then delete <code>experiments/</code> if you want. The document stays. The lesson stays.</p>
<p>LLMs are also very good at documentation. Use that. Ask it to document everything. Why we chose PostgreSQL instead of SQLite in this case. Why the deploy uses a multi-stage Docker image. Why the service runs behind Cloudflare Tunnel. Why that sysctl exists. Even if you delete half of it later, the cost of writing fell near zero.</p>
<h2>Automated deploy or you will stop maintaining it<span class="hx:absolute hx:-mt-20" id="automated-deploy-or-you-will-stop-maintaining-it"></span>
    <a href="#automated-deploy-or-you-will-stop-maintaining-it" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Every project of mine that matters has automated build. Many run in my homelab, as I described in <a href="/en/2026/03/31/migrating-my-home-server-with-claude-code/">&ldquo;Migrating my Home Server with Claude Code&rdquo;</a>. Almost every project has a <code>bin/deploy</code> that builds a Docker image, pushes it, rotates it on the server, applies migration if needed, and validates healthcheck.</p>
<p>Claude and Codex are excellent at deploy. They read <code>bin/deploy</code>, understand Dockerfile, edit GitHub Actions, adjust release workflows, fix binary signing, update Homebrew taps, generate checksums. And yes, I ask Claude/Codex to SSH into my homelab and redeploy Docker containers. They are very good at that. ai-jail, for example, has GitHub Actions to build signed binaries for Linux and macOS.</p>
<p>If you have dozens of projects, the more automated the better. I rarely type admin commands in the terminal by myself. I ask the LLM to do it, observe, approve what is dangerous, and then ask:</p>
<blockquote>
  <p>&ldquo;Document what was done and why it was done.&rdquo;</p>

</blockquote>
<p>This applies to the homelab and my workstation. My Omarchy is customized through Claude: ZSH, Hyprland, Waybar, scripts, shortcuts, themes, integrations. Even my gaming/emulation setups fall into this, as I showed in the <a href="/en/2026/04/19/my-favorite-retro-racing-games-on-distrobox/">retro racing games running on Distrobox</a> post. This is a case where I normally do not use ai-jail, because I actually want to touch the host. So I look at commands, read diffs, approve slowly. Even then, I never had the agent break my system in an unrecoverable way. Quite the opposite. My PC has never been more stable and documented.</p>
<p>Days later, when I forget why I configured something that way, the context is in markdown, Git, ai-memory, or the project history itself. I can ask and the agent has something to pull from.</p>
<h2>Even this post was written this way<span class="hx:absolute hx:-mt-20" id="even-this-post-was-written-this-way"></span>
    <a href="#even-this-post-was-written-this-way" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>This is how I write these posts now. I dump a huge messy block from my brain into Claude. I ask it to read recent posts to calibrate style. I ask it to check the projects directly and elaborate the technical parts. I ask it to use the latest screenshots, upload to S3 when needed, link previous posts, review the tone.</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/2026/05/24/ai-toolkit/writing-this-post.png" alt="Terminal screenshot with the raw prompt used to write this post: a huge block of instructions, links, opinions, and technical details dumped into the agent before final editing."  loading="lazy" /></p>
<p>Then I read and edit. I cut what sounds generic. I replace sentences that sound like release notes. I put my rants back in. The result is still my text; I just spend energy on what matters: deciding what to say, correcting nuance, cutting nonsense.</p>
<h2>&ldquo;But did you test Pi?&rdquo;<span class="hx:absolute hx:-mt-20" id="but-did-you-test-pi"></span>
    <a href="#but-did-you-test-pi" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Every time I mention an LLM or LLM tool, someone shows up in the comments with the same question: &ldquo;but did you test Pi?&rdquo;, &ldquo;but did you test DeepSeek?&rdquo;, &ldquo;but what about Qwen?&rdquo;, &ldquo;but what about the new model that came out yesterday?&rdquo; Every. Single. Time.</p>
<p>It is annoying as fuck. And almost always it comes from three kinds of people: someone who tested nothing and wants to outsource the work, someone who already chose a tool and wants me to validate their choice, or a fanboy treating an LLM vendor like a soccer team. They all sound the same. NPC repeating tutorial dialogue.</p>
<p>Software engineers should not decide based on other people&rsquo;s opinions. Not even mine. If you choose a tool because &ldquo;Akita said so,&rdquo; you understood it wrong. I advocate Claude Code and Codex because I used them for hundreds of hours, in real projects, publishing code and post-mortems of what worked and what failed. And even then I did not stop at opinion.</p>
<p>I built my own automated benchmark: <a href="https://github.com/akitaonrails/llm-coding-benchmark"target="_blank" rel="noopener">llm-coding-benchmark</a>. I update it when a popular vendor releases a new version. I run comparable scenarios. I publish results. Then I adjust my opinion based on the data. That gives me enough ground to say that, in my workflow, Opus and GPT keep winning. Not because I woke up wanting to defend some billionaire company&rsquo;s logo.</p>
<p>If your first reaction was &ldquo;but did you test Qwen?&rdquo;, great. Test it yourself. Run the benchmark. Create a better scenario. Send a PR. Show numbers. Show cost. Show latency. Show where it failed. Show where it won. Bring new data.</p>
<p>Loose opinion is irrelevant. &ldquo;It works for me&rdquo; does not scale. &ldquo;I like it better&rdquo; does not matter. &ldquo;In my one-shot prompt it was better&rdquo; is an anecdote. Engineering starts when something can be reproduced, compared, and acted on.</p>
<p>So it is simple: bring actionable data or shut the hell up. I do not need vendor fan clubs in the comments. I need people testing, measuring, and contributing new results.</p>
<h2>Final checklist<span class="hx:absolute hx:-mt-20" id="final-checklist"></span>
    <a href="#final-checklist" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Short summary, because this post is already long:</p>
<ul>
<li>Focus on Claude Code, Codex, or opencode. Stop collecting agents.</li>
<li>Use Opus 4.7 and GPT 5.5 through Pro/Plus/Max plans when daily productivity matters.</li>
<li>DeepSeek, Kimi, and local models are useful, but still do not replace the main workflow.</li>
<li>Agile Vibe Coding is XP with LLM: tests, <a href="/en/2026/04/20/clean-code-for-ai-agents/">Clean Code</a>, CI, pair programming, and deploy.</li>
<li>Use <code>ai-jail</code> when you want agent autonomy with a filesystem fence.</li>
<li>Combine <code>ai-jail</code> with dangerous Claude/Codex permissions when the project is protected by Git.</li>
<li>Have real backup: Btrfs snapshots, restic, NAS, offsite, Git, Bitwarden.</li>
<li>Review <code>git add</code>, <code>git diff --cached</code>, and pushes so you do not leak secrets.</li>
<li>Use <code>ai-memory</code> for transient context and handoff between agents.</li>
<li>Write canonical documentation in <code>docs/</code> when information needs to survive with guarantees.</li>
<li>Use <code>ai-usagebar</code> to know when to switch from Claude to Codex, or when to top up OpenRouter.</li>
<li>Use <code>ghpending</code> so you do not abandon issues and PRs.</li>
<li>Ask for refactoring explicitly after large features.</li>
<li>Run a security audit before release, preferably with more than one model.</li>
<li>Create disposable prototypes in <code>experiments/</code> before deciding by faith.</li>
<li>If you disagree with a benchmark, run <a href="https://github.com/akitaonrails/llm-coding-benchmark"target="_blank" rel="noopener">llm-coding-benchmark</a> and bring new data.</li>
<li>Document decisions in markdown. Code got cheap. Documentation too.</li>
<li>Automate deploy. If it depends on a manual ritual, you will stop doing it.</li>
</ul>
<p>In the end, it is the same advice as always: tools change, engineering does not. LLM increases leverage. If you already had good habits, you will produce more. If you did not, you will just produce mess faster.</p>
<p>And yes, this changes the interface of the work. I already wrote about that in <a href="/en/2026/04/11/vs-code-is-the-new-punch-card/">&ldquo;VS Code Is the New Punch Card&rdquo;</a>: polishing pixels in an editor is now old-programmer nostalgia. The hard part is writing intent correctly, reviewing execution without being lazy, measuring results, throwing away cheap code, and not confusing opinion with data.</p>
]]></content:encoded><category>ai-jail</category><category>ai-memory</category><category>ai-usagebar</category><category>ghpending</category></item><item><title>I Built a Memory System for Coding Agents: ai-memory</title><link>https://akitaonrails.github.io/en/2026/05/23/i-built-memory-system-for-coding-agents-ai-memory/</link><guid isPermaLink="true">https://akitaonrails.github.io/en/2026/05/23/i-built-memory-system-for-coding-agents-ai-memory/</guid><pubDate>Sat, 23 May 2026 16:30:00 -0300</pubDate><description>&lt;p&gt;&lt;img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/2026/05/23/ai-memory/ai-memory-logo.png" alt="ai-memory project logo: circular pictogram with a stylized chip opening “wings” like books/pages on each side, next to the ai-memory wordmark in italics." loading="lazy" /&gt;&lt;/p&gt;
&lt;p&gt;Five days ago I &lt;a href="https://akitaonrails.github.io/en/2026/05/18/ai-agent-memory-karpathy-llm-wiki-agentmemory/"&gt;wrote a long post on coding-agent memory&lt;/a&gt; where I recommended &lt;a href="https://github.com/rohitg00/agentmemory"target="_blank" rel="noopener"&gt;agentmemory&lt;/a&gt; as the answer. After a week running it in personal production, I&amp;rsquo;m walking it back. This post explains what went wrong and the open source project I started building to fix it: &lt;a href="https://github.com/akitaonrails/ai-memory"target="_blank" rel="noopener"&gt;ai-memory&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;Why agentmemory didn&amp;rsquo;t pan out&lt;span class="hx:absolute hx:-mt-20" id="why-agentmemory-didnt-pan-out"&gt;&lt;/span&gt;
&lt;a href="#why-agentmemory-didnt-pan-out" class="subheading-anchor" aria-label="Permalink for this section"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;agentmemory has the right ideas (Karpathy&amp;rsquo;s LLM Wiki, tiered consolidation, automatic-capture hooks, MCP) but the implementation has structural problems that hurt in daily use. The main ones I hit in practice:&lt;/p&gt;</description><content:encoded><![CDATA[<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/2026/05/23/ai-memory/ai-memory-logo.png" alt="ai-memory project logo: circular pictogram with a stylized chip opening “wings” like books/pages on each side, next to the ai-memory wordmark in italics."  loading="lazy" /></p>
<p>Five days ago I <a href="/en/2026/05/18/ai-agent-memory-karpathy-llm-wiki-agentmemory/">wrote a long post on coding-agent memory</a> where I recommended <a href="https://github.com/rohitg00/agentmemory"target="_blank" rel="noopener">agentmemory</a> as the answer. After a week running it in personal production, I&rsquo;m walking it back. This post explains what went wrong and the open source project I started building to fix it: <a href="https://github.com/akitaonrails/ai-memory"target="_blank" rel="noopener">ai-memory</a>.</p>
<h2>Why agentmemory didn&rsquo;t pan out<span class="hx:absolute hx:-mt-20" id="why-agentmemory-didnt-pan-out"></span>
    <a href="#why-agentmemory-didnt-pan-out" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>agentmemory has the right ideas (Karpathy&rsquo;s LLM Wiki, tiered consolidation, automatic-capture hooks, MCP) but the implementation has structural problems that hurt in daily use. The main ones I hit in practice:</p>
<ul>
<li><strong>BM25 reindex on every restart.</strong> The index persists to a file (<code>mem:index:bm25.bin</code>) through a remote KV called iii-engine. With few observations it flies, but pass 10K observations and <code>state::set</code> starts timing out, the file stays at ~96 empty bytes, and every restart pays ~5 minutes rebuilding from scratch (<a href="https://github.com/rohitg00/agentmemory/issues/309"target="_blank" rel="noopener">issue #309</a>, still open).</li>
<li><strong>5-second data-loss window.</strong> All persistence flows through a 5s debounce on <code>IndexPersistence</code>. When the 30s <code>state::set</code> timeout blows up, the Node process dies taking everything that was in memory with it (<a href="https://github.com/rohitg00/agentmemory/issues/204"target="_blank" rel="noopener">#204</a>).</li>
<li><strong>Two config-read paths in the same codebase.</strong> <code>process.env</code> directly in one place, <code>getMergedEnv()</code> in another. The classic &ldquo;I set the variable and nothing changed&rdquo; (<a href="https://github.com/rohitg00/agentmemory/issues/456"target="_blank" rel="noopener">#456</a>).</li>
<li><strong>Wrong hook key on ~47% of Claude Code tool calls.</strong> The hook reads <code>data.tool_output</code>, but Claude Code sends <code>tool_response</code>. Six weeks of observations silently vanishing (<a href="https://github.com/rohitg00/agentmemory/issues/539"target="_blank" rel="noopener">#539</a>).</li>
<li><strong>Engine runs from the caller&rsquo;s working directory.</strong> Windows users thought they&rsquo;d lost memories because every terminal opened the state store in a different path (<a href="https://github.com/rohitg00/agentmemory/issues/303"target="_blank" rel="noopener">#303</a>, still open).</li>
</ul>
<p>There&rsquo;s more. I wrote it all up <a href="https://github.com/akitaonrails/ai-memory/blob/main/docs/issues-agentmemory.md"target="_blank" rel="noopener">here</a> in my research repo. The author is responsive, the repo has 15.7K stars, and even so the architecture chosen (TypeScript MCP + separate iii-engine Rust binary + 4 ports, 3 processes, in-memory indexes persisted via remote KV) accumulates a class of bug you can&rsquo;t close without rewriting half the system. The shape of the problem is structural, not a lack of effort from the maintainer.</p>
<p>Same story with every other solution I tried: either it&rsquo;s incomplete, or too fixated on some specific technology (proprietary vector DB, a knowledge graph that needs Neo4j, an elaborate LLM pipeline), or it demands that the user yell <code>write_note</code> every time something&rsquo;s worth saving. None of them &ldquo;stay out of the way&rdquo; enough for me to trust them in long sessions.</p>
<h2>What I wanted from day one<span class="hx:absolute hx:-mt-20" id="what-i-wanted-from-day-one"></span>
    <a href="#what-i-wanted-from-day-one" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>When I started my <a href="/en/2026/05/14/wrapping-up-my-ai-marathon-success-or-failure/">37-day vibe coding marathon</a> back in February, I knew I needed some kind of knowledge organizer. It took more than 500 hours of experimentation to crystallize what I actually wanted.</p>
<p>If you use just one of the three (only Claude Code, or only Codex, or only opencode) and stay there, you probably don&rsquo;t need anything extra. The three of them already do a reasonable job of managing memory within the session. Claude Code has three levels of compaction (time-gap microcompact, token-threshold autocompact, experimental sessionMemoryCompact). Codex has per-model auto_compact_token_limit. opencode has anchored compaction with a 20K buffer. I covered this in detail <a href="/en/2026/05/18/ai-agent-memory-karpathy-llm-wiki-agentmemory/">in the previous post</a>.</p>
<p>The one extra discipline worth adopting in that scenario is to keep a <code>docs/</code> folder in the project with markdown files organized by topic, and ask the agent to save there when something important happens. Research you don&rsquo;t want to redo, known gotchas, why you picked option A over B. Works. Takes discipline.</p>
<p>The problem shows up for people like me, jumping between agents in the same project. I use Claude Code by default (I find the harness, the subagent orchestrator, and the long-task planning superior). But when Claude gets stuck, I fire up Codex in the same directory just to &ldquo;stir things up.&rdquo; Codex thinks more &ldquo;outside the box&rdquo; and sometimes finds a solution Claude didn&rsquo;t see. Then I go back to Claude to implement carefully.</p>
<p>This back-and-forth between agents is where external memory really matters. Without it:</p>
<ul>
<li>You close Claude Code, open Codex in the same directory, and Codex knows nothing about the last 4 hours of discussion.</li>
<li>You have to manually ask Claude to write a handoff note to <code>./HANDOFF.md</code>, then ask Codex to read it. Every time.</li>
<li>Projects you left untouched for weeks: you open them again, forgot why you decided against Redis, forgot what the bug in library X was.</li>
</ul>
<p>Karpathy nailed the concept in his <a href="https://gist.github.com/karpathy/442a6bf555914893e9891c11519de94f"target="_blank" rel="noopener">LLM Wiki</a>, which I went deep on in the previous post. But there&rsquo;s one specific line from the gist that stuck in my head:</p>
<blockquote>
  <p><code>index.md</code> is &ldquo;surprisingly good at ~100 sources, a few hundred pages, no embeddings needed&rdquo;.</p>

</blockquote>
<p>That line summed up what I wanted. <strong>You don&rsquo;t need complicated technology.</strong> Simple storage (markdown in git), simple index (SQLite with FTS5 and links), simple install (a binary or container), automatic use (hooks that fire on their own), zero maintenance (memory decays without the user touching anything).</p>
<p>That&rsquo;s why I started ai-memory.</p>
<h2>Research before code<span class="hx:absolute hx:-mt-20" id="research-before-code"></span>
    <a href="#research-before-code" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Instead of just diving into code, we dug through the source and issues of the relevant projects to understand what each one got right and wrong. The research lives in the <a href="https://github.com/akitaonrails/ai-memory/tree/main/docs"target="_blank" rel="noopener">repo itself</a>:</p>
<ul>
<li><strong><a href="https://github.com/akitaonrails/ai-memory/blob/main/docs/research-karpathy-llm-wiki.md"target="_blank" rel="noopener">research-karpathy-llm-wiki.md</a></strong> — what Karpathy literally wrote, separated from what the community attributes (paraphrasing) to him. Three core principles: compile instead of retrieve, three layers (raw / wiki / schema), three operations (ingest / query / lint). The conceptual blueprint.</li>
<li><strong><a href="https://github.com/akitaonrails/ai-memory/blob/main/docs/research-agentmemory.md"target="_blank" rel="noopener">research-agentmemory.md</a></strong> — technical breakdown of agentmemory: four consolidation tiers (working → episodic → semantic → procedural), supersession with <code>is_latest=false</code> instead of delete, exponential decay, cluster reflection. I kept agentmemory&rsquo;s ideas; I changed the implementation.</li>
<li><strong><a href="https://github.com/akitaonrails/ai-memory/blob/main/docs/research-basic-memory.md"target="_blank" rel="noopener">research-basic-memory.md</a></strong> — Python, MCP-native, plain markdown on disk. The model is explicitly manual: the agent calls <code>write_note</code> when it decides to save. Good storage model, terrible capture model (it depends on the agent remembering to call).</li>
<li><strong><a href="https://github.com/akitaonrails/ai-memory/blob/main/docs/research-cognee.md"target="_blank" rel="noopener">research-cognee.md</a></strong> — cognify pipeline (extract → chunk → graph + summarize → embed → persist) with a triple knowledge graph + vector + relational store. Excellent for a well-funded enterprise agent that wants semantic relationships between entities. Way too heavy for &ldquo;coding session memory.&rdquo;</li>
</ul>
<p>The synthesis I took away: <strong>agentmemory has the right ideas. The rest is execution.</strong></p>
<p>The idea I like most from agentmemory, which it inherited partially from LLM Wiki v2, is the <strong>sleep-style consolidation</strong>: short memory keeps raw detail, long memory keeps consolidating and summarizing, and long-term memory that nobody touches eventually gets forgotten. It doesn&rsquo;t pile up cruft. There&rsquo;s <code>accessCount</code>, geometric exponential decay, spaced-repetition reinforcement. It&rsquo;s similar to (and inspired by) what a human does while sleeping.</p>
<p>In ai-memory I kept that structure but swapped the engineering underneath:</p>
<ul>
<li><strong>TypeScript → single Rust binary.</strong> No separate remote KV. No 3 processes. One Rust binary, with a data directory and an Axum server.</li>
<li><strong>Persistent index in SQLite + FTS5.</strong> Native. No reindex on every restart. WAL mode, 5s busy_timeout.</li>
<li><strong>Single writer in a dedicated thread via mpsc.</strong> No 5s loss window, no 30s timeout blowing up.</li>
<li><strong>Plain markdown on disk as source of truth.</strong> SQLite is just a derived index. You can open the wiki in Obsidian. You can <code>grep</code> it. You can version it with git (and it versions automatically).</li>
<li><strong>Per-project isolation in the physical layout on disk.</strong> <code>&lt;wiki_root&gt;/&lt;workspace_id&gt;/&lt;project_id&gt;/...</code> keyed by stable UUIDs. Renaming a project is a column update. Deleting a project is <code>rm -rf</code> on a subdir. Same page name in two projects doesn&rsquo;t collide.</li>
<li><strong>Embedding and LLM are optional.</strong> Without a provider key, the system still works with FTS5, link expansion, and raw-observation fallback. Add embeddings when you want vector re-ranking, and Claude Haiku or GPT-5.4-mini when you want quality consolidated pages.</li>
</ul>
<h2>How it works day to day<span class="hx:absolute hx:-mt-20" id="how-it-works-day-to-day"></span>
    <a href="#how-it-works-day-to-day" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Interaction with the agents happens through two mechanisms: <strong>hooks/extensions</strong> (automatic capture) and <strong>MCP</strong> (on-demand query).</p>
<p>Claude Code and Codex use shell hooks. OpenCode uses a TypeScript plugin. OMP/Pi uses a TypeScript extension. Cursor and Gemini CLI use JSON lifecycle config. They all emit equivalent events (<code>SessionStart</code>, <code>UserPromptSubmit</code>, <code>PreToolUse</code>, <code>PostToolUse</code>, <code>PreCompact</code>, <code>Stop</code>, <code>SessionEnd</code>) as fire-and-forget POSTs to ai-memory&rsquo;s HTTP server (running at <code>127.0.0.1:49374</code> by default). The agent never waits. If ai-memory is down, the session continues normally, just without capture. Claude Desktop and OpenClaw are MCP-only: they can query memory, but they don&rsquo;t automatically capture lifecycle events.</p>
<p>On the agent side, the MCP server exposes tools the LLM can call when it sees fit:</p>
<table>
  <thead>
      <tr>
          <th>You say…</th>
          <th>Agent calls…</th>
          <th>What happens</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>&ldquo;Have we talked about X?&rdquo;</td>
          <td><code>memory_query</code></td>
          <td>FTS5 + link/graph-neighbour RRF over compiled wiki pages, optional vector re-ranking, and raw-observation fallback when wiki search misses</td>
      </tr>
      <tr>
          <td>(before proposing architecture) implicit</td>
          <td><code>memory_query</code></td>
          <td>The routing snippet tells the agent to check past decisions before proposing something new</td>
      </tr>
      <tr>
          <td>&ldquo;Catch me up&rdquo; / &ldquo;I&rsquo;ve been away&rdquo;</td>
          <td><code>memory_explore</code></td>
          <td>Prose digest. Verbosity scales with time since last activity</td>
      </tr>
      <tr>
          <td>&ldquo;Where did we leave off?&rdquo;</td>
          <td>(handoff already in context)</td>
          <td>The <code>SessionStart</code> hook already prepended the handoff before your first prompt</td>
      </tr>
      <tr>
          <td>&ldquo;Save context for next session&rdquo;</td>
          <td><code>memory_handoff_begin</code></td>
          <td>Writes a terse handoff with <code>open_questions</code> + <code>next_steps</code></td>
      </tr>
      <tr>
          <td>&ldquo;Consolidate this session&rdquo;</td>
          <td><code>memory_consolidate</code></td>
          <td>Manual trigger of what SessionEnd does automatically</td>
      </tr>
      <tr>
          <td>&ldquo;Audit the wiki&rdquo;</td>
          <td><code>memory_lint</code></td>
          <td>Detects stale pages, contradictions, suggests rules</td>
      </tr>
      <tr>
          <td>&ldquo;Show me stats&rdquo;</td>
          <td><code>memory_status</code> / <code>memory_briefing</code></td>
          <td>Counts pages, sessions, observations, and recent activity</td>
      </tr>
  </tbody>
</table>
<p>The routing snippet that lands in <code>CLAUDE.md</code> (or <code>AGENTS.md</code> for Codex/OpenCode/Cursor/Gemini/OMP) is what teaches the agent when to call which tool. You install it with one command: ask the agent &ldquo;install the ai-memory routing in this project&rdquo; and it invokes the MCP tool <code>memory_install_self_routing</code>, gets back the canonical snippet, and writes it to the right file. Idempotent.</p>
<h2>Handoff between agents in action<span class="hx:absolute hx:-mt-20" id="handoff-between-agents-in-action"></span>
    <a href="#handoff-between-agents-in-action" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Here&rsquo;s the concrete scenario that motivated the project:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>$ claude
&gt; &#34;Refactoring auth. JWT rotation is broken; I&#39;m going to try
   session cookies as an alternative.&#34;
[works for an hour]
&gt; /exit

$ codex   # same directory, hours or days later
[ai-memory&#39;s SessionStart hook fetches the handoff and prepends it to context]
&gt; &#34;Picking up: you were investigating session cookies as an
   alternative to broken JWT rotation. Continue?&#34;</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>You did nothing special. At Claude Code&rsquo;s <code>SessionEnd</code>, ai-memory consolidated the session&rsquo;s observations into a <code>sessions/&lt;uuid&gt;.md</code> page, created a typed handoff with <code>open_questions</code> + <code>next_steps</code>, and marked it &ldquo;pending.&rdquo; At Codex&rsquo;s <code>SessionStart</code>, the server saw the pending handoff, fetched it, and injected it into the initial context. The agent reads and continues.</p>
<p>Same scenario if you abandon the project for two months and come back. <code>memory_explore</code> auto-tunes verbosity: less than an hour since the last session, it returns one line. More than 30 days, it returns a full catch-up of what happened.</p>
<h2>Adopting ai-memory on an existing project<span class="hx:absolute hx:-mt-20" id="adopting-ai-memory-on-an-existing-project"></span>
    <a href="#adopting-ai-memory-on-an-existing-project" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>If you install ai-memory on a project with months of history, the wiki starts empty and the first sessions break even — you&rsquo;re populating, not retrieving. <code>ai-memory bootstrap</code> solves this. It collects your <code>git log</code>, README, <code>docs/</code>, module headers, and project-rules files (<code>CLAUDE.md</code> / <code>AGENTS.md</code>), then sends them to the server which uses the LLM to generate seed wiki pages:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="nb">cd</span> ~/Projects/my-project
</span></span><span class="line"><span class="cl">ai-memory bootstrap</span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Costs about $0.05 with Claude Haiku 4.5 (budget capped at 50K input tokens). Run with <code>--dry-run</code> first to see what would be sent without paying. From there the wiki starts with real context, and every session builds on top.</p>
<h2>Install: three commands<span class="hx:absolute hx:-mt-20" id="install-three-commands"></span>
    <a href="#install-three-commands" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>I reduced the install to the bare essentials. The recommended path is Docker, because the server stays isolated and updates are one line. Nothing else needed:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="c1"># 1. Wrapper script (~3KB) that runs the binary inside the container</span>
</span></span><span class="line"><span class="cl">mkdir -p ~/.local/bin
</span></span><span class="line"><span class="cl">curl -fsSL https://raw.githubusercontent.com/akitaonrails/ai-memory/main/bin/ai-memory <span class="se">\
</span></span></span><span class="line"><span class="cl">    -o ~/.local/bin/ai-memory
</span></span><span class="line"><span class="cl">chmod +x ~/.local/bin/ai-memory
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># 2. Start the server (loopback-only, no auth — single-user laptop)</span>
</span></span><span class="line"><span class="cl">docker run -d --name ai-memory <span class="se">\
</span></span></span><span class="line"><span class="cl">    --restart unless-stopped <span class="se">\
</span></span></span><span class="line"><span class="cl">    -p 127.0.0.1:49374:49374 <span class="se">\
</span></span></span><span class="line"><span class="cl">    -v ai-memory-data:/data <span class="se">\
</span></span></span><span class="line"><span class="cl">    -e <span class="nv">AI_MEMORY_LLM_PROVIDER</span><span class="o">=</span>anthropic <span class="se">\
</span></span></span><span class="line"><span class="cl">    -e <span class="nv">ANTHROPIC_API_KEY</span><span class="o">=</span>sk-ant-... <span class="se">\
</span></span></span><span class="line"><span class="cl">    akitaonrails/ai-memory:latest
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># 3. Wire up your agent</span>
</span></span><span class="line"><span class="cl">ai-memory install-mcp   --client claude-code --apply
</span></span><span class="line"><span class="cl">ai-memory install-hooks --agent  claude-code --apply</span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Done. Open Claude Code as usual. Every prompt and tool call now lands in ai-memory, and the next session you open in this project will see a handoff with where you left off.</p>
<p>Repeat step 3 with <code>--agent codex</code>, <code>--agent opencode</code>, <code>--agent omp</code>/<code>pi</code>, <code>--client cursor</code>, <code>--client gemini-cli</code>, <code>--client pi</code>/<code>omp</code>, etc. for other agents. Claude Desktop and OpenClaw are MCP-only. Idempotent: re-running replaces only the ai-memory entry, preserving any other hooks/MCP servers you have. It writes a <code>.bak-&lt;timestamp&gt;</code> backup before every modifying write.</p>
<p>The project README covers the variations (<a href="https://github.com/akitaonrails/ai-memory#quick-start"target="_blank" rel="noopener">Docker compose</a>, homelab on the LAN with a bearer token, <a href="https://github.com/akitaonrails/ai-memory/blob/main/docs/install.md"target="_blank" rel="noopener">no-Docker install</a>, source build). Follow <a href="https://github.com/akitaonrails/ai-memory/blob/main/docs/install.md"target="_blank" rel="noopener">docs/install.md</a> if your setup wanders off the happy path.</p>
<h2>Useful commands worth knowing<span class="hx:absolute hx:-mt-20" id="useful-commands-worth-knowing"></span>
    <a href="#useful-commands-worth-knowing" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Once installed, the day-to-day is just using the agents. But it&rsquo;s worth knowing a handful of commands for when you need them:</p>
<ul>
<li><strong><code>ai-memory upgrade</code></strong> — self-upgrades the wrapper + <code>docker pull</code>s the new image + re-stages hook scripts/plugins/extensions. Idempotent. If you have a separate remote server, this only refreshes the local client; you update the server separately.</li>
<li><strong><code>ai-memory bootstrap</code></strong> — seeds the wiki from git log + README + docs/ + project rules. For projects that existed before ai-memory came along.</li>
<li><strong><code>ai-memory purge-project --project &lt;name&gt; --confirm</code></strong> — wipes an entire project. Atomic: SQLite rows, the wiki subdir, neighbors untouched.</li>
<li><strong><code>ai-memory rename-project --from &lt;name&gt; --to &lt;new&gt;</code></strong> — renames. One column in the DB, no file moves on disk. No side effects.</li>
<li><strong><code>ai-memory backup</code></strong> — snapshot of the data directory (wiki + SQLite). <code>ai-memory restore</code> undoes it.</li>
<li><strong><code>ai-memory lint</code> / <code>ai-memory forget-sweep</code> / <code>ai-memory embed</code></strong> — manual maintenance. Lint and forget-sweep also run on the server schedule by default; embedding backfill exists but stays off by default because it may call a paid provider.</li>
<li><strong><code>ai-memory generate-auth-token</code></strong> — when you&rsquo;re about to expose the server beyond loopback (see <code>docs/deploy.md</code>).</li>
</ul>
<h2>Spelunking the wiki in the browser<span class="hx:absolute hx:-mt-20" id="spelunking-the-wiki-in-the-browser"></span>
    <a href="#spelunking-the-wiki-in-the-browser" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>The server can also mount a read-only web UI at <code>http://127.0.0.1:49374/web</code> when started with <code>--enable-web</code>. Same binary, same port, no extra process. It&rsquo;s handy for three practical things: auditing what the agent&rsquo;s been saving, checking whether the consolidated pages still look coherent, and sharing a single page with a teammate without giving them access to the agent.</p>
<p>The homepage lists detected projects, each with a page count and time since last activity:</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/2026/05/23/ai-memory/ai-memory-web-projects.png" alt="ai-memory /web homepage: project cards (llm-coding-benchmark, nes-to-sms, ai-jail, .config, ai-memory, distrobox-gaming, scratch) each with page counts and “just now”, orange banner warning that this is LLM-optimised memory, not human-curated documentation."  loading="lazy" /></p>
<p>Notice the orange warning at the top: the wiki is optimised for LLM consumption, with pages compiled from session observations by the LLM consolidator. For human-curated canonical documentation, use the project&rsquo;s own <code>docs/</code>. The <code>/web</code> UI is for spelunking.</p>
<p>Each project is isolated by UUID in the physical layout on disk. Two pages with the same path in different projects don&rsquo;t collide. Click a card and you land in the project&rsquo;s page tree:</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/2026/05/23/ai-memory/ai-memory-web-project-view.png" alt="ai-memory project view: left sidebar with the tree grouped by kind (concepts/, decisions/, gotchas/), right column lists recent activity with kind badges (fact, decision) and relative timestamps."  loading="lazy" /></p>
<p>The sidebar groups the tree by kind: <code>concepts/</code> (durable knowledge), <code>decisions/</code> (architectural calls), <code>gotchas/</code> (footguns), <code>_rules/</code> (project rules suggested for promotion into <code>CLAUDE.md</code>), <code>sessions/</code> (per-session logs), and <code>bootstrap.md</code> (the manifest generated by <code>ai-memory bootstrap</code>). The right column shows recent activity.</p>
<p>Click any page and you land in rendered markdown:</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/2026/05/23/ai-memory/ai-memory-web-page.png" alt="Individual page “Per-project UUID-namespaced disk layout” rendered: “semantic” and “fact” badges at the top, “updated just now” and “created 1 hour ago” timestamps, markdown body with an ASCII code block showing the directory tree."  loading="lazy" /></p>
<p>The rendering has syntax highlighting, tier badges (<code>working</code>/<code>episodic</code>/<code>semantic</code>/<code>procedural</code>) and kind badges (<code>decision</code>/<code>gotcha</code>/<code>rule</code>/<code>fact</code>), breadcrumbs, the supersession chain visible. Search combines FTS5, link expansion, and embeddings when configured; light/dark mode follows the OS preference via <code>prefers-color-scheme</code>.</p>
<p>To edit the wiki you open the files directly in any markdown editor (Obsidian works great). The web UI is read-only by design: the LLM consolidator is the one writing, humans just read.</p>
<h2>Why Docker<span class="hx:absolute hx:-mt-20" id="why-docker"></span>
    <a href="#why-docker" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Picking Docker as the recommended path was deliberate. A few practical wins:</p>
<ul>
<li><strong>Updates are one line.</strong> <code>ai-memory upgrade</code> pulls the new image, refreshes the wrapper, re-stages hooks/plugins/extensions. You don&rsquo;t compile Rust, don&rsquo;t manage libsqlite versions, don&rsquo;t fight with mise/Node version churn the way Node-based solutions force you to.</li>
<li><strong>Real isolation.</strong> The server runs in the container, reads only <code>/data</code> (named volume), doesn&rsquo;t pollute your system. To clean up, it&rsquo;s <code>docker volume rm</code>.</li>
<li><strong>Same image across setups.</strong> Laptop, desktop, homelab. Same amd64 or arm64 image.</li>
<li><strong>Auto restart.</strong> <code>--restart unless-stopped</code> brings the server back when you restart Docker, or when the machine boots (assuming <code>systemctl enable docker</code>).</li>
<li><strong>No source build needed.</strong> Compiling the Rust 1.95+ toolchain takes about 3 minutes in release. For end users, that&rsquo;s unnecessary ceremony. Docker abstracts it away.</li>
</ul>
<p>There&rsquo;s a no-Docker path in docs/install.md for anyone who prefers it. But Docker is where the UX is best.</p>
<h2>Which LLM for consolidation<span class="hx:absolute hx:-mt-20" id="which-llm-for-consolidation"></span>
    <a href="#which-llm-for-consolidation" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>This is a case where <strong>you don&rsquo;t need a heavy model</strong>. Consolidation is text in, text out: the agent records raw observations during the session, on <code>SessionEnd</code> the LLM compiles 1-5 wiki pages classified as <code>concept</code> / <code>decision</code> / <code>gotcha</code> / <code>rule</code>. No complex reasoning, no code. Opus 4.7 or GPT-5.5 thinking are overkill — expensive and slow for a task that accepts a light model.</p>
<p>To pick the default we ran serious A/B testing across 6 different providers against 5 synthetic fixtures, each designed to stress a specific failure mode: multi-page extraction, restraint (resisting the urge to fabricate a page when the session is trivial), correct classification of <code>rule</code> vs <code>gotcha</code> vs <code>decision</code>, and topic separation. Full writeup with parse-rate, latency, and quality tables per fixture is at <a href="https://github.com/akitaonrails/ai-memory/blob/main/docs/llm-provider-comparison.md"target="_blank" rel="noopener"><code>docs/llm-provider-comparison.md</code></a>. The summary table:</p>
<table>
  <thead>
      <tr>
          <th>Model</th>
          <th>Cost</th>
          <th>Latency</th>
          <th>Verdict</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td><strong>Claude Haiku 4.5</strong></td>
          <td>~$0.02/run</td>
          <td>7s</td>
          <td><strong>The default I picked.</strong> Best classification and restraint, no hallucination.</td>
      </tr>
      <tr>
          <td>GPT-5.4-mini (OpenAI)</td>
          <td>~$0.005/run</td>
          <td>4s</td>
          <td>Cheaper, faster alternative. Mild over-classification on trivial sessions.</td>
      </tr>
      <tr>
          <td>qwen3:32b (Ollama local)</td>
          <td>$0</td>
          <td>92s</td>
          <td>Free if you have a local server. Latency invisible in the background.</td>
      </tr>
      <tr>
          <td>DeepSeek V4 Flash</td>
          <td>~$0.005/run</td>
          <td>22s</td>
          <td>Works, but no edge over GPT-mini or Haiku.</td>
      </tr>
      <tr>
          <td>Sonnet 4.5</td>
          <td>~$0.06/run</td>
          <td>11s</td>
          <td>Displaced by Haiku. 3× the cost, more hallucination.</td>
      </tr>
      <tr>
          <td>Kimi-K2.6</td>
          <td>n/a</td>
          <td>hangs</td>
          <td>INELIGIBLE. Reasoning model burns the token budget internally before emitting content.</td>
      </tr>
  </tbody>
</table>
<p>Why Haiku ended up as default: hosted (always available), best at <strong>restraint</strong> (resists fabricating pages when the session is trivial, crucial for the wiki not to turn into a pile of empty pages), and best at <strong>classification</strong> (consistently gets <code>kind: rule</code> right, which is what makes auto-routing to <code>_rules/&lt;slug&gt;.md</code> work). $0.02 per consolidation is negligible for personal use.</p>
<p>But the user has legitimate alternatives:</p>
<ul>
<li><strong>GPT-5.4-mini</strong> if budget is tight (5× cheaper than Haiku, 2× faster). The only measurable defect was fabricating a <code>decisions/docs-spelling.md</code> page on a typo-fix session. Over-classification, but mild.</li>
<li><strong>qwen3:32b on Ollama</strong> if you have a local server with ~20GB of RAM/VRAM. Zero cost per consolidation, fidelity comparable to the top hosted models. The ~92s latency doesn&rsquo;t matter because consolidation runs in the background.</li>
<li><strong>DeepSeek V4 Flash</strong> works, but GPT-mini matches it on quality and beats it on speed.</li>
</ul>
<p>If you want to test other models, the eval harness is at <a href="https://github.com/akitaonrails/ai-memory/tree/main/evals"target="_blank" rel="noopener"><code>evals/</code></a> as a separate Rust crate. Add a JSON fixture, run <code>cargo run -p ai-memory-eval --release</code>, compare two providers side by side. Outputs land in <code>evals/runs/&lt;timestamp&gt;/{baseline,candidate}/</code> with the exact <code>.raw.txt</code> the model answered plus <code>.meta.json</code> for latency and parse rate. PRs with new models tested are very welcome.</p>
<h2>Status: beta, needs users<span class="hx:absolute hx:-mt-20" id="status-beta-needs-users"></span>
    <a href="#status-beta-needs-users" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>ai-memory is at the <code>v0.2-complete</code> tag on GitHub. The main features work: automatic capture, MCP, optional web UI, bootstrap, purge/rename/backup, bearer auth, browsing, FTS5 + graph/link-neighbour RRF search, optional embeddings, consolidation, decay, scheduled maintenance, and handoff across Claude Code / Codex / OpenCode / Cursor / Gemini CLI / OMP-Pi. I&rsquo;ve been running it in personal production for a few weeks.</p>
<p>But it&rsquo;s beta. It needs many more users banging on it for me to find the bugs that don&rsquo;t show up on my machine. Claude Desktop and OpenClaw work as MCP-only clients; some exotic MCP clients still need real testing. The most polished integration today is Claude Code, followed by Codex, OpenCode, and OMP/Pi.</p>
<p>If you&rsquo;ve made it this far, consider installing and sending feedback. Issues at <a href="https://github.com/akitaonrails/ai-memory/issues"target="_blank" rel="noopener">github.com/akitaonrails/ai-memory/issues</a>. PRs are very welcome — the code is Rust, MIT licensed, and the architecture is documented in <a href="https://github.com/akitaonrails/ai-memory/blob/main/docs/ARCHITECTURE.md"target="_blank" rel="noopener"><code>docs/ARCHITECTURE.md</code></a> and <a href="https://github.com/akitaonrails/ai-memory/blob/main/docs/design-decisions.md"target="_blank" rel="noopener"><code>docs/design-decisions.md</code></a>. Even a bug report of &ldquo;I installed it, it didn&rsquo;t run on my setup&rdquo; helps — it means I assumed something about environments that doesn&rsquo;t match yours.</p>
<p>The core motivation stays the Karpathy line. Agent memory is text. Text lives on disk. You index it with SQLite. You compile with an LLM when the work is worth it. You forget what nobody looks at anymore. You stay out of the way. And when you switch agents in the middle of a project, the next one already knows where you left off.</p>
<p>That&rsquo;s what ai-memory tries to deliver.</p>
]]></content:encoded><category>ai-memory</category><category>coding-agents</category><category>rust</category></item><item><title>AI Agent Memory: Karpathy LLM Wiki and agentmemory in Practice</title><link>https://akitaonrails.github.io/en/2026/05/18/ai-agent-memory-karpathy-llm-wiki-agentmemory/</link><guid isPermaLink="true">https://akitaonrails.github.io/en/2026/05/18/ai-agent-memory-karpathy-llm-wiki-agentmemory/</guid><pubDate>Mon, 18 May 2026 15:00:00 -0300</pubDate><description>&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Update (May 23, 2026)&lt;/strong&gt;: after a week running agentmemory in personal production, I&amp;rsquo;m walking it back. The architecture it picked accumulates a class of bug that doesn&amp;rsquo;t close without rewriting half the system (BM25 reindex on every restart, 5-second data-loss window, wrong hook key on ~47% of Claude Code tool calls, etc). I started a Rust replacement called &lt;strong&gt;ai-memory&lt;/strong&gt; that fixes those. See &lt;a href="https://akitaonrails.github.io/en/2026/05/23/i-built-memory-system-for-coding-agents-ai-memory/"&gt;I Built a Memory System for Coding Agents: ai-memory&lt;/a&gt; for the full writeup, the alternatives ranking, and install instructions. The rest of this post still holds as background on how compaction works in the three agents, Karpathy&amp;rsquo;s LLM Wiki pattern, and why external memory matters.&lt;/p&gt;</description><content:encoded><![CDATA[<blockquote>
  <p><strong>Update (May 23, 2026)</strong>: after a week running agentmemory in personal production, I&rsquo;m walking it back. The architecture it picked accumulates a class of bug that doesn&rsquo;t close without rewriting half the system (BM25 reindex on every restart, 5-second data-loss window, wrong hook key on ~47% of Claude Code tool calls, etc). I started a Rust replacement called <strong>ai-memory</strong> that fixes those. See <a href="/en/2026/05/23/i-built-memory-system-for-coding-agents-ai-memory/">I Built a Memory System for Coding Agents: ai-memory</a> for the full writeup, the alternatives ranking, and install instructions. The rest of this post still holds as background on how compaction works in the three agents, Karpathy&rsquo;s LLM Wiki pattern, and why external memory matters.</p>

</blockquote>
<p>Anyone running long sessions in Claude Code, Codex CLI or opencode has eventually seen the &ldquo;context approaching limit&rdquo; warning or watched the agent &ldquo;forget&rdquo; decisions made three hours ago. This post is a deep dive into how memory works in these agents today, where it breaks, and what you can do to get something closer to long-term memory. I read the source code directly: Codex (Rust), opencode (TypeScript) and Claude Code (TypeScript, via the leak that&rsquo;s been circulating). Then I closed by testing <a href="https://github.com/rohitg00/agentmemory"target="_blank" rel="noopener">agentmemory</a>, an open source MCP server that tries to solve the problem systematically.</p>
<h2>First things first: what is &ldquo;context&rdquo;<span class="hx:absolute hx:-mt-20" id="first-things-first-what-is-context"></span>
    <a href="#first-things-first-what-is-context" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>A language model (LLM) has no persistent memory. What it &ldquo;remembers&rdquo; during a conversation is just the set of tokens that fit inside its <strong>context window</strong>. Every message exchanged, every file read, every command output, every tool call — all of it goes into the window. When you use Claude Code, Codex or opencode, the agent is assembling a sequence of messages (system prompt + history + tools + tool output) and sending the whole thing to the API on every turn.</p>
<p>That has two direct effects. The first is behavioral: the agent performs best when the relevant part of the conversation is fresh in context, and degrades as important information gets buried under pages of <code>ls</code> and <code>grep</code> output. The second is financial: every token sent gets billed (or chipped off your quota), and large windows have higher latency. Opus 4.7 has a 1M context, GPT 5.5 too, but just because the window fits doesn&rsquo;t mean it pays to fill it. The fuller it is, the slower inference gets and the pricier each request becomes.</p>
<p>That&rsquo;s why every agent implements some form of <strong>compaction</strong>: when the context approaches the limit, the agent runs an extra LLM call that summarizes the conversation so far into something much shorter, dumps the raw history, and continues the session on top of the summary. The upside is obvious (more room to work) and so is the downside (the summarized part loses detail).</p>
<p>Let&rsquo;s see how each of the big three pulls this off.</p>
<h2>Codex CLI: per-model limit + explicit handoff<span class="hx:absolute hx:-mt-20" id="codex-cli-per-model-limit--explicit-handoff"></span>
    <a href="#codex-cli-per-model-limit--explicit-handoff" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Codex CLI is open source (<a href="https://github.com/openai/codex"target="_blank" rel="noopener">github.com/openai/codex</a>), so we get to read it directly. The auto-compaction logic lives in <code>codex-rs/core/src/session/turn.rs</code> and fires like this:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-rust" data-lang="rust"><span class="line"><span class="cl"><span class="kd">let</span><span class="w"> </span><span class="n">auto_compact_limit</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">model_info</span><span class="p">.</span><span class="n">auto_compact_token_limit</span><span class="p">().</span><span class="n">unwrap_or</span><span class="p">(</span><span class="kt">i64</span>::<span class="no">MAX</span><span class="p">);</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="c1">// ... every turn ...
</span></span></span><span class="line"><span class="cl"><span class="kd">let</span><span class="w"> </span><span class="n">total_usage_tokens</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">sess</span><span class="p">.</span><span class="n">get_total_token_usage</span><span class="p">().</span><span class="k">await</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="kd">let</span><span class="w"> </span><span class="n">token_limit_reached</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">total_usage_tokens</span><span class="w"> </span><span class="o">&gt;=</span><span class="w"> </span><span class="n">auto_compact_limit</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="k">if</span><span class="w"> </span><span class="n">token_limit_reached</span><span class="w"> </span><span class="o">&amp;&amp;</span><span class="w"> </span><span class="n">needs_follow_up</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="kd">let</span><span class="w"> </span><span class="n">reset_client_session</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="k">match</span><span class="w"> </span><span class="n">run_auto_compact</span><span class="p">(</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="o">&amp;</span><span class="n">sess</span><span class="p">,</span><span class="w"> </span><span class="o">&amp;</span><span class="n">turn_context</span><span class="p">,</span><span class="w"> </span><span class="o">&amp;</span><span class="k">mut</span><span class="w"> </span><span class="n">client_session</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="n">InitialContextInjection</span>::<span class="n">BeforeLastUserMessage</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="n">CompactionReason</span>::<span class="n">ContextLimit</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="n">CompactionPhase</span>::<span class="n">MidTurn</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="p">).</span><span class="k">await</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="cm">/* ... */</span><span class="w"> </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="p">}</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>The limit is per model (<code>auto_compact_token_limit</code> comes from <code>ModelProviderInfo</code>). When it hits, Codex calls the LLM itself with a specific compaction prompt (in <code>codex-rs/core/templates/compact/prompt.md</code>):</p>
<blockquote>
  <p>You are performing a CONTEXT CHECKPOINT COMPACTION. Create a handoff summary for another LLM that will resume the task.</p>
<p>Include:</p>
<ul>
<li>Current progress and key decisions made</li>
<li>Important context, constraints, or user preferences</li>
<li>What remains to be done (clear next steps)</li>
<li>Any critical data, examples, or references needed to continue</li>
</ul>

</blockquote>
<p>The response becomes the new context, prefixed with a preamble that literally says &ldquo;another language model started to solve this problem and produced a summary of its thinking process.&rdquo; Codex emits <code>pre_compact</code> and <code>post_compact</code> events that hooks can intercept (handled in <a href="https://github.com/openai/codex/blob/main/codex-rs/core/src/hook_runtime.rs"target="_blank" rel="noopener"><code>codex-rs/core/src/hook_runtime.rs</code></a>). Those hooks are the seam where external tools (like agentmemory) plug in to save state before compaction wipes the history.</p>
<h2>opencode: 20K buffer + anchored summarization<span class="hx:absolute hx:-mt-20" id="opencode-20k-buffer--anchored-summarization"></span>
    <a href="#opencode-20k-buffer--anchored-summarization" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>opencode (<a href="https://github.com/sst/opencode"target="_blank" rel="noopener">github.com/sst/opencode</a>) does the same thing with different math. In <code>packages/opencode/src/session/overflow.ts</code>:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-typescript" data-lang="typescript"><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">COMPACTION_BUFFER</span> <span class="o">=</span> <span class="mi">20</span><span class="nx">_000</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kr">export</span> <span class="kd">function</span> <span class="nx">usable</span><span class="p">(</span><span class="nx">input</span><span class="o">:</span> <span class="p">{</span> <span class="nx">cfg</span><span class="p">,</span> <span class="nx">model</span><span class="p">,</span> <span class="nx">outputTokenMax</span><span class="o">?</span> <span class="p">})</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="kr">const</span> <span class="nx">context</span> <span class="o">=</span> <span class="nx">input</span><span class="p">.</span><span class="nx">model</span><span class="p">.</span><span class="nx">limit</span><span class="p">.</span><span class="nx">context</span>
</span></span><span class="line"><span class="cl">  <span class="kr">const</span> <span class="nx">reserved</span> <span class="o">=</span> <span class="nx">input</span><span class="p">.</span><span class="nx">cfg</span><span class="p">.</span><span class="nx">compaction</span><span class="o">?</span><span class="p">.</span><span class="nx">reserved</span>
</span></span><span class="line"><span class="cl">    <span class="o">??</span> <span class="nb">Math</span><span class="p">.</span><span class="nx">min</span><span class="p">(</span><span class="nx">COMPACTION_BUFFER</span><span class="p">,</span> <span class="nx">ProviderTransform</span><span class="p">.</span><span class="nx">maxOutputTokens</span><span class="p">(</span><span class="nx">input</span><span class="p">.</span><span class="nx">model</span><span class="p">,</span> <span class="nx">input</span><span class="p">.</span><span class="nx">outputTokenMax</span><span class="p">))</span>
</span></span><span class="line"><span class="cl">  <span class="k">return</span> <span class="nx">input</span><span class="p">.</span><span class="nx">model</span><span class="p">.</span><span class="nx">limit</span><span class="p">.</span><span class="nx">input</span>
</span></span><span class="line"><span class="cl">    <span class="o">?</span> <span class="nb">Math</span><span class="p">.</span><span class="nx">max</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="nx">input</span><span class="p">.</span><span class="nx">model</span><span class="p">.</span><span class="nx">limit</span><span class="p">.</span><span class="nx">input</span> <span class="o">-</span> <span class="nx">reserved</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="o">:</span> <span class="nb">Math</span><span class="p">.</span><span class="nx">max</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="nx">context</span> <span class="o">-</span> <span class="nx">ProviderTransform</span><span class="p">.</span><span class="nx">maxOutputTokens</span><span class="p">(</span><span class="nx">input</span><span class="p">.</span><span class="nx">model</span><span class="p">,</span> <span class="nx">input</span><span class="p">.</span><span class="nx">outputTokenMax</span><span class="p">))</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kr">export</span> <span class="kd">function</span> <span class="nx">isOverflow</span><span class="p">(</span><span class="nx">input</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="k">if</span> <span class="p">(</span><span class="nx">input</span><span class="p">.</span><span class="nx">cfg</span><span class="p">.</span><span class="nx">compaction</span><span class="o">?</span><span class="p">.</span><span class="nx">auto</span> <span class="o">===</span> <span class="kc">false</span><span class="p">)</span> <span class="k">return</span> <span class="kc">false</span>
</span></span><span class="line"><span class="cl">  <span class="kr">const</span> <span class="nx">count</span> <span class="o">=</span> <span class="nx">input</span><span class="p">.</span><span class="nx">tokens</span><span class="p">.</span><span class="nx">total</span>
</span></span><span class="line"><span class="cl">    <span class="o">||</span> <span class="nx">input</span><span class="p">.</span><span class="nx">tokens</span><span class="p">.</span><span class="nx">input</span> <span class="o">+</span> <span class="nx">input</span><span class="p">.</span><span class="nx">tokens</span><span class="p">.</span><span class="nx">output</span> <span class="o">+</span> <span class="nx">input</span><span class="p">.</span><span class="nx">tokens</span><span class="p">.</span><span class="nx">cache</span><span class="p">.</span><span class="nx">read</span> <span class="o">+</span> <span class="nx">input</span><span class="p">.</span><span class="nx">tokens</span><span class="p">.</span><span class="nx">cache</span><span class="p">.</span><span class="nx">write</span>
</span></span><span class="line"><span class="cl">  <span class="k">return</span> <span class="nx">count</span> <span class="o">&gt;=</span> <span class="nx">usable</span><span class="p">(</span><span class="nx">input</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>By default, opencode reserves 20K tokens as a buffer between content and the window limit. When total tokens crosses <code>usable()</code>, it marks the session as <code>needsCompaction = true</code> and runs the compaction flow on the next turn. The summarization prompt (in <code>packages/opencode/src/agent/prompt/compaction.txt</code>) is more surgical than Codex&rsquo;s:</p>
<blockquote>
  <p>You are an anchored context summarization assistant for coding sessions.</p>
<p>Summarize only the conversation history you are given. The newest turns may be kept verbatim outside your summary, so focus on the older context that still matters for continuing the work.</p>
<p>If the prompt includes a <code>&lt;previous-summary&gt;</code> block, treat it as the current anchored summary. Update it with the new history by preserving still-true details, removing stale details, and merging in new facts.</p>

</blockquote>
<p>Notice the difference: opencode keeps an &ldquo;anchored summary&rdquo; that gets <strong>updated</strong> on every compaction, instead of regenerated from scratch. The most recent turns stay verbatim, and only the older history gets collapsed. It&rsquo;s a middle ground between Codex&rsquo;s full handoff and keeping everything raw.</p>
<h2>Claude Code: three levels of compaction + detailed summary<span class="hx:absolute hx:-mt-20" id="claude-code-three-levels-of-compaction--detailed-summary"></span>
    <a href="#claude-code-three-levels-of-compaction--detailed-summary" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Claude Code is proprietary, but a recent leak exposed the source (TypeScript, same as opencode but with very different architecture). The code shows Anthropic went further than the competition: Claude Code has <strong>three levels of compaction</strong> running in parallel, not one.</p>
<p>The first is <code>microcompact</code>, time-based, in <code>src/services/compact/microCompact.ts</code> and <code>timeBasedMCConfig.ts</code>. When the gap since the last assistant message goes past 60 minutes, the server-side prompt cache (1h TTL) is guaranteed expired, so the whole prefix is going to be rewritten on the next request anyway. Before sending it, Claude Code clears the content of old tool results (<code>Read</code>, <code>Grep</code>, <code>Glob</code>, <code>WebFetch</code>, <code>Bash</code>, etc.) and replaces them with <code>[Old tool result content cleared]</code>. Shrinks the request size without entering the expensive summarization flow. Comment in the code:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-typescript" data-lang="typescript"><span class="line"><span class="cl"><span class="cm">/** Trigger when (now − last assistant timestamp) exceeds this many minutes.
</span></span></span><span class="line"><span class="cl"><span class="cm"> *  60 is the safe choice: the server&#39;s 1h cache TTL is guaranteed expired
</span></span></span><span class="line"><span class="cl"><span class="cm"> *  for all users, so we never force a miss that wouldn&#39;t have happened. */</span>
</span></span><span class="line"><span class="cl"><span class="nx">gapThresholdMinutes</span>: <span class="kt">number</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>The second level is <code>autoCompact</code>, in <code>src/services/compact/autoCompact.ts</code>. Similar to opencode&rsquo;s, but more carefully tuned:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-typescript" data-lang="typescript"><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">MAX_OUTPUT_TOKENS_FOR_SUMMARY</span> <span class="o">=</span> <span class="mi">20</span><span class="nx">_000</span>
</span></span><span class="line"><span class="cl"><span class="kr">export</span> <span class="kr">const</span> <span class="nx">AUTOCOMPACT_BUFFER_TOKENS</span> <span class="o">=</span> <span class="mi">13</span><span class="nx">_000</span>
</span></span><span class="line"><span class="cl"><span class="kr">export</span> <span class="kr">const</span> <span class="nx">WARNING_THRESHOLD_BUFFER_TOKENS</span> <span class="o">=</span> <span class="mi">20</span><span class="nx">_000</span>
</span></span><span class="line"><span class="cl"><span class="kr">export</span> <span class="kr">const</span> <span class="nx">ERROR_THRESHOLD_BUFFER_TOKENS</span> <span class="o">=</span> <span class="mi">20</span><span class="nx">_000</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kr">export</span> <span class="kd">function</span> <span class="nx">getAutoCompactThreshold</span><span class="p">(</span><span class="nx">model</span>: <span class="kt">string</span><span class="p">)</span><span class="o">:</span> <span class="kt">number</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="kr">const</span> <span class="nx">effectiveContextWindow</span> <span class="o">=</span> <span class="nx">getEffectiveContextWindowSize</span><span class="p">(</span><span class="nx">model</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">  <span class="k">return</span> <span class="nx">effectiveContextWindow</span> <span class="o">-</span> <span class="nx">AUTOCOMPACT_BUFFER_TOKENS</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Reserves 20K tokens for the summarization output, 13K of buffer for triggering the compaction, and has warning + error thresholds 20K below that limit (the TUI status bar turns yellow past the warning, red past the error). There&rsquo;s also a circuit breaker: after 3 consecutive auto-compact failures, it stops trying — an internal comment reveals that without it &ldquo;1,279 sessions had 50+ consecutive failures (up to 3,272), wasting ~250K API calls/day globally.&rdquo;</p>
<p>The third level is <code>sessionMemoryCompact</code> in <code>sessionMemoryCompact.ts</code>, marked experimental, which ties into the persistent cross-session memory system.</p>
<p>The most visible difference vs Codex and opencode is in the summarization prompt. Where Codex asks for 4 short bullets and opencode asks for an update of the &ldquo;anchored summary,&rdquo; Claude Code asks for a 9-section explicit structure (<code>src/services/compact/prompt.ts</code>):</p>
<blockquote>
  <ol>
<li>Primary Request and Intent: Capture all of the user&rsquo;s explicit requests and intents in detail</li>
<li>Key Technical Concepts: List all important technical concepts, technologies, and frameworks discussed.</li>
<li>Files and Code Sections: Enumerate specific files and code sections examined, modified, or created&hellip;</li>
<li>Errors and fixes: List all errors that you ran into, and how you fixed them&hellip;</li>
<li>Problem Solving: Document problems solved and any ongoing troubleshooting efforts.</li>
<li>All user messages: List ALL user messages that are not tool results. These are critical&hellip;</li>
<li>Pending Tasks: Outline any pending tasks that you have explicitly been asked to work on.</li>
<li>Current Work: Describe in detail precisely what was being worked on immediately before this summary request&hellip;</li>
<li>Optional Next Step: List the next step that you will take&hellip;</li>
</ol>

</blockquote>
<p>Section 6 (&ldquo;All user messages&rdquo;) is the unusual one: the summary has to contain a verbatim list of every user message that isn&rsquo;t a tool result. Meaning even after compaction, Claude Code keeps your asks, literal. That&rsquo;s why compacted sessions in Claude Code feel like they preserve the tone of the conversation better than Codex (where the handoff is more executive and less narrative).</p>
<p>There&rsquo;s also a <code>PARTIAL_COMPACT_PROMPT</code> variant that summarizes only the recent stretch when a prior summary is preserved, and a <code>PARTIAL_COMPACT_UP_TO_PROMPT</code> to keep cache hits by placing the summary at the start. The <code>/compact</code> slash command is still around for manual force, and the <code>PreCompact</code> / <code>PostCompact</code> hooks run the same as the other agents.</p>
<h2>Comparing the three side by side<span class="hx:absolute hx:-mt-20" id="comparing-the-three-side-by-side"></span>
    <a href="#comparing-the-three-side-by-side" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><table>
  <thead>
      <tr>
          <th></th>
          <th>Claude Code</th>
          <th>Codex</th>
          <th>opencode</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>Pre-compaction buffer</td>
          <td>13K (autocompact) + 20K (output)</td>
          <td>per-model via <code>auto_compact_token_limit</code></td>
          <td>20K (config <code>compaction.reserved</code>)</td>
      </tr>
      <tr>
          <td>Compaction kinds</td>
          <td>3 (microcompact, autocompact, sessionMemoryCompact)</td>
          <td>1 (plus remote v1/v2 variants)</td>
          <td>1 (anchored, with updatable summary)</td>
      </tr>
      <tr>
          <td>Summary structure</td>
          <td>9 fixed sections + <code>&lt;analysis&gt;</code> scratchpad block</td>
          <td>4 free-form bullets (progress, decisions, next, refs)</td>
          <td>Update of the pre-existing &ldquo;anchored summary&rdquo;</td>
      </tr>
      <tr>
          <td>Verbatim preservation</td>
          <td>Lists every user message</td>
          <td>No</td>
          <td>Most recent turns kept intact outside the summary</td>
      </tr>
      <tr>
          <td>Circuit breaker</td>
          <td>Yes, 3 consecutive failures stop the cycle</td>
          <td>Not documented</td>
          <td>No</td>
      </tr>
      <tr>
          <td>Hooks</td>
          <td>PreCompact / PostCompact</td>
          <td>pre_compact / post_compact (Rust)</td>
          <td>no explicit compaction hooks</td>
      </tr>
      <tr>
          <td>Time-gap microcompact</td>
          <td>Yes (60min, synced with cache TTL)</td>
          <td>No</td>
          <td>No</td>
      </tr>
  </tbody>
</table>
<p>The design choices tell a story. Claude Code invests in <strong>preserving user narrative</strong> (the 9 sections, especially #6) and <strong>optimizing cache cost</strong> (gap-based microcompact, clean separation of 3 paths). Codex prioritizes <strong>handoff between models</strong> (the &ldquo;summary produced by the other language model&rdquo; preamble shows the expectation that the next turn might be executed by a different LLM). opencode picked <strong>incremental summarization</strong>: the anchored summary updates each cycle instead of being regenerated. Each strategy has trade-offs, but this is the first time you can look at all three side by side using real source.</p>
<h2>&ldquo;Vendor lock&rdquo;? Doesn&rsquo;t exist for this kind of memory<span class="hx:absolute hx:-mt-20" id="vendor-lock-doesnt-exist-for-this-kind-of-memory"></span>
    <a href="#vendor-lock-doesnt-exist-for-this-kind-of-memory" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>A worry that comes up a lot: by starting with Claude Code you get &ldquo;locked in&rdquo; and can&rsquo;t migrate to opencode or Codex later. That&rsquo;s a myth. Agent memory, as we saw, is just <strong>text</strong>. No proprietary binary format, no closed schema, no vendor-only state. Everything the agent carries is prompt + message history + context files.</p>
<p>In practice you can do a manual handoff between agents. Tell Claude Code: &ldquo;write a markdown doc at <code>./HANDOFF.md</code> with the current project state, decisions made, next steps, and any important context for a different agent to continue.&rdquo; Out comes a well-written session, you close Claude Code, open opencode, say &ldquo;read <code>./HANDOFF.md</code> and pick up where it left off.&rdquo; And opencode picks up from where Claude stopped, without meaningful loss (the loss is exactly the loss an internal compaction would have caused).</p>
<p>This pattern of explicitly exporting context is actually better than relying on automatic compaction. You decide when and what to preserve, instead of leaving it to the agent under token pressure.</p>
<h2>The problem: long-term memory disappears alongside<span class="hx:absolute hx:-mt-20" id="the-problem-long-term-memory-disappears-alongside"></span>
    <a href="#the-problem-long-term-memory-disappears-alongside" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Compaction solves the immediate problem (room in the context) but creates a subtler one: <strong>information from the start of the session is the first to go</strong>. If you spent 30 minutes on turn 5 exploring an architecture, decided three trade-offs and discarded two approaches, by turn 50 that whole exploration may have collapsed into a single bullet. If you need to revisit one of those discarded trade-offs (&ldquo;why did we decide against Redis here?&rdquo;), the agent doesn&rsquo;t know anymore.</p>
<p>The workaround I&rsquo;ve been using for months is to force the agent to write into files manually. On important projects I keep a <code>./.docs/</code> or <code>./docs/</code> directory with markdown files organized by topic: architecture, decisions, known gotchas, weird configurations, links to relevant issues. When something important happens in a session, I ask: &ldquo;save this to <code>./.docs/&lt;topic&gt;.md</code>&rdquo;. Then on the next session, or after a compaction, the agent can re-read the file if it needs to.</p>
<p>The cost of this approach is discipline. I have to remember to ask. The agent won&rsquo;t do it on its own. And I have to organize the files so it can find what it needs later (which usually means a MEMORY.md or CLAUDE.md at the root listing the topics).</p>
<p>There&rsquo;s a more systematic way to do this. It&rsquo;s called <strong>LLM Wiki</strong>, popularized by <a href="https://venturebeat.com/data/karpathy-shares-llm-knowledge-base-architecture-that-bypasses-rag-with-an"target="_blank" rel="noopener">Andrej Karpathy in April 2026</a> in a GitHub gist.</p>
<h2>Karpathy&rsquo;s LLM Wiki pattern<span class="hx:absolute hx:-mt-20" id="karpathys-llm-wiki-pattern"></span>
    <a href="#karpathys-llm-wiki-pattern" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/2026/05/18/memoria-agentes/karpathy_wiki_diagram.jpg" alt="Diagram of the LLM Wiki pattern: three layers (Raw Sources, The Wiki, Schema) in the architecture; three operations (Ingest, Query, Lint); two actors (Human and LLM Agent). Visualization by Yuchen Jin alongside Karpathy’s original tweet."  loading="lazy" /></p>
<p>The idea is simple and powerful: instead of treating knowledge as something to <strong>retrieve</strong> on demand (RAG), treat it as something to <strong>compile</strong> over time, like code. The architecture has three layers:</p>
<ol>
<li><strong>Raw Sources</strong> — immutable documents (papers, articles, transcripts, notes) that serve as source of truth.</li>
<li><strong>Wiki Layer</strong> — markdown files generated and maintained by the LLM. Each concept gets a page. Pages link to other pages. The LLM updates, cross-references, flags contradictions.</li>
<li><strong>Schema</strong> — a file (think <code>CLAUDE.md</code> or <code>SCHEMA.md</code>) that defines conventions: how to name pages, tag taxonomy, minimum structure per entry.</li>
</ol>
<p>The workflow has three operations. <strong>Ingest</strong>: when a new source arrives, the LLM reads, extracts what matters, updates 10-15 existing pages, creates the missing ones, fixes cross-references. <strong>Query</strong>: questions get synthesized answers with citations; valuable insights become new pages. <strong>Lint</strong>: periodic passes detect contradictions, outdated claims, missing connections.</p>
<p>The core win over RAG is that <strong>knowledge compounds</strong>. RAG re-derives the answer on every query, starting from the same raw documents. The wiki synthesizes once, and the next query starts from the synthesis, not from raw material. For programming work this is gold: the first time you discover that a library has a weird timezone gotcha, it becomes a wiki page. The second time the topic comes up, the agent reads the page instead of re-discovering the problem.</p>
<p>The grunt work of maintaining a wiki always killed human wikis. That&rsquo;s why they die. But LLMs are good at writing and repetitive maintenance. Karpathy&rsquo;s bet is that we finally have a machine that does the boring work of keeping the wiki alive.</p>
<h2>agentmemory: practical implementation of the pattern<span class="hx:absolute hx:-mt-20" id="agentmemory-practical-implementation-of-the-pattern"></span>
    <a href="#agentmemory-practical-implementation-of-the-pattern" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/2026/05/18/memoria-agentes/agentmemory-banner.png" alt="agentmemory project banner: “Persistent memory for AI coding agents” with badges for R@5 95.2% retrieval, 92% fewer tokens, 53 MCP tools, 12 auto hooks, 0 external DBs, 950&#43; tests passing."  loading="lazy" /></p>
<p>I&rsquo;d been doing this wiki by hand in <code>./.docs/</code> for months. This week I migrated to a tool that automates most of the process: <a href="https://github.com/rohitg00/agentmemory"target="_blank" rel="noopener">agentmemory</a> by Rohit Ghumare. It&rsquo;s open source (Apache-2.0) and is literally an implementation of the LLM Wiki pattern with some extensions (confidence scoring, memory lifecycle, knowledge graph, hybrid search).</p>
<p>What it is, in practice:</p>
<ul>
<li>A <strong>Node daemon</strong> running locally on <code>127.0.0.1:3111</code> (REST) and <code>:3113</code> (web viewer with timeline and session replay). Storage on SQLite + in-memory vector index, zero external dependencies.</li>
<li>An <strong>MCP server</strong> (<code>@agentmemory/mcp</code>) that any MCP-compatible agent (Claude Code, Codex, opencode, Cursor, Gemini CLI, etc.) loads as a stdio server. Exposes 51 memory tools (<code>memory_smart_search</code>, <code>memory_save</code>, <code>memory_sessions</code>, <code>memory_consolidate</code>, etc.).</li>
<li><strong>Hook plugins</strong> for Claude Code (12 hooks) and Codex (6 hooks) that capture observations automatically on every tool call, prompt and compaction event.</li>
<li>Hybrid retrieval: <strong>BM25 + vector + knowledge graph</strong>, fused via Reciprocal Rank Fusion (RRF, k=60), with per-session diversification.</li>
<li><strong>4-tier memory consolidation</strong> inspired by how the human brain processes memory during sleep: Working (raw observations) → Episodic (session summaries) → Semantic (extracted facts and patterns) → Procedural (workflows and decision patterns).</li>
</ul>
<p>That last part is what makes it interesting. It&rsquo;s not just a log of everything that happened. There&rsquo;s decay (Ebbinghaus curve — memories that aren&rsquo;t accessed decay), reinforcement (frequently accessed memories strengthen), stale eviction, contradiction detection and resolution. Exactly what&rsquo;s missing from the &ldquo;write to <code>./.docs/</code> by hand&rdquo; pattern.</p>
<h2>Quick install<span class="hx:absolute hx:-mt-20" id="quick-install"></span>
    <a href="#quick-install" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Three options: npm global, npx, or (what I did) a dedicated prefix to dodge mise/Node version churn. The one-liner version from the project README:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">npm install -g @agentmemory/agentmemory     <span class="c1"># once — `agentmemory` on PATH</span>
</span></span><span class="line"><span class="cl">agentmemory                                  <span class="c1"># spin up the daemon on :3111</span>
</span></span><span class="line"><span class="cl">agentmemory demo                             <span class="c1"># seed sample sessions + validate recall</span>
</span></span><span class="line"><span class="cl">agentmemory connect claude-code              <span class="c1"># wire your agent (also: codex, cursor, gemini-cli, ...)</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>For full details, the <a href="https://github.com/rohitg00/agentmemory#install"target="_blank" rel="noopener">agentmemory README</a> covers every variant (Docker, source build, Windows, embedding providers). For folks using mise to manage Node, it&rsquo;s worth installing into a dedicated prefix (something like <code>~/.local/share/agentmemory-npm/</code>) and starting the daemon via a systemd user unit, so global packages don&rsquo;t vanish when mise swaps Node versions. But the README path works for most cases.</p>
<p>After the daemon is up, the main step is registering the MCP server in whichever agent you use.</p>
<p>For <strong>Claude Code</strong>, edit <code>~/.mcp.json</code>:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-json" data-lang="json"><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nt">&#34;mcpServers&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;agentmemory&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="nt">&#34;command&#34;</span><span class="p">:</span> <span class="s2">&#34;/path/to/agentmemory-mcp&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="nt">&#34;env&#34;</span><span class="p">:</span> <span class="p">{</span> <span class="nt">&#34;AGENTMEMORY_URL&#34;</span><span class="p">:</span> <span class="s2">&#34;http://localhost:3111&#34;</span> <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Verify with <code>claude mcp list</code>. You should see <code>agentmemory: ✓ Connected</code>.</p>
<p>For <strong>Codex CLI</strong>, edit <code>~/.codex/config.toml</code>:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-toml" data-lang="toml"><span class="line"><span class="cl"><span class="p">[</span><span class="nx">mcp_servers</span><span class="p">.</span><span class="nx">agentmemory</span><span class="p">]</span>
</span></span><span class="line"><span class="cl"><span class="nx">command</span> <span class="p">=</span> <span class="s2">&#34;/path/to/agentmemory-mcp&#34;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="p">[</span><span class="nx">mcp_servers</span><span class="p">.</span><span class="nx">agentmemory</span><span class="p">.</span><span class="nx">env</span><span class="p">]</span>
</span></span><span class="line"><span class="cl"><span class="nx">AGENTMEMORY_URL</span> <span class="p">=</span> <span class="s2">&#34;http://localhost:3111&#34;</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>For <strong>opencode</strong>, edit <code>~/.config/opencode/opencode.json</code> and add at the root of the object:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-json" data-lang="json"><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nt">&#34;mcp&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;agentmemory&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="nt">&#34;type&#34;</span><span class="p">:</span> <span class="s2">&#34;local&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="nt">&#34;command&#34;</span><span class="p">:</span> <span class="p">[</span><span class="s2">&#34;/path/to/agentmemory-mcp&#34;</span><span class="p">],</span>
</span></span><span class="line"><span class="cl">      <span class="nt">&#34;enabled&#34;</span><span class="p">:</span> <span class="kc">true</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="nt">&#34;environment&#34;</span><span class="p">:</span> <span class="p">{</span> <span class="nt">&#34;AGENTMEMORY_URL&#34;</span><span class="p">:</span> <span class="s2">&#34;http://localhost:3111&#34;</span> <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>After this, the three agents share the same memory server. Save a decision in Claude Code, run <code>memory_smart_search</code> in Codex and it shows up.</p>
<p>To push the agent toward consulting memory at the start of non-trivial tasks, it&rsquo;s worth adding a line to <code>CLAUDE.md</code> (or equivalent):</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>At the start of non-trivial tasks, call `memory_smart_search` with the task
keywords. Use `memory_save` or `memory_lesson_save` when capturing decisions,
patterns, or preferences worth keeping.</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Otherwise the agent uses the tools when it judges it useful, but will skip them on purely exploratory sessions.</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/2026/05/18/memoria-agentes/agentmemory-traces.png" alt="agentmemory iii console showing a waterfall trace of a session: each operation (smart-search, save, recall, consolidate) along the timeline, with latencies and call relationships."  loading="lazy" /></p>
<h2>Practical upside: frictionless handoff<span class="hx:absolute hx:-mt-20" id="practical-upside-frictionless-handoff"></span>
    <a href="#practical-upside-frictionless-handoff" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Here&rsquo;s the thing that sold me. Remember the export-to-markdown pattern I described earlier, for migrating between agents? With agentmemory, it&rsquo;s automatic. You save an architectural decision in a Claude Code session (<code>memory_save type=architecture content=&quot;we use cookie store instead of session store because X&quot;</code>). Open opencode in the same project. Ask about session persistence. opencode calls <code>memory_smart_search</code>, retrieves the entry, and works from there.</p>
<p>Forget the &ldquo;export to markdown, open the other agent, tell it to read&rdquo;. Both agents read from the same place. Vendor lock stops making sense in this setup, because the memory source is external to both.</p>
<h2>The trade-offs that stay<span class="hx:absolute hx:-mt-20" id="the-trade-offs-that-stay"></span>
    <a href="#the-trade-offs-that-stay" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>This isn&rsquo;t magic. Some things to keep in mind:</p>
<p>The ideal embedding layer is a paid API (Voyage, OpenAI, Cohere). Without that, agentmemory uses local MiniLM via <code>@xenova/transformers</code>, which works but is slower on first ingest and less accurate on complex semantic queries. For anyone fine with a local model, it&rsquo;s a real solution. If you want max recall quality, the API key is worth it.</p>
<p>The daemon runs as a permanent process. Needs a systemd unit (I run mine in user mode) or launchd on macOS. There&rsquo;s no &ldquo;start the server when you remember&rdquo; — it has to stay up, or the plugin hooks miss events.</p>
<p>The 4-tier consolidation uses an LLM to process. Without a provider key configured, agentmemory runs in &ldquo;no-op mode&rdquo; — still indexes observations and searches, but doesn&rsquo;t compress or consolidate. You still have the equivalent of the wiki, just without Karpathy&rsquo;s &ldquo;periodic lint.&rdquo;</p>
<p>And like any new tool, the docs have holes. Some things to watch for that aren&rsquo;t in the upstream README: the real state path depends on how the daemon is started (relative to its cwd), the iii engine&rsquo;s port <code>49134</code> binds to <code>0.0.0.0</code> by default (passes through your firewall, worth checking), <code>import-jsonl</code> doesn&rsquo;t honor the <code>--dry-run</code> flag despite the global help saying it does. Read the project README first, and be ready to debug when the docs fall short.</p>
<h2>Memory is text. Text needs management.<span class="hx:absolute hx:-mt-20" id="memory-is-text-text-needs-management"></span>
    <a href="#memory-is-text-text-needs-management" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>The synthesis I take from all this is simple. Agent memory, at the root, is text. No proprietary schema, no binary format, no secret state. That&rsquo;s liberating: you&rsquo;re not locked to a vendor, you can move between Claude Code, Codex and opencode whenever you want, manually or via an external layer like agentmemory.</p>
<p>But loose text turns into garbage fast. Without compaction, the context window fills up and the agent gets slow and expensive. With compaction, you lose long-term memory. Without the discipline to save into files, important decisions evaporate on the next compaction. Without structure across files, they turn into a pile the agent can&rsquo;t read efficiently.</p>
<p>The answer is a combination of four layers:</p>
<ul>
<li><strong>Compaction</strong> solves the full-context-window problem. The big three (Claude Code, Codex, opencode) handle that by themselves.</li>
<li><strong>Manual markdown in <code>./.docs/</code> or <code>./docs/</code></strong> is the baseline fallback that always works, at the cost of demanding discipline from the programmer.</li>
<li><strong>LLM Wiki pattern</strong> (Karpathy) lifts manual markdown into a structured workflow: source / wiki / schema, with ingest / query / lint.</li>
<li><strong>agentmemory</strong> (or similar MCP-based tools) automates the wiki, adds tiered consolidation, hybrid retrieval, memory lifecycle, and as a bonus serves the three agents off the same daemon.</li>
</ul>
<p>The most underrated piece of all this is the compound effect. An architectural decision saved today is available for every future session, in any agent. A library gotcha discovered on Tuesday doesn&rsquo;t need to be re-discovered on Sunday. It&rsquo;s the kind of productivity that takes a few weeks to show up (you need critical mass of saved memories first) but that changes the game once it lands.</p>
<p>Worth testing. If you use Claude Code, Codex or opencode every day and never set up anything for long-term memory, start simple (a <code>./.docs/</code> in the current repo). When the frustration of the third &ldquo;explanation I already gave&rdquo; hits, install agentmemory.</p>
]]></content:encoded><category>ai-memory</category><category>coding-agents</category><category>llms</category></item></channel></rss>