<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/">
    <channel>
        <title>Justin3go</title>
        <link>https://justin3go.com</link>
        <description>A T-shaped front-end developer who is committed to deepening expertise in the technical field, focuses on independent development, enjoys working with Vue.js and Nest.js, and has some knowledge of Python, search engines, NLP, Web3, and back-end development.</description>
        <lastBuildDate>Tue, 08 Sep 2026 16:25:04 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <language>en-US</language>
        <image>
            <title>Justin3go</title>
            <url>https://oss.justin3go.com/justin3goAvatar.jpg</url>
            <link>https://justin3go.com</link>
        </image>
        <copyright>Copyright© 2021-present Justin3go</copyright>
        <item>
            <title><![CDATA[DeepSeek Harness In Depth: 90K Stars in Two Days for "Everything Is a Plugin" — the Future, or Over-Engineering?]]></title>
            <link>https://justin3go.com/en/posts/2026/08/15-deepseek-harness-review</link>
            <guid>https://justin3go.com/en/posts/2026/08/15-deepseek-harness-review</guid>
            <pubDate>Sat, 15 Aug 2026 00:00:00 GMT</pubDate>
            <description><![CDATA[<h1 id="deepseek-harness-in-depth-90k-stars-in-two-days-for-everything-is-a-plugin-—-the-future-or-over-engineering" tabindex="-1">DeepSeek Harness In Depth: 90K Stars in Two Days for &quot;Everything Is a Plugin&quot; — the Future, or Over-Engineering? <a class="header-anchor" href="#deepseek-harness-in-depth-90k-stars-in-two-days-for-everything-is-a-plugin-—-the-future-or-over-engineering" aria-label="Permalink to &quot;DeepSeek Harness In Depth: 90K Stars in Two Days for &quot;Everything Is a Plugin&quot; — the Future, or Over-Engineering?&quot;">&ZeroWidthSpace;</a></h1>
<blockquote>
<p>✨Article Summary (AI Generated)</p>
</blockquote>
<!-- DESC SEP -->
<blockquote></blockquote>
<p>DeepSeek open-sourced its agent runtime framework deepseek-harness (dsh) on 2026-08-13, and it crossed 90,000+ stars within two days. This article draws on a full read of the source, a side-by-side comparison with Pi, Codex CLI, Claude Code, and OpenCode, and cross-checks against dozens of real reviews from X, Hacker News, and Chinese-language communities to unpack its &quot;everything is a plugin&quot; Cordis core, its event-driven Turn/Step main loop, its append-only session log, and its self-modifying toolset — verifying, claim by claim, what the praise and the criticism actually get right. It closes with a clear recommendation on who should (and shouldn't) adopt it.</p>
<blockquote></blockquote>
<!-- DESC SEP -->
<h2 id="prologue-28-hours-90-000-stars" tabindex="-1">Prologue: 28 Hours, 90,000 Stars <a class="header-anchor" href="#prologue-28-hours-90-000-stars" aria-label="Permalink to &quot;Prologue: 28 Hours, 90,000 Stars&quot;">&ZeroWidthSpace;</a></h2>
<p>On August 13, 2026, DeepSeek open-sourced a project called <strong>deepseek-harness</strong> (CLI name <code>dsh</code>). It crossed 50,000 stars in about 12 hours and roughly 92,000 by hour 28 — for reference, the previous velocity record holder, OpenClaw, took 84 days to reach 200,000.</p>
<p>The buzz is real, and so is the controversy. My timeline showed two opposing takes at once:</p>
<ul>
<li>One side: this is &quot;the seed of an Agent OS,&quot; &quot;the low-level skeleton no other framework has.&quot;</li>
<li>The other: &quot;needlessly heavy,&quot; &quot;wrapping an entire plate of dumplings' worth of vinegar just to chase self-evolution.&quot;</li>
</ul>
<p>Oddly, both camps included people who had genuinely read the source. So for this piece I did three things: read the whole repo cover to cover, compared it point by point against Pi, Codex CLI, Claude Code, and OpenCode, and pulled together the substantive commentary from X (Twitter), Hacker News, and Chinese-language communities, checking each claim against the actual code — to see how much of what people are saying actually holds up.</p>
<p>The one-line verdict up front: <strong>dsh isn't really &quot;DeepSeek's version of Claude Code&quot; — it's closer to a radical experiment in what an agent runtime <em>should</em> look like. It's not the right tool today for most people who just want to write code, but the bet it's making is worth a serious look from anyone building agent infrastructure.</strong></p>
<h2 id="part-one-what-it-actually-is" tabindex="-1">Part One: What It Actually Is <a class="header-anchor" href="#part-one-what-it-actually-is" aria-label="Permalink to &quot;Part One: What It Actually Is&quot;">&ZeroWidthSpace;</a></h2>
<h3 id="_1-1-the-basics" tabindex="-1">1.1 The Basics <a class="header-anchor" href="#_1-1-the-basics" aria-label="Permalink to &quot;1.1 The Basics&quot;">&ZeroWidthSpace;</a></h3>
<ul>
<li><strong>Positioning</strong>: an open-source agent runtime framework (harness/runtime) — the CLI, the web UI, and the automation server are all just &quot;assembled shapes&quot; sitting on top of it.</li>
<li><strong>Release</strong>: 2026-08-13, currently at version <code>0.1.0-rc.5</code>, explicitly labeled a developer preview. The README states plainly: &quot;THERE WILL BE COMPATIBILITY-BREAKING CHANGES.&quot;</li>
<li><strong>License</strong>: MIT, fully open source.</li>
<li><strong>Stack</strong>: a TypeScript monorepo (57 package groups, roughly 500K lines of TypeScript), with about 300 lines of C11 underneath the Linux sandbox.</li>
<li><strong>Model support</strong>: not locked to DeepSeek's own models — a plugin adapter layer supports roughly 40 providers, including OpenAI, Anthropic, Google, Kimi, and any OpenAI-compatible endpoint; wiring one up takes a few lines of YAML.</li>
<li><strong>Scale</strong> (two days after launch, per the GitHub API): 92,700+ stars / 8,400+ forks.</li>
</ul>
<p>An easy-to-miss piece of backstory: when DeepSeek previously published model benchmark numbers (for DeepSWE, for instance), it drew criticism for &quot;vendor-reported, unreproducible&quot; scores, and the team promised at the time to &quot;open-source the harness used for evaluation.&quot; Multiple signals now point to dsh being exactly that promise kept — it's the internal framework DeepSeek uses to run agentic benchmarks against its own models. That explains why the repo shipped so mature on day one: 22 contributors, with the top contributors sitting at thousands of commits each — clearly this had been iterating internally for a long time.</p>
<h3 id="_1-2-core-idea-everything-is-a-plugin" tabindex="-1">1.2 Core Idea: Everything Is a Plugin <a class="header-anchor" href="#_1-2-core-idea-everything-is-a-plugin" aria-label="Permalink to &quot;1.2 Core Idea: Everything Is a Plugin&quot;">&ZeroWidthSpace;</a></h3>
<p>Most coding agents work like this: write a core agent loop (take input → call the model → run tools → repeat), then leave a few extension points around the edges (MCP, skills, and so on). The core is privileged code; extensions are second-class citizens.</p>
<p>dsh flips that structure. Its foundation is a general-purpose plugin framework called <strong>Cordis</strong> (its design traces back to the paper <em>A Programming Paradigm for Spatiotemporal Composability</em>, and it has already spent four years in production inside the Koishi chatbot framework). From there —</p>
<p><strong>the model adapter is a plugin, the tool registry is a plugin, session storage is a plugin, the sandbox is a plugin, the UI is a plugin, and even the agent's main loop itself is a plugin.</strong></p>
<p>This isn't marketing copy. In the source, the agent loop is literally just an ordinary package (<code>packages/core/agent-loop</code>) that can be swapped out via config like any other plugin. The minimal shape of a plugin is a file that exports an <code>apply(ctx)</code> function, mounted with a single line of YAML:</p>
<div class="language-ts vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">ts</span><pre class="shiki shiki-themes github-light github-dark vp-code" tabindex="0" v-pre=""><code><span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">import</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583"> type</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8"> { Context } </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">from</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF"> '@deepseek-ai/cordis'</span></span>
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">export</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583"> const</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF"> name</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583"> =</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF"> 'hello'</span></span>
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">export</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583"> function</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0"> apply</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">(</span><span style="--shiki-light:#E36209;--shiki-dark:#FFAB70">ctx</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">:</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0"> Context</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">) {</span></span>
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">  console.</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0">log</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">(</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF">'hello from my first plugin'</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">)</span></span>
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">}</span></span></code></pre>
</div><p>The official release ships four preset run modes: <strong>standard mode</strong> (a full-featured coding agent), <strong>code mode</strong> (TypeScript SDK orchestration), <strong>minimal mode</strong> (just a shell and a file editor, for running benchmarks), and <strong>creative mode</strong> (runtime inspection and plugin experimentation). But these four are just four of the official &quot;build patterns&quot; — as beta tester Jiayuan Zhang put it in an apt comparison: dsh is like a <strong>Lego car kit</strong>, and the official presets are just one recommended way to assemble it, printed on the box.</p>
<h2 id="part-two-core-design-unpacked" tabindex="-1">Part Two: Core Design, Unpacked <a class="header-anchor" href="#part-two-core-design-unpacked" aria-label="Permalink to &quot;Part Two: Core Design, Unpacked&quot;">&ZeroWidthSpace;</a></h2>
<h3 id="_2-1-an-event-driven-main-loop-turn-and-step" tabindex="-1">2.1 An Event-Driven Main Loop: Turn and Step <a class="header-anchor" href="#_2-1-an-event-driven-main-loop-turn-and-step" aria-label="Permalink to &quot;2.1 An Event-Driven Main Loop: Turn and Step&quot;">&ZeroWidthSpace;</a></h3>
<p>dsh's main loop is a standard ReAct pattern (the model thinks → calls a tool → reads the result → thinks again), but instead of a hard-coded <code>while</code> loop, it's decomposed into a set of events:</p>
<div class="language- vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang"></span><pre class="shiki shiki-themes github-light github-dark vp-code" tabindex="0" v-pre=""><code><span class="line"><span>turn/start → agent/pre-step → step/start</span></span>
<span class="line"><span>  → system-prompt/assemble (assembles the prompt and tool schema)</span></span>
<span class="line"><span>  → agent/request → llm/stream → assistant/message</span></span>
<span class="line"><span>  → tools/pre-execute → tools/execute → tools/post-execute</span></span>
<span class="line"><span>  → step/end → agent/turn-stopping → turn/end</span></span></code></pre>
</div><p>A <strong>step</strong> is &quot;one model request plus whatever tool calls it triggers&quot;; a <strong>turn</strong> is zero or more steps, from receiving input through to everything being done. The key point: almost every stage is an interceptable event — a plugin can rewrite messages or refuse execution at <code>agent/pre-step</code>, or swap out a tool's result at <code>tools/post-execute</code>. The loop isn't the framework's private property; it's a public protocol every plugin gets to participate in.</p>
<p>The direct consequence: <strong>turning a single agent into a multi-agent collaboration architecture just means swapping out the loop plugin — no need to fork the whole project.</strong> Compare that to Codex CLI, where changing the main loop means editing its Rust core.</p>
<h3 id="_2-2-append-only-session-logs-everything-the-model-sees-is-on-the-record" tabindex="-1">2.2 Append-Only Session Logs: Everything the Model Sees Is on the Record <a class="header-anchor" href="#_2-2-append-only-session-logs-everything-the-model-sees-is-on-the-record" aria-label="Permalink to &quot;2.2 Append-Only Session Logs: Everything the Model Sees Is on the Record&quot;">&ZeroWidthSpace;</a></h3>
<p>dsh enforces a runtime invariant: &quot;<strong>Model-visible means logged</strong>&quot; — anything that goes into a model request must be reconstructible from the session log. The session log is an append-only event stream, and the conversation history the model sees is <em>projected</em> from that log, which supports resume, fork, search, and replay.</p>
<p>Some on Hacker News have called this a killer feature: at a moment when U.S. vendors are increasingly encrypting reasoning traces and making them hard to audit, dsh made &quot;fully traceable&quot; an architectural guarantee rather than a nice-to-have. GeekPark's hands-on testing confirmed the experience in practice: the system prompt, the chain of thought, and every tool call and result are preserved in full.</p>
<p>Context compaction isn't a black box baked into the loop either — it's an independent plugin: over-budget tool results get trimmed first, and if that's not enough, a summary node is generated to replace a chunk of history. The whole process is locked with three log events, so even a crash mid-compaction is reconstructible from the log.</p>
<h3 id="_2-3-three-things-nobody-else-has" tabindex="-1">2.3 Three Things &quot;Nobody Else Has&quot; <a class="header-anchor" href="#_2-3-three-things-nobody-else-has" aria-label="Permalink to &quot;2.3 Three Things &quot;Nobody Else Has&quot;&quot;">&ZeroWidthSpace;</a></h3>
<p><strong>① Code Mode (<code>run_code</code>)</strong>: the model writes a chunk of TypeScript that batch-calls tools via <code>await tools.name(args)</code>, and only whatever gets <code>print</code>ed or <code>return</code>ed goes back to the model. This is a solution to the &quot;a dozen scattered tool calls burn through the context window&quot; problem — a dozen round-trips collapse into a single execution of one code block.</p>
<p><strong>② A subagent can be delegated to a competitor</strong>: dsh's subagent backend (<code>ctx.subagents</code>) supports multiple providers, and startlingly, that list includes <code>claude-code</code> and <code>codex</code> — meaning you can dispatch a subtask from inside dsh whose actual executor is Claude Code or Codex CLI. This &quot;harness-agnostic&quot; stance has no precedent among competing products.</p>
<p><strong>③ A self-modifying toolset (<code>cordis_*</code>)</strong>: the agent can inspect its own plugin tree at runtime, write a new plugin on the fly, and mount it for use. This is the seed of a &quot;self-evolving agent&quot; — though two caveats are worth stating plainly: it's <strong>not enabled in any official preset by default</strong> and has to be turned on explicitly, and a plugin written on the fly lives only in memory — it's gone on restart, with no way to persist it yet.</p>
<h3 id="_2-4-sandboxing-and-permissions-strict-where-it-should-be" tabindex="-1">2.4 Sandboxing and Permissions: Strict Where It Should Be <a class="header-anchor" href="#_2-4-sandboxing-and-permissions-strict-where-it-should-be" aria-label="Permalink to &quot;2.4 Sandboxing and Permissions: Strict Where It Should Be&quot;">&ZeroWidthSpace;</a></h3>
<p>The security design here isn't sloppy: Linux uses bwrap + Landlock (paired with a custom-built C launcher that's fail-closed), macOS uses Seatbelt, and Windows uses restricted ACL tokens. The approval model is a closed enumeration, and anything anomalous is rejected as &quot;unavailable&quot; by default rather than silently allowed. It's even honest about distinguishing &quot;full&quot; versus &quot;partial&quot; sandbox enforcement — Landlock on older kernels only qualifies as partial, and it doesn't misreport itself as full.</p>
<p>But there's a layering gap worth flagging: <strong>the sandbox governs tool execution, while plugins themselves run inside the harness process.</strong> 36Kr's hands-on testing pointed out explicitly that any plugin can reach the shell and the filesystem — right now, the trust model for installing third-party plugins basically comes down to good faith.</p>
<h3 id="_2-5-an-easter-egg-building-a-harness-with-a-harness" tabindex="-1">2.5 An Easter Egg: Building a Harness With a Harness <a class="header-anchor" href="#_2-5-an-easter-egg-building-a-harness-with-a-harness" aria-label="Permalink to &quot;2.5 An Easter Egg: Building a Harness With a Harness&quot;">&ZeroWidthSpace;</a></h3>
<p>What struck me most in this repo wasn't the code — it was the <strong>1,386 Agent Notes</strong> under <code>.agents/</code>: architectural decision records classified as &quot;implemented / rejected / archived / proposed,&quot; plus published post-mortems. The documentation runs to roughly 170,000 lines, nearly on par with the main codebase, and type snippets embedded in the docs are automatically diffed against the source in CI to prevent drift; 100% test coverage per file is a hard gate.</p>
<p>These traces strongly suggest that the repo itself was built with heavy AI-agent involvement — designing, reviewing, and writing post-mortems. dsh is the first user of its own philosophy.</p>
<h2 id="part-three-side-by-side-—-four-different-roads" tabindex="-1">Part Three: Side by Side — Four Different Roads <a class="header-anchor" href="#part-three-side-by-side-—-four-different-roads" aria-label="Permalink to &quot;Part Three: Side by Side — Four Different Roads&quot;">&ZeroWidthSpace;</a></h2>
<p>The coding-agent harness landscape right now roughly splits into four camps (star counts per the GitHub API as of 2026-08-15):</p>
<p>| Project | Approach | License | Stars | One-liner |
|</p>
]]></description>
            <content:encoded><![CDATA[<h1 id="deepseek-harness-in-depth-90k-stars-in-two-days-for-everything-is-a-plugin-—-the-future-or-over-engineering" tabindex="-1">DeepSeek Harness In Depth: 90K Stars in Two Days for &quot;Everything Is a Plugin&quot; — the Future, or Over-Engineering? <a class="header-anchor" href="#deepseek-harness-in-depth-90k-stars-in-two-days-for-everything-is-a-plugin-—-the-future-or-over-engineering" aria-label="Permalink to &quot;DeepSeek Harness In Depth: 90K Stars in Two Days for &quot;Everything Is a Plugin&quot; — the Future, or Over-Engineering?&quot;">&ZeroWidthSpace;</a></h1>
<blockquote>
<p>✨Article Summary (AI Generated)</p>
</blockquote>
<!-- DESC SEP -->
<blockquote></blockquote>
<p>DeepSeek open-sourced its agent runtime framework deepseek-harness (dsh) on 2026-08-13, and it crossed 90,000+ stars within two days. This article draws on a full read of the source, a side-by-side comparison with Pi, Codex CLI, Claude Code, and OpenCode, and cross-checks against dozens of real reviews from X, Hacker News, and Chinese-language communities to unpack its &quot;everything is a plugin&quot; Cordis core, its event-driven Turn/Step main loop, its append-only session log, and its self-modifying toolset — verifying, claim by claim, what the praise and the criticism actually get right. It closes with a clear recommendation on who should (and shouldn't) adopt it.</p>
<blockquote></blockquote>
<!-- DESC SEP -->
<h2 id="prologue-28-hours-90-000-stars" tabindex="-1">Prologue: 28 Hours, 90,000 Stars <a class="header-anchor" href="#prologue-28-hours-90-000-stars" aria-label="Permalink to &quot;Prologue: 28 Hours, 90,000 Stars&quot;">&ZeroWidthSpace;</a></h2>
<p>On August 13, 2026, DeepSeek open-sourced a project called <strong>deepseek-harness</strong> (CLI name <code>dsh</code>). It crossed 50,000 stars in about 12 hours and roughly 92,000 by hour 28 — for reference, the previous velocity record holder, OpenClaw, took 84 days to reach 200,000.</p>
<p>The buzz is real, and so is the controversy. My timeline showed two opposing takes at once:</p>
<ul>
<li>One side: this is &quot;the seed of an Agent OS,&quot; &quot;the low-level skeleton no other framework has.&quot;</li>
<li>The other: &quot;needlessly heavy,&quot; &quot;wrapping an entire plate of dumplings' worth of vinegar just to chase self-evolution.&quot;</li>
</ul>
<p>Oddly, both camps included people who had genuinely read the source. So for this piece I did three things: read the whole repo cover to cover, compared it point by point against Pi, Codex CLI, Claude Code, and OpenCode, and pulled together the substantive commentary from X (Twitter), Hacker News, and Chinese-language communities, checking each claim against the actual code — to see how much of what people are saying actually holds up.</p>
<p>The one-line verdict up front: <strong>dsh isn't really &quot;DeepSeek's version of Claude Code&quot; — it's closer to a radical experiment in what an agent runtime <em>should</em> look like. It's not the right tool today for most people who just want to write code, but the bet it's making is worth a serious look from anyone building agent infrastructure.</strong></p>
<h2 id="part-one-what-it-actually-is" tabindex="-1">Part One: What It Actually Is <a class="header-anchor" href="#part-one-what-it-actually-is" aria-label="Permalink to &quot;Part One: What It Actually Is&quot;">&ZeroWidthSpace;</a></h2>
<h3 id="_1-1-the-basics" tabindex="-1">1.1 The Basics <a class="header-anchor" href="#_1-1-the-basics" aria-label="Permalink to &quot;1.1 The Basics&quot;">&ZeroWidthSpace;</a></h3>
<ul>
<li><strong>Positioning</strong>: an open-source agent runtime framework (harness/runtime) — the CLI, the web UI, and the automation server are all just &quot;assembled shapes&quot; sitting on top of it.</li>
<li><strong>Release</strong>: 2026-08-13, currently at version <code>0.1.0-rc.5</code>, explicitly labeled a developer preview. The README states plainly: &quot;THERE WILL BE COMPATIBILITY-BREAKING CHANGES.&quot;</li>
<li><strong>License</strong>: MIT, fully open source.</li>
<li><strong>Stack</strong>: a TypeScript monorepo (57 package groups, roughly 500K lines of TypeScript), with about 300 lines of C11 underneath the Linux sandbox.</li>
<li><strong>Model support</strong>: not locked to DeepSeek's own models — a plugin adapter layer supports roughly 40 providers, including OpenAI, Anthropic, Google, Kimi, and any OpenAI-compatible endpoint; wiring one up takes a few lines of YAML.</li>
<li><strong>Scale</strong> (two days after launch, per the GitHub API): 92,700+ stars / 8,400+ forks.</li>
</ul>
<p>An easy-to-miss piece of backstory: when DeepSeek previously published model benchmark numbers (for DeepSWE, for instance), it drew criticism for &quot;vendor-reported, unreproducible&quot; scores, and the team promised at the time to &quot;open-source the harness used for evaluation.&quot; Multiple signals now point to dsh being exactly that promise kept — it's the internal framework DeepSeek uses to run agentic benchmarks against its own models. That explains why the repo shipped so mature on day one: 22 contributors, with the top contributors sitting at thousands of commits each — clearly this had been iterating internally for a long time.</p>
<h3 id="_1-2-core-idea-everything-is-a-plugin" tabindex="-1">1.2 Core Idea: Everything Is a Plugin <a class="header-anchor" href="#_1-2-core-idea-everything-is-a-plugin" aria-label="Permalink to &quot;1.2 Core Idea: Everything Is a Plugin&quot;">&ZeroWidthSpace;</a></h3>
<p>Most coding agents work like this: write a core agent loop (take input → call the model → run tools → repeat), then leave a few extension points around the edges (MCP, skills, and so on). The core is privileged code; extensions are second-class citizens.</p>
<p>dsh flips that structure. Its foundation is a general-purpose plugin framework called <strong>Cordis</strong> (its design traces back to the paper <em>A Programming Paradigm for Spatiotemporal Composability</em>, and it has already spent four years in production inside the Koishi chatbot framework). From there —</p>
<p><strong>the model adapter is a plugin, the tool registry is a plugin, session storage is a plugin, the sandbox is a plugin, the UI is a plugin, and even the agent's main loop itself is a plugin.</strong></p>
<p>This isn't marketing copy. In the source, the agent loop is literally just an ordinary package (<code>packages/core/agent-loop</code>) that can be swapped out via config like any other plugin. The minimal shape of a plugin is a file that exports an <code>apply(ctx)</code> function, mounted with a single line of YAML:</p>
<div class="language-ts vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">ts</span><pre class="shiki shiki-themes github-light github-dark vp-code" tabindex="0" v-pre=""><code><span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">import</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583"> type</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8"> { Context } </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">from</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF"> '@deepseek-ai/cordis'</span></span>
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">export</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583"> const</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF"> name</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583"> =</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF"> 'hello'</span></span>
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">export</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583"> function</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0"> apply</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">(</span><span style="--shiki-light:#E36209;--shiki-dark:#FFAB70">ctx</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">:</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0"> Context</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">) {</span></span>
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">  console.</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0">log</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">(</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF">'hello from my first plugin'</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">)</span></span>
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">}</span></span></code></pre>
</div><p>The official release ships four preset run modes: <strong>standard mode</strong> (a full-featured coding agent), <strong>code mode</strong> (TypeScript SDK orchestration), <strong>minimal mode</strong> (just a shell and a file editor, for running benchmarks), and <strong>creative mode</strong> (runtime inspection and plugin experimentation). But these four are just four of the official &quot;build patterns&quot; — as beta tester Jiayuan Zhang put it in an apt comparison: dsh is like a <strong>Lego car kit</strong>, and the official presets are just one recommended way to assemble it, printed on the box.</p>
<h2 id="part-two-core-design-unpacked" tabindex="-1">Part Two: Core Design, Unpacked <a class="header-anchor" href="#part-two-core-design-unpacked" aria-label="Permalink to &quot;Part Two: Core Design, Unpacked&quot;">&ZeroWidthSpace;</a></h2>
<h3 id="_2-1-an-event-driven-main-loop-turn-and-step" tabindex="-1">2.1 An Event-Driven Main Loop: Turn and Step <a class="header-anchor" href="#_2-1-an-event-driven-main-loop-turn-and-step" aria-label="Permalink to &quot;2.1 An Event-Driven Main Loop: Turn and Step&quot;">&ZeroWidthSpace;</a></h3>
<p>dsh's main loop is a standard ReAct pattern (the model thinks → calls a tool → reads the result → thinks again), but instead of a hard-coded <code>while</code> loop, it's decomposed into a set of events:</p>
<div class="language- vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang"></span><pre class="shiki shiki-themes github-light github-dark vp-code" tabindex="0" v-pre=""><code><span class="line"><span>turn/start → agent/pre-step → step/start</span></span>
<span class="line"><span>  → system-prompt/assemble (assembles the prompt and tool schema)</span></span>
<span class="line"><span>  → agent/request → llm/stream → assistant/message</span></span>
<span class="line"><span>  → tools/pre-execute → tools/execute → tools/post-execute</span></span>
<span class="line"><span>  → step/end → agent/turn-stopping → turn/end</span></span></code></pre>
</div><p>A <strong>step</strong> is &quot;one model request plus whatever tool calls it triggers&quot;; a <strong>turn</strong> is zero or more steps, from receiving input through to everything being done. The key point: almost every stage is an interceptable event — a plugin can rewrite messages or refuse execution at <code>agent/pre-step</code>, or swap out a tool's result at <code>tools/post-execute</code>. The loop isn't the framework's private property; it's a public protocol every plugin gets to participate in.</p>
<p>The direct consequence: <strong>turning a single agent into a multi-agent collaboration architecture just means swapping out the loop plugin — no need to fork the whole project.</strong> Compare that to Codex CLI, where changing the main loop means editing its Rust core.</p>
<h3 id="_2-2-append-only-session-logs-everything-the-model-sees-is-on-the-record" tabindex="-1">2.2 Append-Only Session Logs: Everything the Model Sees Is on the Record <a class="header-anchor" href="#_2-2-append-only-session-logs-everything-the-model-sees-is-on-the-record" aria-label="Permalink to &quot;2.2 Append-Only Session Logs: Everything the Model Sees Is on the Record&quot;">&ZeroWidthSpace;</a></h3>
<p>dsh enforces a runtime invariant: &quot;<strong>Model-visible means logged</strong>&quot; — anything that goes into a model request must be reconstructible from the session log. The session log is an append-only event stream, and the conversation history the model sees is <em>projected</em> from that log, which supports resume, fork, search, and replay.</p>
<p>Some on Hacker News have called this a killer feature: at a moment when U.S. vendors are increasingly encrypting reasoning traces and making them hard to audit, dsh made &quot;fully traceable&quot; an architectural guarantee rather than a nice-to-have. GeekPark's hands-on testing confirmed the experience in practice: the system prompt, the chain of thought, and every tool call and result are preserved in full.</p>
<p>Context compaction isn't a black box baked into the loop either — it's an independent plugin: over-budget tool results get trimmed first, and if that's not enough, a summary node is generated to replace a chunk of history. The whole process is locked with three log events, so even a crash mid-compaction is reconstructible from the log.</p>
<h3 id="_2-3-three-things-nobody-else-has" tabindex="-1">2.3 Three Things &quot;Nobody Else Has&quot; <a class="header-anchor" href="#_2-3-three-things-nobody-else-has" aria-label="Permalink to &quot;2.3 Three Things &quot;Nobody Else Has&quot;&quot;">&ZeroWidthSpace;</a></h3>
<p><strong>① Code Mode (<code>run_code</code>)</strong>: the model writes a chunk of TypeScript that batch-calls tools via <code>await tools.name(args)</code>, and only whatever gets <code>print</code>ed or <code>return</code>ed goes back to the model. This is a solution to the &quot;a dozen scattered tool calls burn through the context window&quot; problem — a dozen round-trips collapse into a single execution of one code block.</p>
<p><strong>② A subagent can be delegated to a competitor</strong>: dsh's subagent backend (<code>ctx.subagents</code>) supports multiple providers, and startlingly, that list includes <code>claude-code</code> and <code>codex</code> — meaning you can dispatch a subtask from inside dsh whose actual executor is Claude Code or Codex CLI. This &quot;harness-agnostic&quot; stance has no precedent among competing products.</p>
<p><strong>③ A self-modifying toolset (<code>cordis_*</code>)</strong>: the agent can inspect its own plugin tree at runtime, write a new plugin on the fly, and mount it for use. This is the seed of a &quot;self-evolving agent&quot; — though two caveats are worth stating plainly: it's <strong>not enabled in any official preset by default</strong> and has to be turned on explicitly, and a plugin written on the fly lives only in memory — it's gone on restart, with no way to persist it yet.</p>
<h3 id="_2-4-sandboxing-and-permissions-strict-where-it-should-be" tabindex="-1">2.4 Sandboxing and Permissions: Strict Where It Should Be <a class="header-anchor" href="#_2-4-sandboxing-and-permissions-strict-where-it-should-be" aria-label="Permalink to &quot;2.4 Sandboxing and Permissions: Strict Where It Should Be&quot;">&ZeroWidthSpace;</a></h3>
<p>The security design here isn't sloppy: Linux uses bwrap + Landlock (paired with a custom-built C launcher that's fail-closed), macOS uses Seatbelt, and Windows uses restricted ACL tokens. The approval model is a closed enumeration, and anything anomalous is rejected as &quot;unavailable&quot; by default rather than silently allowed. It's even honest about distinguishing &quot;full&quot; versus &quot;partial&quot; sandbox enforcement — Landlock on older kernels only qualifies as partial, and it doesn't misreport itself as full.</p>
<p>But there's a layering gap worth flagging: <strong>the sandbox governs tool execution, while plugins themselves run inside the harness process.</strong> 36Kr's hands-on testing pointed out explicitly that any plugin can reach the shell and the filesystem — right now, the trust model for installing third-party plugins basically comes down to good faith.</p>
<h3 id="_2-5-an-easter-egg-building-a-harness-with-a-harness" tabindex="-1">2.5 An Easter Egg: Building a Harness With a Harness <a class="header-anchor" href="#_2-5-an-easter-egg-building-a-harness-with-a-harness" aria-label="Permalink to &quot;2.5 An Easter Egg: Building a Harness With a Harness&quot;">&ZeroWidthSpace;</a></h3>
<p>What struck me most in this repo wasn't the code — it was the <strong>1,386 Agent Notes</strong> under <code>.agents/</code>: architectural decision records classified as &quot;implemented / rejected / archived / proposed,&quot; plus published post-mortems. The documentation runs to roughly 170,000 lines, nearly on par with the main codebase, and type snippets embedded in the docs are automatically diffed against the source in CI to prevent drift; 100% test coverage per file is a hard gate.</p>
<p>These traces strongly suggest that the repo itself was built with heavy AI-agent involvement — designing, reviewing, and writing post-mortems. dsh is the first user of its own philosophy.</p>
<h2 id="part-three-side-by-side-—-four-different-roads" tabindex="-1">Part Three: Side by Side — Four Different Roads <a class="header-anchor" href="#part-three-side-by-side-—-four-different-roads" aria-label="Permalink to &quot;Part Three: Side by Side — Four Different Roads&quot;">&ZeroWidthSpace;</a></h2>
<p>The coding-agent harness landscape right now roughly splits into four camps (star counts per the GitHub API as of 2026-08-15):</p>
<table tabindex="0">
<thead>
<tr>
<th>Project</th>
<th>Approach</th>
<th>License</th>
<th>Stars</th>
<th>One-liner</th>
</tr>
</thead>
<tbody>
<tr>
<td><strong>Claude Code</strong></td>
<td>Layered extensible ecosystem</td>
<td>Source-available, non-standard open license</td>
<td>141k</td>
<td>Skills/Hooks/Subagents/MCP/Plugins — the fullest ecosystem, and the &quot;heaviest&quot;</td>
</tr>
<tr>
<td><strong>OpenAI Codex CLI</strong></td>
<td>Rust + kernel-level sandbox</td>
<td>Apache 2.0</td>
<td>106k</td>
<td>Widely regarded as the safety leader; declarative extensions (a folder is a plugin)</td>
</tr>
<tr>
<td><strong>Pi</strong> (Earendil)</td>
<td>Minimalist</td>
<td>MIT</td>
<td>90k</td>
<td>Ships only 4 tools by default, a system prompt under 1,000 tokens; the engine under OpenClaw</td>
</tr>
<tr>
<td><strong>deepseek-harness</strong></td>
<td>Runtime-pluggable</td>
<td>MIT</td>
<td>93k</td>
<td>Everything is a plugin, even the loop can be swapped</td>
</tr>
</tbody>
</table>
<p>(For completeness: the fully open-source OpenCode sits at 197k stars, Gemini CLI at 107k, and Aider at 48k — their approaches roughly track Claude Code, Codex, and pair-programming tools respectively, and I won't dig into them further here.)</p>
<h3 id="_3-1-versus-codex-declarative-vs-imperative" tabindex="-1">3.1 Versus Codex: Declarative vs. Imperative <a class="header-anchor" href="#_3-1-versus-codex-declarative-vs-imperative" aria-label="Permalink to &quot;3.1 Versus Codex: Declarative vs. Imperative&quot;">&ZeroWidthSpace;</a></h3>
<p>This is the highest-quality technical debate I found in the community, from developer grapeot, who read both codebases line by line:</p>
<ul>
<li><strong>Codex is declarative</strong>: a plugin is just a folder on disk (a Markdown skill, an MCP config, a shell script) that never enters the harness process. Reloading a config change takes 2-3 seconds, and the barrier to entry is close to zero.</li>
<li><strong>dsh is imperative</strong>: plugins carry state and run directly inside the harness process, registering and calling into each other. Hot-swapping a plugin at runtime means handling dangling references, terminating background tasks, coordinating dependency chains, and rolling back cleanly from a crash — which is why it needed a heavyweight runtime like Cordis; the core module that just manages plugin lifecycles alone runs to 750 lines.</li>
</ul>
<p>An apt renovation analogy: Codex hands you a finished apartment plus a pegboard wall you can hang anything on — hang the wrong thing, take it down, hang something else. dsh hands you a house where you can <strong>rework a load-bearing wall without cutting the water or power</strong>. The question is: how often do you actually need to rework a load-bearing wall?</p>
<h3 id="_3-2-versus-pi-two-extremes" tabindex="-1">3.2 Versus Pi: Two Extremes <a class="header-anchor" href="#_3-2-versus-pi-two-extremes" aria-label="Permalink to &quot;3.2 Versus Pi: Two Extremes&quot;">&ZeroWidthSpace;</a></h3>
<p>Pi sits at the opposite end of the spectrum: it's the minimalist agent libGDX author Mario Zechner built because he couldn't stand Claude Code's complexity creep — four default tools, and a philosophy that &quot;what you leave out matters more than what you add.&quot; Interestingly, the two aren't opposites in every sense — dsh's multi-provider model adapter layer actually uses Pi's own <code>@earendil-works/pi-ai</code> library, so in a sense dsh is &quot;a plugin skyscraper built on top of Pi's model layer.&quot;</p>
<p>And the token-efficiency comparison is brutal: one developer's preliminary test found that, on the same model, Pi's uncached input runs around 4.5K tokens versus roughly 47.6K for dsh — a difference of an order of magnitude (the tester flagged confounding factors of their own, and noted dsh is still a preview). The cost gap between minimalism and full pluggability shows up plainly on the bill.</p>
<h3 id="_3-3-versus-claude-code-not-a-fight-over-features-but-over-business-model" tabindex="-1">3.3 Versus Claude Code: Not a Fight Over Features, But Over Business Model <a class="header-anchor" href="#_3-3-versus-claude-code-not-a-fight-over-features-but-over-business-model" aria-label="Permalink to &quot;3.3 Versus Claude Code: Not a Fight Over Features, But Over Business Model&quot;">&ZeroWidthSpace;</a></h3>
<p>On product maturity today, dsh and Claude Code aren't in the same league — even a developer who had a month of early access before launch said flatly that &quot;as a coding agent to actually use, the experience genuinely isn't as polished as Claude Code or Codex.&quot; But 36Kr's analysis pointed to something more fundamental: by opening the entire capability set under MIT for free, dsh is effectively <strong>declaring that the harness layer shouldn't be a paid product at all</strong>, trying to pull the competition back to model capability and pricing themselves. That's not a shot at Claude Code's feature list — it's a shot at &quot;the harness as a paywall&quot; as a business model.</p>
<h2 id="part-four-what-the-community-is-saying-and-whether-it-s-right" tabindex="-1">Part Four: What the Community Is Saying, and Whether It's Right <a class="header-anchor" href="#part-four-what-the-community-is-saying-and-whether-it-s-right" aria-label="Permalink to &quot;Part Four: What the Community Is Saying, and Whether It's Right&quot;">&ZeroWidthSpace;</a></h2>
<p>I filtered the commentary I collected down to claims backed by code or hands-on testing, then checked each one against the actual repo.</p>
<h3 id="_4-1-the-praise-mostly-holds-up" tabindex="-1">4.1 The Praise: Mostly Holds Up <a class="header-anchor" href="#_4-1-the-praise-mostly-holds-up" aria-label="Permalink to &quot;4.1 The Praise: Mostly Holds Up&quot;">&ZeroWidthSpace;</a></h3>
<ul>
<li><strong>&quot;Clever engineering in the plugin architecture&quot; / &quot;the seed of an Agent OS&quot;</strong> — holds up. Loop-as-plugin, the three-role capability-surface design, transaction rollback — all verifiable in the code.</li>
<li><strong>&quot;Full traceability is the killer feature&quot;</strong> — holds up. &quot;Model-visible means logged&quot; is a runtime-enforced invariant, not documentation flourish.</li>
<li><strong>&quot;The seed of self-evolution&quot;</strong> — holds up, but is overstated. The <code>cordis_*</code> tools genuinely exist, but they're off by default and their output can't persist — still a real distance from &quot;a self-evolving agent.&quot;</li>
<li><strong>&quot;Generation quality is solid&quot;</strong> — independent hands-on tests from ifanr and GeekPark both came out well (a Three.js mini-game, a site rebuild, at roughly $3 in cost). Credible, though the sample size is still small.</li>
</ul>
<h3 id="_4-2-the-criticism-also-mostly-holds-up" tabindex="-1">4.2 The Criticism: Also Mostly Holds Up <a class="header-anchor" href="#_4-2-the-criticism-also-mostly-holds-up" aria-label="Permalink to &quot;4.2 The Criticism: Also Mostly Holds Up&quot;">&ZeroWidthSpace;</a></h3>
<ul>
<li><strong>&quot;Over-engineered for everyday development&quot;</strong> — I think this one <strong>holds up</strong>. The Chinese-language piece from yage.ai, titled roughly &quot;wrapping an entire plate of dumplings' worth of vinegar just to chase self-evolution,&quot; makes a solid point-by-point rebuttal: search services only need brief interactions, restarting an MCP server takes 2-3 seconds anyway, and a skill is plain text that doesn't need framework-level hot reload. The &quot;swap components without stopping the runtime&quot; capability dsh solves for is real, but it's a rare requirement for the vast majority of use cases. One beta tester even observed that DeepSeek's own models frequently can't figure out how to use a plugin correctly and just edit their own code instead — &quot;faster, and about as effective anyway.&quot;</li>
<li><strong>&quot;Token usage runs high&quot;</strong> — preliminary testing backs this up (roughly 10x versus Pi, roughly 3x versus other frameworks), and there's one confirmed, specific bug behind part of it: dsh reads both <code>CLAUDE.md</code> and <code>AGENTS.md</code> from a project, and if the two files have identical content (common, since many projects keep them in sync for cross-tool compatibility), the instruction set gets injected twice, doubling the system prompt outright. No official fix as of this writing.</li>
<li><strong>&quot;Poor compatibility, early-stage ecosystem&quot;</strong> — holds up. The official compatibility list shows 41 compatible integrations against 219 flagged as needing attention or further investigation; 36Kr's hands-on test found all 5 third-party tools it tried failed outright. The plugin repository crossed 2,000+ submissions in two days, but quantity isn't quality.</li>
<li><strong>&quot;Documentation reads like word salad&quot;</strong> — partially holds up. User-facing onboarding docs are genuinely thin, but the internal architecture documentation runs to roughly 170,000 lines and is checked against the code for drift — the problem isn't a lack of documentation, it's that &quot;documentation written for agents to read&quot; and &quot;documentation written for newcomers to read&quot; are two entirely different things, and the latter is currently missing.</li>
</ul>
<h3 id="_4-3-the-benchmark-controversy-a-transparency-problem-not-a-proven-fabrication" tabindex="-1">4.3 The Benchmark Controversy: A Transparency Problem, Not a Proven Fabrication <a class="header-anchor" href="#_4-3-the-benchmark-controversy-a-transparency-problem-not-a-proven-fabrication" aria-label="Permalink to &quot;4.3 The Benchmark Controversy: A Transparency Problem, Not a Proven Fabrication&quot;">&ZeroWidthSpace;</a></h3>
<p>This part needs the most careful phrasing:</p>
<ol>
<li><strong>Inconsistent scoring</strong>: V4-Pro's SWE-bench Verified score has two versions in circulation — 80.6% self-reported by the vendor versus 96.4% from third-party evaluator Vals — a 16-point gap most likely explained by different variants or methodologies, with no authoritative explanation available yet.</li>
<li><strong>Scores from minimal mode</strong>: the official agent benchmark numbers were run in dsh's minimal mode, so the question of &quot;does this score reflect the model's capability or the framework's boost&quot; is a fair one — though, seen from another angle, an open-source harness is precisely what makes &quot;reproduce it yourself&quot; possible for the first time.</li>
<li><strong>Non-public internal leaderboards</strong>: the official results table mixes in two non-public internal benchmarks (DSBench-FullStack and DSBench-Hard), and the two leaderboards rank things in contradictory order. Commentator MaxForAI's framing is worth keeping in mind: &quot;what benchmarks a lab builds for itself tends to reveal exactly what it's optimizing for.&quot;</li>
<li><strong>No one has publicly reproduced and disproven any official number yet.</strong> The skepticism is concentrated on transparency, not fabrication.</li>
</ol>
<p>Worth noting honestly as well: the release coincided with a V4-Pro API price increase (corroborated by multiple independent sources), plus some users grumbling that &quot;Pro writes worse code than Flash.&quot; That's a batch of negative sentiment unrelated to the harness itself but still coloring the discourse — and this kind of &quot;triple disappointment&quot; commentary generally comes without specific usage details, so it's of limited evidentiary value.</p>
<h2 id="part-five-conclusion" tabindex="-1">Part Five: Conclusion <a class="header-anchor" href="#part-five-conclusion" aria-label="Permalink to &quot;Part Five: Conclusion&quot;">&ZeroWidthSpace;</a></h2>
<h3 id="what-it-gets-right" tabindex="-1">What It Gets Right <a class="header-anchor" href="#what-it-gets-right" aria-label="Permalink to &quot;What It Gets Right&quot;">&ZeroWidthSpace;</a></h3>
<ol>
<li><strong>Genuinely new architecture</strong>: loop-as-plugin, a fully swappable runtime, subagents delegable to competing tools — none of these exist in Claude Code, Codex, or Pi.</li>
<li><strong>Traceability made into an architectural guarantee</strong>: for teams that need to audit, replay, or study agent behavior, this is currently unmatched.</li>
<li><strong>A thoroughly open posture</strong>: MIT license, no model lock-in, compatibility with a rival's MCP naming conventions, and a direct challenge to the &quot;pay for the harness&quot; business model.</li>
<li><strong>A rare display of engineering culture</strong>: 1,386 decision notes, docs gated against code drift, and the &quot;built with its own harness&quot; proof-of-concept — on its own, a valuable sample of AI-native engineering practice.</li>
</ol>
<h3 id="where-it-falls-short" tabindex="-1">Where It Falls Short <a class="header-anchor" href="#where-it-falls-short" aria-label="Permalink to &quot;Where It Falls Short&quot;">&ZeroWidthSpace;</a></h3>
<ol>
<li><strong>It's a preview build right now</strong>: the team itself has promised breaking changes; interfaces will shift dramatically, and production use isn't recommended.</li>
<li><strong>Niche needs, borne by everyone</strong>: the complexity and token overhead that come with the heavyweight runtime are paid by every user, while the benefit of &quot;hot-swap the loop at runtime&quot; only accrues to a small slice of explorers.</li>
<li><strong>Rough edges in efficiency and quality</strong>: a context-duplication bug, a roughly order-of-magnitude token gap, and near-zero third-party compatibility.</li>
<li><strong>Trust-building isn't finished</strong>: the transparency questions around benchmark methodology and internal leaderboards will need time and third-party reproduction to settle.</li>
</ol>
<h3 id="should-you-use-it" tabindex="-1">Should You Use It? <a class="header-anchor" href="#should-you-use-it" aria-label="Permalink to &quot;Should You Use It?&quot;">&ZeroWidthSpace;</a></h3>
<ul>
<li><strong>You just want a good coding agent to write code with</strong>: not recommended, at least not yet. Claude Code (for the ecosystem), Codex CLI (for safety and stability), and Pi (for minimalism and cost) are all more mature choices today.</li>
<li><strong>You work on agent infrastructure, multi-agent systems, or self-evolving agent research</strong>: it's worth a weekend to read the source and the <code>.agents/</code> directory — the capability-surface design and event-driven loop currently have no other working reference implementation.</li>
<li><strong>Your organization needs auditable agent execution records</strong>: worth watching closely — the append-only log is its least controversial strength.</li>
<li><strong>You're on the fence</strong>: give it three to six months. The plugin ecosystem will shake out, the interfaces will stabilize, and someone will reproduce the benchmarks. By then we'll know whether &quot;everything is a plugin&quot; grew into an Agent OS, or fell into the &quot;plugin fatigue&quot; that one HN commenter worried about.</li>
</ul>
<p>One closing thought. Reading through this repo, what came to mind wasn't a competing product — it was the history of operating systems: dsh is betting that &quot;agents will grow into systems complex enough to need an OS,&quot; while Pi is betting that &quot;an agent should stay a sharp, small knife.&quot; Both bets could very well pay off — they're just aimed at different users, on different timelines. And a model company choosing to lay its own evaluation harness fully open under MIT, decision records included, has already shifted the industry's baseline for what &quot;transparent&quot; means — regardless of how this particular bet turns out.</p>
<hr>
<p><em>This article is based on a snapshot of the repository (v0.1.0-rc.5) as of 2026-08-15, along with public community discussion. dsh is iterating quickly, and specific details here may age fast; all benchmark figures are labeled by source, and where vendor-reported and third-party numbers diverge, no conclusion has been reached — judge accordingly. Primary sources: <a href="https://github.com/deepseek-ai/deepseek-harness" target="_blank" rel="noreferrer">deepseek-ai/deepseek-harness</a>, the <a href="https://deepseek.com/harness/en/" target="_blank" rel="noreferrer">DeepSeek Harness website</a>, Hacker News discussion, long-form source-code analyses from several developers on X, and independent hands-on testing from ifanr, GeekPark, and 36Kr.</em></p>
]]></content:encoded>
            <author>just@justin3go.com (Justin3go)</author>
        </item>
        <item>
            <title><![CDATA[From "You Prompt the Agent" to "The System Prompts the Agent": A Complete Guide to Loop Engineering]]></title>
            <link>https://justin3go.com/en/posts/2026/07/08-loop-engineering-from-prompting-to-designing-loops</link>
            <guid>https://justin3go.com/en/posts/2026/07/08-loop-engineering-from-prompting-to-designing-loops</guid>
            <pubDate>Wed, 08 Jul 2026 00:00:00 GMT</pubDate>
            <description><![CDATA[<h1 id="from-you-prompt-the-agent-to-the-system-prompts-the-agent-a-complete-guide-to-loop-engineering" tabindex="-1">From &quot;You Prompt the Agent&quot; to &quot;The System Prompts the Agent&quot;: A Complete Guide to Loop Engineering <a class="header-anchor" href="#from-you-prompt-the-agent-to-the-system-prompts-the-agent-a-complete-guide-to-loop-engineering" aria-label="Permalink to &quot;From &quot;You Prompt the Agent&quot; to &quot;The System Prompts the Agent&quot;: A Complete Guide to Loop Engineering&quot;">&ZeroWidthSpace;</a></h1>
<blockquote>
<p>✨Article Summary (AI Generated)</p>
</blockquote>
<!-- DESC SEP -->
<blockquote></blockquote>
<p>Following the evolution from <strong>Prompt → Context → Harness → Loop</strong>, this article unpacks the origins of Loop Engineering, its six-stage control flow, verifiers, stopping conditions, and three essential guardrails. Through Ralph Loop, Claude Code's <code>/goal</code> and <code>/loop</code>, Codex Automations, and Karpathy's autoresearch, it shows that the new idea is not the <code>while</code> statement itself, but an engineering system that combines verification, budgets, external state, and feedback. It concludes with a task-selection matrix and adoption path, arguing that a loop's value is capped by a verifier the agent cannot game.</p>
<blockquote></blockquote>
<!-- DESC SEP -->
<h2 id="introduction-you-are-the-slowest-part-of-the-chain" tabindex="-1">Introduction: You Are the Slowest Part of the Chain <a class="header-anchor" href="#introduction-you-are-the-slowest-part-of-the-chain" aria-label="Permalink to &quot;Introduction: You Are the Slowest Part of the Chain&quot;">&ZeroWidthSpace;</a></h2>
<p>Consider a scene that plays out every day in 2026.</p>
<p>An engineer opens a terminal and tells a coding agent, “Fix the failing CI test.” The agent works for three minutes and reports back. The engineer reads the result: “No, you changed the wrong file; look at the auth module.” Three more minutes pass. “The test passes, but you broke another case.” After five rounds, the issue is fixed in forty minutes. The agent worked for fifteen of them. During the other twenty-five, it was <strong>waiting for a human to read output, make a decision, and type the next prompt</strong>.</p>
<p>Models reason faster and tools execute faster. The person at the keyboard has not. The bottleneck has moved from the model to the human.</p>
<p>At an Acquired Unplugged event hosted by WorkOS on June 2, 2026, Claude Code creator Boris Cherny described his response:</p>
<blockquote>
<p>“I don't prompt Claude anymore. I have loops that are running. They're the ones that are prompting Claude and figuring out what to do. My job is to write loops.”</p>
</blockquote>
<p>Five days later, OpenClaw creator Peter Steinberger, now at OpenAI, posted the viral line: “You shouldn't be prompting coding agents anymore. You should be designing loops that prompt your agents.” The following day, Google engineering leader Addy Osmani published <em>Loop Engineering</em> and gave the practice a name.</p>
<p>Rather than follow a research-report sequence of definition, timeline, and critique, this article traces the evolution of the developer-agent collaboration chain: how each layer emerged, what actually lives inside a loop, which parts are old ideas in new packaging, what is genuinely new, and whether your own work should use one.</p>
<h2 id="_1-four-delegations-prompt-→-context-→-harness-→-loop" tabindex="-1">1. Four Delegations: Prompt → Context → Harness → Loop <a class="header-anchor" href="#_1-four-delegations-prompt-→-context-→-harness-→-loop" aria-label="Permalink to &quot;1. Four Delegations: Prompt → Context → Harness → Loop&quot;">&ZeroWidthSpace;</a></h2>
<p>Loop engineering did not appear from nowhere. It is the fourth delegation of work along the same collaboration chain. At every layer, a human hands one more piece of manual work to the system and moves up a level.</p>
<p><img src="https://oss.justin3go.com/blogs/four-layer-stack.png" alt="Four nested layers: Prompt, Context, Harness, and Loop"></p>
<p>Each layer contains the previous one rather than replacing it. Loop authors still write prompts; those prompts have simply moved from words typed on the spot to templates assembled automatically during every iteration.</p>
<p>A popular Chinese-language analogy puts the four layers plainly:</p>
<blockquote>
<p>Prompt is how you ask it. Context is what you let it see. Harness is the environment you place it in. Loop is how you make that system turn by itself.</p>
</blockquote>
<p>| Layer | Rise | Authoritative source | Core idea |
|</p>
]]></description>
            <content:encoded><![CDATA[<h1 id="from-you-prompt-the-agent-to-the-system-prompts-the-agent-a-complete-guide-to-loop-engineering" tabindex="-1">From &quot;You Prompt the Agent&quot; to &quot;The System Prompts the Agent&quot;: A Complete Guide to Loop Engineering <a class="header-anchor" href="#from-you-prompt-the-agent-to-the-system-prompts-the-agent-a-complete-guide-to-loop-engineering" aria-label="Permalink to &quot;From &quot;You Prompt the Agent&quot; to &quot;The System Prompts the Agent&quot;: A Complete Guide to Loop Engineering&quot;">&ZeroWidthSpace;</a></h1>
<blockquote>
<p>✨Article Summary (AI Generated)</p>
</blockquote>
<!-- DESC SEP -->
<blockquote></blockquote>
<p>Following the evolution from <strong>Prompt → Context → Harness → Loop</strong>, this article unpacks the origins of Loop Engineering, its six-stage control flow, verifiers, stopping conditions, and three essential guardrails. Through Ralph Loop, Claude Code's <code>/goal</code> and <code>/loop</code>, Codex Automations, and Karpathy's autoresearch, it shows that the new idea is not the <code>while</code> statement itself, but an engineering system that combines verification, budgets, external state, and feedback. It concludes with a task-selection matrix and adoption path, arguing that a loop's value is capped by a verifier the agent cannot game.</p>
<blockquote></blockquote>
<!-- DESC SEP -->
<h2 id="introduction-you-are-the-slowest-part-of-the-chain" tabindex="-1">Introduction: You Are the Slowest Part of the Chain <a class="header-anchor" href="#introduction-you-are-the-slowest-part-of-the-chain" aria-label="Permalink to &quot;Introduction: You Are the Slowest Part of the Chain&quot;">&ZeroWidthSpace;</a></h2>
<p>Consider a scene that plays out every day in 2026.</p>
<p>An engineer opens a terminal and tells a coding agent, “Fix the failing CI test.” The agent works for three minutes and reports back. The engineer reads the result: “No, you changed the wrong file; look at the auth module.” Three more minutes pass. “The test passes, but you broke another case.” After five rounds, the issue is fixed in forty minutes. The agent worked for fifteen of them. During the other twenty-five, it was <strong>waiting for a human to read output, make a decision, and type the next prompt</strong>.</p>
<p>Models reason faster and tools execute faster. The person at the keyboard has not. The bottleneck has moved from the model to the human.</p>
<p>At an Acquired Unplugged event hosted by WorkOS on June 2, 2026, Claude Code creator Boris Cherny described his response:</p>
<blockquote>
<p>“I don't prompt Claude anymore. I have loops that are running. They're the ones that are prompting Claude and figuring out what to do. My job is to write loops.”</p>
</blockquote>
<p>Five days later, OpenClaw creator Peter Steinberger, now at OpenAI, posted the viral line: “You shouldn't be prompting coding agents anymore. You should be designing loops that prompt your agents.” The following day, Google engineering leader Addy Osmani published <em>Loop Engineering</em> and gave the practice a name.</p>
<p>Rather than follow a research-report sequence of definition, timeline, and critique, this article traces the evolution of the developer-agent collaboration chain: how each layer emerged, what actually lives inside a loop, which parts are old ideas in new packaging, what is genuinely new, and whether your own work should use one.</p>
<h2 id="_1-four-delegations-prompt-→-context-→-harness-→-loop" tabindex="-1">1. Four Delegations: Prompt → Context → Harness → Loop <a class="header-anchor" href="#_1-four-delegations-prompt-→-context-→-harness-→-loop" aria-label="Permalink to &quot;1. Four Delegations: Prompt → Context → Harness → Loop&quot;">&ZeroWidthSpace;</a></h2>
<p>Loop engineering did not appear from nowhere. It is the fourth delegation of work along the same collaboration chain. At every layer, a human hands one more piece of manual work to the system and moves up a level.</p>
<p><img src="https://oss.justin3go.com/blogs/four-layer-stack.png" alt="Four nested layers: Prompt, Context, Harness, and Loop"></p>
<p>Each layer contains the previous one rather than replacing it. Loop authors still write prompts; those prompts have simply moved from words typed on the spot to templates assembled automatically during every iteration.</p>
<p>A popular Chinese-language analogy puts the four layers plainly:</p>
<blockquote>
<p>Prompt is how you ask it. Context is what you let it see. Harness is the environment you place it in. Loop is how you make that system turn by itself.</p>
</blockquote>
<table tabindex="0">
<thead>
<tr>
<th>Layer</th>
<th>Rise</th>
<th>Authoritative source</th>
<th>Core idea</th>
</tr>
</thead>
<tbody>
<tr>
<td>Prompt engineering</td>
<td>2022–2024</td>
<td>Industry-wide practice, no single originator</td>
<td>How to state the task correctly</td>
</tr>
<tr>
<td>Context engineering</td>
<td>2024–2025</td>
<td>Tobi Lütke's June 18, 2025 post, amplified by Karpathy on June 25; Anthropic's <em>Effective context engineering for AI agents</em> (September 29, 2025)</td>
<td>“The art of providing all the context for the task to be plausibly solvable by the LLM”</td>
</tr>
<tr>
<td>Harness engineering</td>
<td>Late 2025</td>
<td>Anthropic's <em>Effective harnesses for long-running agents</em> (November 26, 2025; Justin Young et al.)</td>
<td>The model is the brain; the harness is the body</td>
</tr>
<tr>
<td>Loop engineering</td>
<td>June 2026</td>
<td>Addy Osmani's <em>Loop Engineering</em> (June 7, 2026)</td>
<td>Replace yourself as the person prompting the agent by designing the system that does it</td>
</tr>
</tbody>
</table>
<p>The timing closely matches Anthropic's engineering publications, although “loop engineering” itself is still not an official Anthropic term. Osmani's definition is the anchor for everything that follows:</p>
<blockquote>
<p>“A loop here can be thought of a recursive goal where you define a purpose and the AI iterates until complete.”</p>
</blockquote>
<h2 id="_2-anatomy-of-a-loop-six-stages-and-one-exit" tabindex="-1">2. Anatomy of a Loop: Six Stages and One Exit <a class="header-anchor" href="#_2-anatomy-of-a-loop-six-stages-and-one-exit" aria-label="Permalink to &quot;2. Anatomy of a Loop: Six Stages and One Exit&quot;">&ZeroWidthSpace;</a></h2>
<p>Anthropic's <em>Building agents with the Claude Agent SDK</em> (Thariq Shihipar, September 29, 2025) gives the minimal version: “gather context → take action → verify work → repeat.” The complete Loop Engineering control flow has six stages:</p>
<p><img src="https://oss.justin3go.com/blogs/six-stage-loop-control-flow.png" alt="Six-stage control flow: DISCOVER → ASSEMBLE → ACT → VERIFY → PERSIST → DECIDE, ending in another iteration or STOP"></p>
<p>The human's position has changed. Instead of standing inside ASSEMBLE and typing every turn, the engineer stands outside the graph, designs how the six stages connect and what qualifies as STOP, and then reviews the delivered result. Geoffrey Huntley puts it this way:</p>
<blockquote>
<p>“Your job is to sit on the loop, not in it.”</p>
</blockquote>
<h3 id="routine-workflow-and-loop" tabindex="-1">Routine, Workflow, and Loop <a class="header-anchor" href="#routine-workflow-and-loop" aria-label="Permalink to &quot;Routine, Workflow, and Loop&quot;">&ZeroWidthSpace;</a></h3>
<p>Not everything that runs automatically is a loop. There is one dividing line: <strong>does it inspect its own work and use that result to decide whether to continue?</strong></p>
<table tabindex="0">
<thead>
<tr>
<th></th>
<th>Routine</th>
<th>Workflow</th>
<th>Loop</th>
</tr>
</thead>
<tbody>
<tr>
<td>Steps</td>
<td>Fixed</td>
<td>Branch on discoveries</td>
<td>Dynamically iterative</td>
</tr>
<tr>
<td>Stop condition</td>
<td>All steps ran</td>
<td>A path ended</td>
<td>A verifier says the goal is met</td>
</tr>
<tr>
<td>Self-check</td>
<td>None</td>
<td>None or weak</td>
<td>Core mechanism</td>
</tr>
<tr>
<td>Example</td>
<td>Run lint on a timer and send a report</td>
<td>CI fails → classify → assign</td>
<td>Continue until every <code>test/auth</code> test and lint check passes</td>
</tr>
</tbody>
</table>
<p>This echoes Anthropic's classic distinction in <em>Building Effective AI Agents</em> (Erik Schluntz and Barry Zhang, December 19, 2024): workflows orchestrate LLMs and tools through predefined code paths, whereas agents dynamically direct their own process based on environmental feedback—in other words, they use tools inside a loop.</p>
<h2 id="_3-prehistory-loops-were-not-invented-in-2026" tabindex="-1">3. Prehistory: Loops Were Not Invented in 2026 <a class="header-anchor" href="#_3-prehistory-loops-were-not-invented-in-2026" aria-label="Permalink to &quot;3. Prehistory: Loops Were Not Invented in 2026&quot;">&ZeroWidthSpace;</a></h2>
<p>The control-flow diagram should look familiar. It is a cybernetic feedback loop, a thermostat, or a Kubernetes reconciliation loop. Academia and the community spent four years building it before “loop engineering” received a name.</p>
<p><img src="https://oss.justin3go.com/blogs/agent-loop-prehistory-timeline.png" alt="Timeline from ReAct to Reflexion, AutoGPT, Ralph Loop, and the Loop Engineering name"></p>
<p>ReAct, submitted on October 6, 2022 and later published at ICLR 2023, established the inner Thought → Action → Observation loop. Reflexion (Shinn et al., 2023) added self-critique and memory. AutoGPT showed the public both the appeal of “give it a goal and let it run” and the failure mode of disappearing down a rabbit hole.</p>
<h3 id="ralph-loop-proving-the-pattern-before-it-had-a-name" tabindex="-1">Ralph Loop: Proving the Pattern Before It Had a Name <a class="header-anchor" href="#ralph-loop-proving-the-pattern-before-it-had-a-name" aria-label="Permalink to &quot;Ralph Loop: Proving the Pattern Before It Had a Name&quot;">&ZeroWidthSpace;</a></h3>
<p>Geoffrey Huntley's <strong>Ralph loop</strong>, or Ralph Wiggum technique, first demonstrated publicly in June 2025 and published in July in <em>Ralph Wiggum as a “software engineer”</em>, proved the pattern before it had a label. Its entire implementation is one line of Bash:</p>
<div class="language-bash vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">bash</span><pre class="shiki shiki-themes github-light github-dark vp-code" tabindex="0" v-pre=""><code><span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">while</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF"> :</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">; </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">do</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0"> cat</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF"> PROMPT.md</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583"> |</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0"> claude-code</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8"> ; </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583">done</span></span></code></pre>
</div><p>That is all: an infinite loop feeding the same prompt file to a coding agent. Huntley's own definition was, “Ralph is a technique. In its purest form, Ralph is a Bash loop.”</p>
<p>The apparently foolish design contains one very smart decision: <strong>every iteration starts with a fresh context</strong>.</p>
<p><img src="https://oss.justin3go.com/blogs/ralph-context-comparison.png" alt="A decaying long conversation compared with Ralph's fresh context and externalized state on every iteration"></p>
<p>Progress is not something the model remembers; it is something the repository contains. Each agent wakes up, reads the spec, inspects the repository, analyzes the gap, completes one item, commits, and dies. Its successor sees everything through Git. Huntley's self-deprecating summary is perfect:</p>
<blockquote>
<p>“The technique is deterministically bad in an undeterministic world.”</p>
</blockquote>
<p>Ralph has impressive but qualified claims. A YC hackathon team reportedly ported six repositories overnight for about $600 in API usage and more than 1,000 commits. Huntley says three months of continuous operation produced CURSED, a programming language with a self-hosting compiler. Both reports come from advocates and lack independent reproduction. Huntley also drew a hard boundary: “There's no way in heck would I use Ralph in an existing code base.” It was for greenfield work.</p>
<p>Anthropic released an official Ralph Wiggum plugin in December 2025. The productization of a playful community hack marked the loop's transition into a platform primitive.</p>
<h2 id="_4-the-naming-event-ten-days-in-june-2026" tabindex="-1">4. The Naming Event: Ten Days in June 2026 <a class="header-anchor" href="#_4-the-naming-event-ten-days-in-june-2026" aria-label="Permalink to &quot;4. The Naming Event: Ten Days in June 2026&quot;">&ZeroWidthSpace;</a></h2>
<p>Why did a four-year-old pattern suddenly acquire a name and dominate discussion in June 2026? A short chain of public statements created the immediate spark.</p>
<p><img src="https://oss.justin3go.com/blogs/loop-engineering-naming-event-timeline.png" alt="The ten-day Loop Engineering naming timeline in June 2026"></p>
<p>Three deeper conditions were all necessary:</p>
<ol>
<li><strong>Models became strong enough.</strong> Opus 4.5+ and GPT-5.x-Codex-class models can operate autonomously for long periods and verify themselves through tests and compilers.</li>
<li><strong>Primitives became products.</strong> Claude Code's <code>/goal</code> and <code>/loop</code>, and Codex Automations, replaced much of the custom Bash required a year earlier.</li>
<li><strong>Leading practitioners spoke at once.</strong> Cherny, Steinberger, Karpathy, and Ng described loop-centered workflows during the same two weeks, giving a diffuse practice a name and credible faces.</li>
</ol>
<p>One widely repeated quote needs a warning label: Jensen Huang's alleged “Nobody writes prompts anymore. The new job is to write and handle loops.” No clean NVIDIA transcript verifies it, and reposts disagree even about whether the source video was 23 or 53 minutes long. Treat it as a paraphrase of a real direction, not an authenticated quotation.</p>
<h2 id="_5-method-five-building-blocks-one-memory-layer-four-nested-loops" tabindex="-1">5. Method: Five Building Blocks, One Memory Layer, Four Nested Loops <a class="header-anchor" href="#_5-method-five-building-blocks-one-memory-layer-four-nested-loops" aria-label="Permalink to &quot;5. Method: Five Building Blocks, One Memory Layer, Four Nested Loops&quot;">&ZeroWidthSpace;</a></h2>
<h3 id="osmani-s-building-blocks" tabindex="-1">Osmani's Building Blocks <a class="header-anchor" href="#osmani-s-building-blocks" aria-label="Permalink to &quot;Osmani's Building Blocks&quot;">&ZeroWidthSpace;</a></h3>
<p>Osmani describes five components plus an external-state layer. The structure maps almost directly onto both Claude Code and OpenAI Codex, evidence that loop shape is becoming tool-independent.</p>
<p><img src="https://oss.justin3go.com/blogs/osmani-five-building-blocks.png" alt="Osmani's loop anatomy: an AUTOMATIONS heartbeat, four building blocks, and EXTERNAL STATE"></p>
<p>His explanation for using sub-agents is memorable: “The model that wrote the code is too nice grading its own homework.”</p>
<h3 id="langchain-s-four-layer-loop-stack" tabindex="-1">LangChain's Four-Layer Loop Stack <a class="header-anchor" href="#langchain-s-four-layer-loop-stack" aria-label="Permalink to &quot;LangChain's Four-Layer Loop Stack&quot;">&ZeroWidthSpace;</a></h3>
<p>Sydney Runkle at LangChain described four nested loops on June 16, 2026, each operating at a different order of time scale.</p>
<p><img src="https://oss.justin3go.com/blogs/langchain-four-loop-stack.png" alt="LangChain's four nested layers: agent loop, validation loop, event-driven loop, and hill-climbing loop"></p>
<p>Loops 1 and 2 complete the immediate work. <strong>Compounding happens in Loops 3 and 4</strong>: systems learn from production traces and improve their own configuration. Andrew Ng's three loops express the same idea at different granularity: coding in minutes, developer feedback in hours, and external feedback in days or weeks.</p>
<h2 id="_6-the-load-bearing-wall-the-verifier" tabindex="-1">6. The Load-Bearing Wall: The Verifier <a class="header-anchor" href="#_6-the-load-bearing-wall-the-verifier" aria-label="Permalink to &quot;6. The Load-Bearing Wall: The Verifier&quot;">&ZeroWidthSpace;</a></h2>
<p>If you remember one sentence from Loop Engineering, make it this: <strong>a loop's value is capped by its verifier, not its model</strong>.</p>
<p>Without a reliable test for completion, a loop either never stops or stops in the wrong place and confidently reports success. Serious 2026 writing converges completely on this point.</p>
<h3 id="separate-the-maker-from-the-checker" tabindex="-1">Separate the Maker From the Checker <a class="header-anchor" href="#separate-the-maker-from-the-checker" aria-label="Permalink to &quot;Separate the Maker From the Checker&quot;">&ZeroWidthSpace;</a></h3>
<p><img src="https://oss.justin3go.com/blogs/maker-checker-separation.png" alt="The MAKER and CHECKER iterate until the work is ready for human review"></p>
<p>The community's rule is uncompromising: “The checker is never the same agent as the maker.” It follows the same separation of powers as the initializer and coding agents in Anthropic's harness work.</p>
<h3 id="good-and-bad-stopping-conditions" tabindex="-1">Good and Bad Stopping Conditions <a class="header-anchor" href="#good-and-bad-stopping-conditions" aria-label="Permalink to &quot;Good and Bad Stopping Conditions&quot;">&ZeroWidthSpace;</a></h3>
<table tabindex="0">
<thead>
<tr>
<th></th>
<th>Bad loop goal</th>
<th>Good loop goal</th>
</tr>
</thead>
<tbody>
<tr>
<td>Example</td>
<td>“Improve this code”</td>
<td>“All tests under <code>test/auth</code> pass and lint is clean”</td>
</tr>
<tr>
<td>Checkability</td>
<td>Subjective</td>
<td>Machine-verifiable</td>
</tr>
<tr>
<td>Loop behavior</td>
<td>Never knows when to stop</td>
<td>Has an explicit exit</td>
</tr>
<tr>
<td>Gameability</td>
<td>Undefined</td>
<td>Must defend against reward hacking</td>
</tr>
</tbody>
</table>
<h3 id="four-failure-modes" tabindex="-1">Four Failure Modes <a class="header-anchor" href="#four-failure-modes" aria-label="Permalink to &quot;Four Failure Modes&quot;">&ZeroWidthSpace;</a></h3>
<table tabindex="0">
<thead>
<tr>
<th>Failure mode</th>
<th>Typical case</th>
<th>Countermeasure</th>
</tr>
</thead>
<tbody>
<tr>
<td>Reward hacking</td>
<td>Delete the failing test to make CI green</td>
<td>Also verify that test count did not decrease; Anthropic's harness rule says, “It is unacceptable to remove or edit tests.”</td>
</tr>
<tr>
<td>Hallucinated success</td>
<td>Agent says “done” without a working result</td>
<td>Trust deterministic verification, never self-reporting</td>
</tr>
<tr>
<td>Error compounding along the trajectory</td>
<td>A small error in iteration 3 becomes a disaster in iteration 15</td>
<td>Small commits and independent verification on every iteration</td>
</tr>
<tr>
<td>Runaway cost</td>
<td>The loop spins overnight and produces a four-figure bill</td>
<td>Install the three guardrails in the next section</td>
</tr>
</tbody>
</table>
<h3 id="how-goal-builds-the-verifier-into-stop" tabindex="-1">How <code>/goal</code> Builds the Verifier Into STOP <a class="header-anchor" href="#how-goal-builds-the-verifier-into-stop" aria-label="Permalink to &quot;How `/goal` Builds the Verifier Into STOP&quot;">&ZeroWidthSpace;</a></h3>
<p>Claude Code's <code>/goal</code>, released in v2.1.139 on May 11, 2026 and checked against official documentation, is a useful specimen: maker and checker are built directly into the stopping condition.</p>
<p><img src="https://oss.justin3go.com/blogs/goal-stop-hook-mechanism.png" alt="The  Stop hook uses a smaller evaluator model to decide NO or YES"></p>
<p>The worker and evaluator are different models with different perspectives—the product form of maker/checker separation.</p>
<h2 id="_7-three-guardrails-to-install-on-day-one" tabindex="-1">7. Three Guardrails to Install on Day One <a class="header-anchor" href="#_7-three-guardrails-to-install-on-day-one" aria-label="Permalink to &quot;7. Three Guardrails to Install on Day One&quot;">&ZeroWidthSpace;</a></h2>
<p>The second consensus among serious writers is that guardrails are mandatory. A loop without guardrails is a liability, not an asset.</p>
<p><img src="https://oss.justin3go.com/blogs/three-guardrails-flowchart.png" alt="Guardrail flow: iteration cap → progress detection → budget cap → verifier"></p>
<p>The budget guardrail has a repeatedly cited real-world footnote. According to secondary reporting, Uber exhausted its annual AI budget in four months and then capped agent tooling at $1,500 per engineer per month. A budget ceiling is not paranoia; someone has already paid the tuition.</p>
<h2 id="_8-the-primitives-have-been-productized" tabindex="-1">8. The Primitives Have Been Productized <a class="header-anchor" href="#_8-the-primitives-have-been-productized" aria-label="Permalink to &quot;8. The Primitives Have Been Productized&quot;">&ZeroWidthSpace;</a></h2>
<p>The table explains another part of “why now.” What required hand-maintained Bash in 2025 became a product feature in 2026.</p>
<table tabindex="0">
<thead>
<tr>
<th>Loop primitive</th>
<th>Claude Code</th>
<th>OpenAI Codex</th>
</tr>
</thead>
<tbody>
<tr>
<td>Scheduled heartbeat</td>
<td><code>/loop</code> (v2.1.72+, dynamic 1 minute–1 hour or fixed, e.g. <code>/loop 15m</code>), <code>/schedule</code>, cron, hooks, GitHub Actions</td>
<td>Automations tab plus Triage inbox</td>
</tr>
<tr>
<td>Goal-driven stopping</td>
<td><code>/goal</code></td>
<td>Corresponding <code>/goal</code></td>
</tr>
<tr>
<td>Parallel isolation</td>
<td><code>git worktree</code>, <code>--worktree</code>, <code>isolation: worktree</code></td>
<td>Worktrees</td>
</tr>
<tr>
<td>Knowledge capture</td>
<td><code>SKILL.md</code></td>
<td><code>SKILL.md</code></td>
</tr>
<tr>
<td>Sub-agents</td>
<td>Subagent mechanism</td>
<td>TOML definitions under <code>.codex/agents/</code></td>
</tr>
<tr>
<td>External connections</td>
<td>MCP</td>
<td>MCP connectors</td>
</tr>
<tr>
<td>Batch dispatch</td>
<td><code>/batch</code> with parallel worktree agents; based on a secondary source, not verified against official docs</td>
<td>Historically, one-shot <code>codex exec</code> wrapped by Bash, such as codex-autoresearch-harness</td>
</tr>
</tbody>
</table>
<p>Boris Cherny's example of how a typical day begins is Loop Engineering's hello world:</p>
<div class="language-text vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">text</span><pre class="shiki shiki-themes github-light github-dark vp-code" tabindex="0" v-pre=""><code><span class="line"><span>/loop babysit all my PRs. Auto-fix build issues, and when comments</span></span>
<span class="line"><span>come in, use a worktree agent to fix them.</span></span></code></pre>
</div><p>His own record is the strongest first-hand evidence in the field. In the 30 days ending in late December 2025—not June 2026, as later retellings often claim—he landed <strong>259 PRs, 497 commits, +40K/−38K lines</strong>, all written by Claude Code with Opus 4.5. He had uninstalled his IDE in November 2025.</p>
<p>The same shape appears outside coding. Andrej Karpathy's autoresearch, released March 7, 2026, gained roughly 25,000 GitHub stars in five days and more than 66,000 by early April. It loops through propose change → train → evaluate, retaining only changes that lower validation loss and using Git revert for failed experiments. The first demonstration reportedly ran about 700 experiments in two days. Fortune called it “The Karpathy Loop.” Loop, mechanical verifier, and externalized Git state are all present.</p>
<h2 id="_9-a-cooler-look-three-critiques-and-what-each-gets-right" tabindex="-1">9. A Cooler Look: Three Critiques and What Each Gets Right <a class="header-anchor" href="#_9-a-cooler-look-three-critiques-and-what-each-gets-right" aria-label="Permalink to &quot;9. A Cooler Look: Three Critiques and What Each Gets Right&quot;">&ZeroWidthSpace;</a></h2>
<p>Popular concepts attract a backlash. All three major critiques deserve attention because each contains something true.</p>
<table tabindex="0">
<thead>
<tr>
<th>Critique</th>
<th>Representative</th>
<th>Argument</th>
<th>What it gets right</th>
<th>Response</th>
</tr>
</thead>
<tbody>
<tr>
<td>“It is just a while loop”</td>
<td>A roughly 1,800-comment Hacker News thread; extra-steps.dev</td>
<td>Strip away the vocabulary and this is an LLM call inside <code>while</code>; CI, autoscalers, and Kubernetes have used loops for years</td>
<td>Technically correct: the primitive is not new</td>
<td>The new content is discipline—timer, verifier, and budget. An infinite loop is a missing stop condition, not an indictment of <code>for</code> loops.</td>
</tr>
<tr>
<td>Economic critique</td>
<td>Ed Zitron</td>
<td>“Does OpenAI invoice itself for token use?” Vendors encourage autonomous token consumption; Cherny is mocked as someone allowed to burn $130K per month, a dubious secondary figure</td>
<td>Advocates often sell tokens or receive heavy subsidies</td>
<td>Budget guardrails are the engineering response; constrained loops can still have positive ROI for selected tasks</td>
</tr>
<tr>
<td>Preconditions critique</td>
<td>Gergely Orosz, <em>The Pragmatic Engineer</em></td>
<td>Most people lack a loop use case unless they have unlimited tokens and find turn-by-turn prompting too slow</td>
<td>Loops are excessive for one-off, exploratory work</td>
<td>The task matrix in the next section exists because loops were never a universal solution</td>
</tr>
</tbody>
</table>
<p>Osmani himself warns about <strong>comprehension debt</strong>: the faster a loop produces code, the wider the gap between the code that exists and the code you understand. Two people can build the same loop and obtain opposite results. <em>The Register</em> argued on June 24, 2026 that his conclusion undercut the concept because loops change the work without removing the engineer.</p>
<p>Osmani's closing line sets the right tone:</p>
<blockquote>
<p>“Build the loop. But build it like someone who intends to stay the engineer, not just the person who presses go.”</p>
</blockquote>
<h2 id="_10-decision-which-tasks-belong-in-a-loop" tabindex="-1">10. Decision: Which Tasks Belong in a Loop? <a class="header-anchor" href="#_10-decision-which-tasks-belong-in-a-loop" aria-label="Permalink to &quot;10. Decision: Which Tasks Belong in a Loop?&quot;">&ZeroWidthSpace;</a></h2>
<p>The decision matrix compresses the argument into two axes: can “done” be mechanically verified, and what is the cost of failure?</p>
<p><img src="https://oss.justin3go.com/blogs/loop-decision-matrix.png" alt="Loop decision matrix: mechanical verifiability of completion versus cost of failure"></p>
<p>The five task types in the lower-right share three traits: they are repeatable, machine-verifiable, and inexpensive to get wrong. Start there. A concrete graduation criterion from the research is: <strong>run one loop unattended for a full week, exceed the budget zero times, and have more than 90% of its PRs mergeable after your review</strong>. Only then expand its authority.</p>
<p>The adoption order matters: build the verifier before the loop.</p>
<p><img src="https://oss.justin3go.com/blogs/loop-adoption-sequence.png" alt="Five-step adoption sequence with the verifier before the loop itself"></p>
<h2 id="epilogue-the-scarce-skill-has-moved" tabindex="-1">Epilogue: The Scarce Skill Has Moved <a class="header-anchor" href="#epilogue-the-scarce-skill-has-moved" aria-label="Permalink to &quot;Epilogue: The Scarce Skill Has Moved&quot;">&ZeroWidthSpace;</a></h2>
<p>Return to the engineer in the introduction. Of forty minutes spent fixing tests, the human occupied twenty-five. Loop Engineering does not answer with “type faster.” It removes the person from the chain and replaces each intervention with a verifier plus three guardrails.</p>
<p>The scarce skill is no longer phrasing—the prompt layer addressed that. It is no longer supplying material—the context layer addressed that. It is not even building the environment, which harness products are increasingly solving. It is <strong>writing a stopping condition the loop cannot fool</strong>.</p>
<p>Someone who can write that condition can let 259 PRs grow in 30 days. Someone who cannot gets a loop that deletes tests to turn CI green and a four-figure bill.</p>
<p>They may have built exactly the same loop.</p>
]]></content:encoded>
            <author>just@justin3go.com (Justin3go)</author>
        </item>
        <item>
            <title><![CDATA[Agent Memory: From Stateless Models to Persistent Minds]]></title>
            <link>https://justin3go.com/en/posts/2026/06/04-agent-memory-architecture-guide</link>
            <guid>https://justin3go.com/en/posts/2026/06/04-agent-memory-architecture-guide</guid>
            <pubDate>Thu, 04 Jun 2026 00:00:00 GMT</pubDate>
            <description><![CDATA[<h1 id="agent-memory-from-stateless-models-to-persistent-minds" tabindex="-1">Agent Memory: From Stateless Models to Persistent Minds <a class="header-anchor" href="#agent-memory-from-stateless-models-to-persistent-minds" aria-label="Permalink to &quot;Agent Memory: From Stateless Models to Persistent Minds&quot;">&ZeroWidthSpace;</a></h1>
<blockquote>
<p>✨Article Summary (AI Generated)</p>
</blockquote>
<!-- DESC SEP -->
<blockquote></blockquote>
<p>Starting from the fundamental constraint that large language models are stateless, this article breaks agent memory into a four-stage lifecycle: <strong>extraction, storage, retrieval, and update/forgetting</strong>. It compares vector stores, temporal knowledge graphs, and file-based memory through systems such as Mem0, Letta, Graphiti, Codex, and Claude Code. The central conclusion is that long-running memory depends less on a fashionable retrieval backend than on auditable maintenance, merge-before-add discipline, and forgetting driven by real usage.</p>
<blockquote></blockquote>
<!-- DESC SEP -->
<h2 id="tl-dr" tabindex="-1">TL;DR <a class="header-anchor" href="#tl-dr" aria-label="Permalink to &quot;TL;DR&quot;">&ZeroWidthSpace;</a></h2>
<ul>
<li><strong>Memory is an engineering workaround for a finite context window.</strong> An LLM is stateless; an external system must put the right part of the past back into the current context. Every memory system can be understood through four stages: <strong>extraction → storage → retrieval → update/forgetting</strong>.</li>
<li>Three trade-offs appear repeatedly: passive extraction versus active self-editing, vectors versus graphs versus files, and database-backed memory middleware versus human-readable memory for personal and coding agents.</li>
<li>Mainstream products are converging on the same shape: <strong>a compressed long-term profile plus raw recent working memory</strong>.</li>
<li>Update and forgetting separate a demo from a system that can operate for years. The emerging principles are “merge before adding” and “keep raw records separate from compressed views.”</li>
<li>Do not put too much faith in benchmarks. Letta's plain filesystem setup with GPT-4o-mini scored 74.0% on LoCoMo, above the 68.5% reported for Mem0's best graph variant. Evaluate with your own data.</li>
</ul>
<p>Let us begin with a fact that is easy to overlook but shapes this entire field: <strong>a large language model is stateless</strong>.</p>
<p>An LLM call is essentially a tokens-in, tokens-out function. Anything you teach it in one conversation—your name, your preference for pnpm over npm, or the pitfall you hit last week—disappears from the next call unless an external system puts that information back into the context window. “An agent has memory” therefore does not mean that the model truly remembers. It means that <strong>a surrounding system feeds the right part of the past back at the right time</strong>.</p>
<p>A larger context window does not remove the problem. Mem0 reported a full-context baseline with a p95 latency of <strong>17.12 seconds</strong> and roughly <strong>26K tokens</strong> per request. A memory-based approach used about <strong>1,764 tokens</strong> of selected facts with roughly <strong>0.2 seconds</strong> of search latency, saving around <strong>90% of the tokens</strong> and <strong>91% of the latency</strong>.</p>
<blockquote>
<p>A memory system is fundamentally an <strong>engineering workaround for a finite context window</strong>. It exchanges roughly 1.8K tokens of selected facts for 26K tokens of raw history and balances capacity, cost, and latency.</p>
</blockquote>
<p><img src="https://oss.justin3go.com/blogs/memory-vs-fullcontext.png" alt="Agent memory works around a finite context window by replacing roughly 26K tokens of history with 1.8K tokens of selected facts"></p>
<p>All later design questions—what to save, where to save it, how to retrieve it, and how to forget it—reduce to one parent question: <strong>with a limited context budget, how can an agent behave as if it remembered everything?</strong></p>
<h2 id="a-conceptual-map-of-memory" tabindex="-1">A Conceptual Map of Memory <a class="header-anchor" href="#a-conceptual-map-of-memory" aria-label="Permalink to &quot;A Conceptual Map of Memory&quot;">&ZeroWidthSpace;</a></h2>
<h3 id="short-term-vs-long-term-memory" tabindex="-1">Short-Term vs. Long-Term Memory <a class="header-anchor" href="#short-term-vs-long-term-memory" aria-label="Permalink to &quot;Short-Term vs. Long-Term Memory&quot;">&ZeroWidthSpace;</a></h3>
<p><strong>Short-term memory</strong>, also called working memory, is the context inside the current conversation or thread: recent messages, tool results, intermediate reasoning, and unfinished plans. Its lifetime is normally the lifetime of that session.</p>
<p><strong>Long-term memory</strong> persists across sessions and threads. It lives in a database, vector store, graph, or file and supports personalization and continued learning.</p>
<p>LangGraph makes this boundary explicit through two separate persistence mechanisms:</p>
<p>| | Checkpointer (short-term) | Store (long-term) |
|</p>
]]></description>
            <content:encoded><![CDATA[<h1 id="agent-memory-from-stateless-models-to-persistent-minds" tabindex="-1">Agent Memory: From Stateless Models to Persistent Minds <a class="header-anchor" href="#agent-memory-from-stateless-models-to-persistent-minds" aria-label="Permalink to &quot;Agent Memory: From Stateless Models to Persistent Minds&quot;">&ZeroWidthSpace;</a></h1>
<blockquote>
<p>✨Article Summary (AI Generated)</p>
</blockquote>
<!-- DESC SEP -->
<blockquote></blockquote>
<p>Starting from the fundamental constraint that large language models are stateless, this article breaks agent memory into a four-stage lifecycle: <strong>extraction, storage, retrieval, and update/forgetting</strong>. It compares vector stores, temporal knowledge graphs, and file-based memory through systems such as Mem0, Letta, Graphiti, Codex, and Claude Code. The central conclusion is that long-running memory depends less on a fashionable retrieval backend than on auditable maintenance, merge-before-add discipline, and forgetting driven by real usage.</p>
<blockquote></blockquote>
<!-- DESC SEP -->
<h2 id="tl-dr" tabindex="-1">TL;DR <a class="header-anchor" href="#tl-dr" aria-label="Permalink to &quot;TL;DR&quot;">&ZeroWidthSpace;</a></h2>
<ul>
<li><strong>Memory is an engineering workaround for a finite context window.</strong> An LLM is stateless; an external system must put the right part of the past back into the current context. Every memory system can be understood through four stages: <strong>extraction → storage → retrieval → update/forgetting</strong>.</li>
<li>Three trade-offs appear repeatedly: passive extraction versus active self-editing, vectors versus graphs versus files, and database-backed memory middleware versus human-readable memory for personal and coding agents.</li>
<li>Mainstream products are converging on the same shape: <strong>a compressed long-term profile plus raw recent working memory</strong>.</li>
<li>Update and forgetting separate a demo from a system that can operate for years. The emerging principles are “merge before adding” and “keep raw records separate from compressed views.”</li>
<li>Do not put too much faith in benchmarks. Letta's plain filesystem setup with GPT-4o-mini scored 74.0% on LoCoMo, above the 68.5% reported for Mem0's best graph variant. Evaluate with your own data.</li>
</ul>
<p>Let us begin with a fact that is easy to overlook but shapes this entire field: <strong>a large language model is stateless</strong>.</p>
<p>An LLM call is essentially a tokens-in, tokens-out function. Anything you teach it in one conversation—your name, your preference for pnpm over npm, or the pitfall you hit last week—disappears from the next call unless an external system puts that information back into the context window. “An agent has memory” therefore does not mean that the model truly remembers. It means that <strong>a surrounding system feeds the right part of the past back at the right time</strong>.</p>
<p>A larger context window does not remove the problem. Mem0 reported a full-context baseline with a p95 latency of <strong>17.12 seconds</strong> and roughly <strong>26K tokens</strong> per request. A memory-based approach used about <strong>1,764 tokens</strong> of selected facts with roughly <strong>0.2 seconds</strong> of search latency, saving around <strong>90% of the tokens</strong> and <strong>91% of the latency</strong>.</p>
<blockquote>
<p>A memory system is fundamentally an <strong>engineering workaround for a finite context window</strong>. It exchanges roughly 1.8K tokens of selected facts for 26K tokens of raw history and balances capacity, cost, and latency.</p>
</blockquote>
<p><img src="https://oss.justin3go.com/blogs/memory-vs-fullcontext.png" alt="Agent memory works around a finite context window by replacing roughly 26K tokens of history with 1.8K tokens of selected facts"></p>
<p>All later design questions—what to save, where to save it, how to retrieve it, and how to forget it—reduce to one parent question: <strong>with a limited context budget, how can an agent behave as if it remembered everything?</strong></p>
<h2 id="a-conceptual-map-of-memory" tabindex="-1">A Conceptual Map of Memory <a class="header-anchor" href="#a-conceptual-map-of-memory" aria-label="Permalink to &quot;A Conceptual Map of Memory&quot;">&ZeroWidthSpace;</a></h2>
<h3 id="short-term-vs-long-term-memory" tabindex="-1">Short-Term vs. Long-Term Memory <a class="header-anchor" href="#short-term-vs-long-term-memory" aria-label="Permalink to &quot;Short-Term vs. Long-Term Memory&quot;">&ZeroWidthSpace;</a></h3>
<p><strong>Short-term memory</strong>, also called working memory, is the context inside the current conversation or thread: recent messages, tool results, intermediate reasoning, and unfinished plans. Its lifetime is normally the lifetime of that session.</p>
<p><strong>Long-term memory</strong> persists across sessions and threads. It lives in a database, vector store, graph, or file and supports personalization and continued learning.</p>
<p>LangGraph makes this boundary explicit through two separate persistence mechanisms:</p>
<table tabindex="0">
<thead>
<tr>
<th></th>
<th>Checkpointer (short-term)</th>
<th>Store (long-term)</th>
</tr>
</thead>
<tbody>
<tr>
<td>Scope</td>
<td>Thread or session</td>
<td>User or application, across threads</td>
</tr>
<tr>
<td>Contents</td>
<td>Graph state, <code>state[&quot;messages&quot;]</code>, conversational context</td>
<td>Cross-session KV data, preferences, and profiles</td>
</tr>
<tr>
<td>Lifetime</td>
<td>Disappears with a new <code>thread_id</code></td>
<td>Persists across sessions and threads</td>
</tr>
<tr>
<td>Analogy</td>
<td>Process memory</td>
<td>Disk outside the process</td>
</tr>
</tbody>
</table>
<blockquote>
<p><strong>Confusing short-term and long-term memory is one of the most common architecture mistakes in agent systems.</strong> Put a user preference in a thread checkpointer and it vanishes when the user starts a new session. Put transient scratch work in a long-term store and that store quickly decays into noisy, misleading context.</p>
</blockquote>
<p>Short-term memory preserves continuity <strong>within</strong> a conversation. Long-term memory preserves continuity <strong>across</strong> conversations. They need different storage media, write triggers, and cleanup policies.</p>
<h3 id="coala-s-four-categories—and-the-disagreement-around-them" tabindex="-1">CoALA's Four Categories—and the Disagreement Around Them <a class="header-anchor" href="#coala-s-four-categories—and-the-disagreement-around-them" aria-label="Permalink to &quot;CoALA's Four Categories—and the Disagreement Around Them&quot;">&ZeroWidthSpace;</a></h3>
<p>The 2023 Princeton paper <em>Cognitive Architectures for Language Agents</em> (CoALA, arXiv:2309.02427) popularized a four-way classification:</p>
<table tabindex="0">
<thead>
<tr>
<th>Category</th>
<th>What it stores</th>
<th>Intuition</th>
</tr>
</thead>
<tbody>
<tr>
<td><strong>Working</strong></td>
<td>Current context, observations, reasoning, partial plans</td>
<td>A limited short-term scratchpad</td>
</tr>
<tr>
<td><strong>Episodic</strong></td>
<td>Specific past events and outcomes</td>
<td>Lets an agent learn from interaction history</td>
</tr>
<tr>
<td><strong>Semantic</strong></td>
<td>Facts about the world or user</td>
<td>The gap not already covered by pretraining</td>
</tr>
<tr>
<td><strong>Procedural</strong></td>
<td>Learned rules, skills, and how-to knowledge</td>
<td>The ability to do something</td>
</tr>
</tbody>
</table>
<p>This vocabulary draws on cognitive psychology, including Tulving's distinction between episodic and semantic memory, Squire's work on procedural memory, and Baddeley and Hitch's working-memory model. IBM, MongoDB, LangChain, Letta, and Mem0 all use variants of it.</p>
<p>By late 2025, however, the field had started to split. Letta's Sarah Wooders rejected the brain analogy: an LLM is a tokens-in, tokens-out function, not a brain, so memory should be designed around information entering and leaving the context window. A December 2025 survey, <em>Memory in the Age of AI Agents</em> (arXiv:2512.13564), proposed a simpler taxonomy: factual, experiential, and working memory.</p>
<p>There is no need to choose a camp. CoALA gives teams a shared vocabulary; the engineering view reminds us that the decisive question is not which label a memory receives, but whether the right information enters the context at the right moment.</p>
<h2 id="the-memory-lifecycle-a-unifying-framework" tabindex="-1">The Memory Lifecycle: A Unifying Framework <a class="header-anchor" href="#the-memory-lifecycle-a-unifying-framework" aria-label="Permalink to &quot;The Memory Lifecycle: A Unifying Framework&quot;">&ZeroWidthSpace;</a></h2>
<p>The most useful way to compare systems is through a memory's complete lifecycle:</p>
<blockquote>
<p><strong>Extraction → Storage → Retrieval → Update/Forgetting</strong></p>
</blockquote>
<ul>
<li><strong>Extraction</strong> decides what is worth remembering.</li>
<li><strong>Storage</strong> decides where it lives and in what representation: vector, graph, KV, relational database, or text file.</li>
<li><strong>Retrieval</strong> decides when and how it returns to the model: semantic search, keywords, graph traversal, or direct prompt injection.</li>
<li><strong>Update/forgetting</strong> resolves conflicts, merges duplicates, and expires or decays stale information.</li>
</ul>
<p><img src="https://oss.justin3go.com/blogs/lifecycle-four-stages.png" alt="The four-stage memory lifecycle: extraction, storage, retrieval, and update or forgetting"></p>
<p>Frameworks differ because they make different choices in these four stages. Mem0 extracts facts passively; Letta lets the agent edit memory through tools. Graphiti invests heavily in update and forgetting through a bi-temporal model. Once a product is placed into these four boxes, its real trade-offs become easier to see.</p>
<h2 id="stage-one-extraction—what-to-remember-and-who-writes-it" tabindex="-1">Stage One: Extraction—What to Remember, and Who Writes It <a class="header-anchor" href="#stage-one-extraction—what-to-remember-and-who-writes-it" aria-label="Permalink to &quot;Stage One: Extraction—What to Remember, and Who Writes It&quot;">&ZeroWidthSpace;</a></h2>
<p>Extraction answers two questions: <strong>who writes memory</strong>, and <strong>what gets extracted</strong>. Information lost here cannot be recovered by a stronger retriever later.</p>
<h3 id="four-ways-to-write-memory" tabindex="-1">Four Ways to Write Memory <a class="header-anchor" href="#four-ways-to-write-memory" aria-label="Permalink to &quot;Four Ways to Write Memory&quot;">&ZeroWidthSpace;</a></h3>
<table tabindex="0">
<thead>
<tr>
<th>Mode</th>
<th>Writer</th>
<th>Examples</th>
<th>Characteristic</th>
</tr>
</thead>
<tbody>
<tr>
<td><strong>Direct append</strong></td>
<td>The system</td>
<td>MetaGPT, Pi</td>
<td>Saves everything without distillation</td>
</tr>
<tr>
<td><strong>LLM extraction</strong></td>
<td>A separate LLM call</td>
<td>Mem0, crewAI, Codex, Graphiti</td>
<td>Distills facts, triples, or insights</td>
</tr>
<tr>
<td><strong>Agent self-editing</strong></td>
<td>The main model through tools</td>
<td>Letta, Claude Code auto memory</td>
<td>The model decides what to rewrite</td>
</tr>
<tr>
<td><strong>Manual maintenance</strong></td>
<td>A human</td>
<td><code>CLAUDE.md</code>, <code>AGENTS.md</code></td>
<td>Human-written instructions; agent reads only</td>
</tr>
</tbody>
</table>
<p>Direct append is cheap and loses no information, but raw logs eventually become too large to feed back into the model. LLM extraction is the database-oriented mainstream: a separate call distills a conversation into structured facts, triples, insights, or experience entries.</p>
<p>Agent self-editing gives the main model tools such as <code>core_memory_append</code>, <code>memory_replace</code>, <code>memory_insert</code>, and <code>memory_rethink</code>. It makes nuanced decisions with full context, but every memory operation spends inference tokens. Manual files offer the highest control and quality but do not scale.</p>
<p>Real systems combine modes. Codex layers human-authored <code>AGENTS.md</code>, LLM-distilled <code>~/.codex/memories/</code>, and append-only session logs. Claude Code combines <code>CLAUDE.md</code> with model-written auto memory.</p>
<p><img src="https://oss.justin3go.com/blogs/classification-matrix.png" alt="Fifteen projects mapped by file versus database storage and by who writes memory"></p>
<p>The matrix has two revealing empty corners. File systems rarely use unfiltered append because files are meant for humans to read. Databases rarely rely entirely on human maintenance because people cannot fill machine-scale retrieval stores. Both sides therefore converge on <strong>LLM extraction</strong>.</p>
<h3 id="what-different-systems-extract" tabindex="-1">What Different Systems Extract <a class="header-anchor" href="#what-different-systems-extract" aria-label="Permalink to &quot;What Different Systems Extract&quot;">&ZeroWidthSpace;</a></h3>
<p><strong>Mem0 extracts general personal facts and preferences.</strong> Its <code>FACT_RETRIEVAL_PROMPT</code> turns dialogue into short, self-contained statements such as <code>Name is John</code>. Newer defaults lean toward ADD-only extraction, retaining separate details instead of aggressively merging them.</p>
<p><strong>Codex extracts four high-signal categories:</strong> user preferences, reusable knowledge, failure shields in the form <code>symptom → cause → fix</code>, and repository maps. It deliberately underindexes assistant claims and overindexes user statements and code evidence. Missing a fact is preferable to storing the agent's speculation as truth.</p>
<p><strong>AutoGen learns insights from failure.</strong> Its task-centric memory repeats a task and, after an incorrect answer, asks an LLM to distill an insight from that failure. This resembles procedural memory more than a passive record.</p>
<h3 id="passive-extraction-vs-active-self-editing" tabindex="-1">Passive Extraction vs. Active Self-Editing <a class="header-anchor" href="#passive-extraction-vs-active-self-editing" aria-label="Permalink to &quot;Passive Extraction vs. Active Self-Editing&quot;">&ZeroWidthSpace;</a></h3>
<table tabindex="0">
<thead>
<tr>
<th></th>
<th>Passive extraction</th>
<th>Active self-editing</th>
</tr>
</thead>
<tbody>
<tr>
<td>Trigger</td>
<td>System, outside the dialogue</td>
<td>Main model, inside its reasoning loop</td>
</tr>
<tr>
<td>Token cost</td>
<td>Low</td>
<td>High</td>
</tr>
<tr>
<td>Nuance</td>
<td>Coarser, prompt-driven</td>
<td>High, because the main model has full context</td>
</tr>
<tr>
<td>Typical failure</td>
<td>A missed fact is lost forever</td>
<td>The model fails to choose to save it</td>
</tr>
<tr>
<td>Examples</td>
<td>Mem0, crewAI</td>
<td>Letta, Claude Code</td>
</tr>
</tbody>
</table>
<p>Neither approach is universally better. Passive extraction offers consistency and low cost for unattended consumer products. Active editing offers the nuance needed by autonomous agents that should understand a user better over time.</p>
<h2 id="stage-two-storage—where-memory-lives" tabindex="-1">Stage Two: Storage—Where Memory Lives <a class="header-anchor" href="#stage-two-storage—where-memory-lives" aria-label="Permalink to &quot;Stage Two: Storage—Where Memory Lives&quot;">&ZeroWidthSpace;</a></h2>
<p>Storage is not merely a database choice. The representation determines how large memory can grow, who can inspect it, how errors are corrected, and how difficult migration becomes.</p>
<h3 id="three-storage-families" tabindex="-1">Three Storage Families <a class="header-anchor" href="#three-storage-families" aria-label="Permalink to &quot;Three Storage Families&quot;">&ZeroWidthSpace;</a></h3>
<table tabindex="0">
<thead>
<tr>
<th>Family</th>
<th>Medium</th>
<th>Retrieval</th>
<th>Examples</th>
</tr>
</thead>
<tbody>
<tr>
<td><strong>Vector store</strong></td>
<td>Embeddings and similarity indexes</td>
<td>Semantic search, often with BM25</td>
<td>Mem0, LlamaIndex, Cursor/Turbopuffer</td>
</tr>
<tr>
<td><strong>Temporal knowledge graph</strong></td>
<td>Entity relationships plus time metadata</td>
<td>Graph, vector, and full-text search</td>
<td>Zep/Graphiti, cognee</td>
</tr>
<tr>
<td><strong>Files or KV</strong></td>
<td>Markdown, JSONL, key/value records</td>
<td>Prompt loading and grep</td>
<td>Claude memory tool, Letta filesystem, <code>CLAUDE.md</code></td>
</tr>
</tbody>
</table>
<p>Vector stores excel at fuzzy semantic matching. Temporal graphs represent entities and their changing relationships; Graphiti uses episodic, semantic-entity, and community subgraphs, combining semantic search, BM25, and graph algorithms. Files are deceptively simple: the model edits Markdown and the runtime loads or searches it.</p>
<p>These families are not mutually exclusive. Mem0 can combine a vector database, an optional graph database, and a conventional metadata store. cognee feeds relational, vector, and graph layers through one pipeline.</p>
<h3 id="the-more-fundamental-divide-databases-vs-files" tabindex="-1">The More Fundamental Divide: Databases vs. Files <a class="header-anchor" href="#the-more-fundamental-divide-databases-vs-files" aria-label="Permalink to &quot;The More Fundamental Divide: Databases vs. Files&quot;">&ZeroWidthSpace;</a></h3>
<table tabindex="0">
<thead>
<tr>
<th>Dimension</th>
<th>Database memory</th>
<th>File memory</th>
</tr>
</thead>
<tbody>
<tr>
<td>Capacity</td>
<td>Nearly unlimited</td>
<td>Bound by context budget</td>
</tr>
<tr>
<td>Retrieval</td>
<td>Strong semantic or graph retrieval</td>
<td>Prompt loading and grep</td>
</tr>
<tr>
<td>Human-readable</td>
<td>No</td>
<td>Yes</td>
</tr>
<tr>
<td>Human-editable</td>
<td>Usually requires an API</td>
<td>Direct editing</td>
</tr>
<tr>
<td>Traceability</td>
<td>Difficult to diff manually</td>
<td>Git diff and blame</td>
</tr>
<tr>
<td>Infrastructure</td>
<td>Additional services</td>
<td>No external dependency</td>
</tr>
<tr>
<td>Migration</td>
<td>Backend-dependent</td>
<td>Plain text is portable</td>
</tr>
</tbody>
</table>
<p>Database memory makes humans pay the cost: vectors and graph nodes are difficult to inspect, review, and migrate. File memory makes capacity the constraint. It scales through <strong>index-then-fetch</strong>: keep a compact index resident and load detailed files only when needed.</p>
<p>This also explains a clear trend. Personal and coding agents increasingly choose files—Codex, Claude Code, OpenCode, Pi, Hermes, OpenClaw, Cursor rules, and Copilot instructions—because transparency, editability, Git history, and repo portability matter. Memory middleware such as Mem0, Zep, Graphiti, and cognee chooses databases because multi-user capacity and retrieval quality matter more than direct human inspection.</p>
<p>The reason is the audience. Developers want memory they can inspect, manage, version, review in a pull request, trace with <code>git blame</code>, and roll back. A <code>CLAUDE.md</code> or <code>AGENTS.md</code> fits the workflow they already use; a vector index does not. Memory middleware has the opposite priorities: large capacity, semantic retrieval, and tenant isolation are the product, while direct human readability is secondary.</p>
<h3 id="backend-choices-at-a-glance" tabindex="-1">Backend Choices at a Glance <a class="header-anchor" href="#backend-choices-at-a-glance" aria-label="Permalink to &quot;Backend Choices at a Glance&quot;">&ZeroWidthSpace;</a></h3>
<table tabindex="0">
<thead>
<tr>
<th>Project</th>
<th>Primary backend</th>
<th>Notes</th>
</tr>
</thead>
<tbody>
<tr>
<td><strong>Mem0</strong></td>
<td>Pinecone, Qdrant, Weaviate, Chroma, or pgvector; optional Neo4j or Memgraph; conventional metadata DB</td>
<td>Vectors for primary retrieval, graphs for relationships, and a DB for timestamps plus user/agent/session IDs</td>
</tr>
<tr>
<td><strong>Graphiti (Zep)</strong></td>
<td>Neo4j</td>
<td>A single graph backend with temporal metadata on every edge</td>
</tr>
<tr>
<td><strong>cognee</strong></td>
<td>LanceDB by default</td>
<td>One backend for relational, vector, and graph layers</td>
</tr>
<tr>
<td><strong>LangGraph</strong></td>
<td>PostgreSQL plus pgvector in production</td>
<td>Cosine similarity by default; SQLite and in-memory options are intended for demos</td>
</tr>
</tbody>
</table>
<p>Even inside the database camp, two styles emerge. Mem0 assigns responsibilities to specialized stores, gaining flexibility while operating several systems. cognee consolidates three layers into LanceDB to reduce dependencies. LangGraph pragmatically reuses PostgreSQL and pgvector, leaving memory design to the developer but introducing no unfamiliar infrastructure. The choice is between a higher capability ceiling from specialized backends and simpler operations from a general-purpose one.</p>
<h2 id="stage-three-retrieval—putting-memory-back-into-context" tabindex="-1">Stage Three: Retrieval—Putting Memory Back Into Context <a class="header-anchor" href="#stage-three-retrieval—putting-memory-back-into-context" aria-label="Permalink to &quot;Stage Three: Retrieval—Putting Memory Back Into Context&quot;">&ZeroWidthSpace;</a></h2>
<p>Storage and retrieval are two sides of the same coin. Pick a vector store and the retrieval path will probably be semantic search; pick Markdown and it will probably be index-then-fetch.</p>
<h3 id="database-memory-from-one-semantic-path-to-hybrid-retrieval" tabindex="-1">Database Memory: From One Semantic Path to Hybrid Retrieval <a class="header-anchor" href="#database-memory-from-one-semantic-path-to-hybrid-retrieval" aria-label="Permalink to &quot;Database Memory: From One Semantic Path to Hybrid Retrieval&quot;">&ZeroWidthSpace;</a></h3>
<p>Database-backed systems begin by embedding the query and retrieving the top-K nearest memories. Pure semantic search is weak at exact entity names, rare proper nouns, numbers, and dates—an embedding may consider <code>pnpm</code> and <code>npm</code> nearly identical—and it does not know whether a fact is still current. The common direction is therefore <strong>hybrid retrieval</strong>.</p>
<table tabindex="0">
<thead>
<tr>
<th>Implementation</th>
<th>Retrieval paths</th>
<th>Fusion and ranking</th>
<th>Distinctive feature</th>
</tr>
</thead>
<tbody>
<tr>
<td><strong>Graphiti (Zep)</strong></td>
<td>Vector, BM25 full text, and graph BFS</td>
<td>Reciprocal Rank Fusion, then cross-encoder reranking</td>
<td>Graph traversal recovers multi-hop relationships</td>
</tr>
<tr>
<td><strong>Mem0's newer algorithm</strong></td>
<td>Vector, BM25, and entity boosting</td>
<td>Multi-signal score fusion</td>
<td>Time-aware retrieval chooses the right present, past, or planned instance</td>
</tr>
<tr>
<td><strong>crewAI RecallFlow</strong></td>
<td>Vector retrieval</td>
<td>Confidence-based routing</td>
<td>Low confidence triggers <code>explore_deeper</code> and a second, LLM-rewritten search</td>
</tr>
</tbody>
</table>
<p>Graphiti is the most complete: vectors capture semantic similarity, BM25 finds exact terms, and graph BFS follows entity relationships. RRF combines the three lists before a cross-encoder reranks them. Mem0 follows a similar design and adds temporal selection for questions such as whether a role belongs to last year or today. crewAI turns retrieval into a feedback loop: below a confidence threshold, it feeds the current results to an LLM, reformulates the query, and searches again.</p>
<p>Hybrid retrieval improves recall, but every additional path, fusion stage, and reranker adds latency and engineering complexity. Mem0's roughly 0.2-second memory-search p95 is dramatically cheaper than its 17.12-second full-context comparison, yet the trade-offs among hybrid paths still require engineering.</p>
<h3 id="file-memory-layered-index-then-fetch-retrieval" tabindex="-1">File Memory: Layered Index-Then-Fetch Retrieval <a class="header-anchor" href="#file-memory-layered-index-then-fetch-retrieval" aria-label="Permalink to &quot;File Memory: Layered Index-Then-Fetch Retrieval&quot;">&ZeroWidthSpace;</a></h3>
<p>File-backed systems load a compact index every session, search it, open the relevant detail file, and return to raw evidence only when verification is needed.</p>
<p>In Codex, the sequence is explicit:</p>
<ol>
<li>Inject <code>memory_summary.md</code> into the system prompt as a resident index.</li>
<li>Search <code>MEMORY.md</code> with keywords to locate a relevant entry.</li>
<li>Follow its pointer and open the detailed topic file.</li>
<li>Return to the original rollout JSONL when the distilled claim needs evidence.</li>
<li>Keep the lookup within a four-to-six-step budget so the agent does not browse memory without limit.</li>
</ol>
<p>Claude Code's auto memory uses the same pattern: the first 200 lines or 25 KB of <code>MEMORY.md</code> act as the per-session index, and topic files are loaded on demand.</p>
<p><img src="https://oss.justin3go.com/blogs/index-then-fetch.png" alt="Index-then-fetch retrieval for file memory"></p>
<p>This is how file memory competes on capacity. The library may grow to hundreds of files while the resident context cost stays fixed; detailed content enters the window only after a relevant grep hit.</p>
<h3 id="a-useful-exception-hermes-uses-full-text-search" tabindex="-1">A Useful Exception: Hermes Uses Full-Text Search <a class="header-anchor" href="#a-useful-exception-hermes-uses-full-text-search" aria-label="Permalink to &quot;A Useful Exception: Hermes Uses Full-Text Search&quot;">&ZeroWidthSpace;</a></h3>
<p>Hermes stores historical messages in SQLite and searches them with FTS5, including a trigram CJK index, rather than semantic embeddings. This deliberately gives up semantic similarity in exchange for zero LLM or embedding cost, the exact original message instead of a second-hand summary, and a retrieval path whose code explicitly says <code>no summary LLM path</code>. When the goal is to recover precisely what someone said, plain full-text search can be faster, cheaper, and more accurate than vectors.</p>
<h3 id="retrieval-may-matter-less-than-we-think" tabindex="-1">Retrieval May Matter Less Than We Think <a class="header-anchor" href="#retrieval-may-matter-less-than-we-think" aria-label="Permalink to &quot;Retrieval May Matter Less Than We Think&quot;">&ZeroWidthSpace;</a></h3>
<p>Letta's filesystem experiment is a counterintuitive reminder: a GPT-4o-mini file agent with almost no prompt tuning scored 74.0% on LoCoMo, above specialized memory systems including Mem0's reported 68.5% graph result. The key may be how an agent manages context, not the retrieval primitive itself. What matters is <strong>when it retrieves, how much it retrieves, and how it uses what it found</strong>.</p>
<h2 id="stage-four-update-and-forgetting—keeping-memory-from-rotting" tabindex="-1">Stage Four: Update and Forgetting—Keeping Memory From Rotting <a class="header-anchor" href="#stage-four-update-and-forgetting—keeping-memory-from-rotting" aria-label="Permalink to &quot;Stage Four: Update and Forgetting—Keeping Memory From Rotting&quot;">&ZeroWidthSpace;</a></h2>
<p>If extraction, storage, and retrieval determine whether memory works at all, update and forgetting determine whether it keeps working. A store that only grows will eventually contain duplicate facts, conflicting preferences, and obsolete information. Many projects implement the first three stages and effectively leave this one blank, which is why <strong>update and forgetting are the true boundary between a toy and a durable system</strong>.</p>
<h3 id="deduplication-and-merging" tabindex="-1">Deduplication and Merging <a class="header-anchor" href="#deduplication-and-merging" aria-label="Permalink to &quot;Deduplication and Merging&quot;">&ZeroWidthSpace;</a></h3>
<p>Most systems do little meaningful deduplication. AutoGen assigns monotonically increasing IDs and appends; MetaGPT only detects exact object duplicates. They assume retrieval ranking can work around dirty data after it has already entered the store.</p>
<p>The systems that treat consolidation as a first-class concern follow three main strategies.</p>
<p><strong>1. Similarity gating plus an LLM decision at write time.</strong> crewAI first performs vector search for similar memories. If the top similarity is at least its default <code>consolidation_threshold</code> of 0.85, an LLM produces a <code>ConsolidationPlan</code> with <code>keep</code>, <code>update</code>, and <code>delete</code> actions and decides whether <code>insert_new</code> is still necessary. Mem0's classic <code>DEFAULT_UPDATE_MEMORY_PROMPT</code> similarly retrieves the top ten memories and chooses ADD, UPDATE, DELETE, or NONE. Mem0 maps UUIDs to consecutive integers before showing them to the LLM to reduce identifier hallucinations.</p>
<p><img src="https://oss.justin3go.com/blogs/write-time-gating.png" alt="Similarity gating and LLM decisions at write time"></p>
<p>The defining idea is simple: merge or reject bad data <strong>before it enters the store</strong>, not after retrieval has to route around it.</p>
<p><strong>2. Deduplication through graph identity.</strong> cognee derives node IDs with <code>uuid5(NAMESPACE, normalized_name)</code>, so repeated mentions of the same normalized entity collapse into one node; an LLM then merges its accumulated descriptions. Graphiti first narrows candidates with MinHash, LSH, and Jaccard similarity, then lets an LLM decide. Its prompt explicitly forbids merging items whose numbers, dates, or critical qualifiers differ—“the 2024 budget” and “the 2025 budget” are similar text but different facts.</p>
<p><strong>3. Offline LLM reorganization.</strong> Letta's sleep-time agent reads transcripts in the background and rewrites memory blocks with <code>memory_rethink</code> so they remain comprehensive, readable, and current. Codex hard-codes <code>no-op preferred</code> and <code>aggressively merge</code>, using the Git workspace diff to route memory that needs consolidation. Hermes performs “umbrella merging” under the maxim that <strong>one skill per session is a failure</strong>: session-specific fragments should be folded into reusable skills instead of becoming a log.</p>
<p>These approaches all refuse to rely on the main conversation agent to maintain memory while doing another task. They create a two-speed system: the conversation records evidence quickly; a dedicated process merges, promotes, rewrites, or archives it.</p>
<p>There is an important reversal in newer Mem0 snapshots. Its default V3 path has moved from aggressive LLM UPDATE decisions toward <strong>ADD-only extraction, <code>linked_memory_ids</code>, and MD5 exact deduplication</strong>. “Owns a dog named Max” and “went camping with Max” remain two linked memories rather than being crushed into one. Even Mem0 is recalibrating the trade-off: merge too aggressively and independently useful facts become impossible to recover. “Merge before adding” is a dial, not a command to erase detail.</p>
<h3 id="forgetting-without-destroying-history" tabindex="-1">Forgetting Without Destroying History <a class="header-anchor" href="#forgetting-without-destroying-history" aria-label="Permalink to &quot;Forgetting Without Destroying History&quot;">&ZeroWidthSpace;</a></h3>
<p>Most memory systems do not truly forget. Mem0, cognee, and AutoGen generally grow monotonically; Letta's archival storage “persists indefinitely” unless an API call explicitly deletes something. Capacity management is pushed to retrieval and context truncation instead of the store itself. The projects that do forget use four distinct approaches.</p>
<p><strong>1. Soft invalidation and versioning.</strong> Graphiti gives every fact edge four bi-temporal timestamps:</p>
<table tabindex="0">
<thead>
<tr>
<th>Timeline</th>
<th>Fields</th>
<th>Meaning</th>
</tr>
</thead>
<tbody>
<tr>
<td>System-record timeline</td>
<td><code>created_at</code> / <code>expired_at</code></td>
<td>When the system recorded and invalidated the edge</td>
</tr>
<tr>
<td>Real-world validity timeline</td>
<td><code>valid_at</code> / <code>invalid_at</code></td>
<td>When the fact became and ceased to be true in reality</td>
</tr>
</tbody>
</table>
<p>When a new fact contradicts an old one, the old edge is not deleted. It gets <code>expired_at=now</code> and <code>invalid_at</code> equal to the new fact's <code>valid_at</code>. This makes both current-state and point-in-time queries possible. If a user moved from npm to pnpm, the system can use pnpm now without erasing the history that npm was previously correct. AutoGPT's newer memory layer reuses Graphiti's model.</p>
<p><img src="https://oss.justin3go.com/blogs/bi-temporal-timeline.png" alt="Graphiti's bi-temporal invalidation keeps old edges for point-in-time queries"></p>
<p><strong>2. Usage-count-driven retention.</strong> Codex stores <code>usage_count</code> and <code>last_usage</code> in <code>stage1_outputs</code>; consolidation can ignore entries whose last use falls outside <code>max_unused_days</code>. OpenClaw likewise promotes and retains memory according to real retrieval traffic. This is more defensible than an “importance” score assigned when the memory was written: repeated use is evidence, while predicted importance is a guess.</p>
<p><strong>3. Time decay and state machines.</strong> OpenClaw applies exponential decay with different half-lives, such as 30 and 14 days, for different layers. crewAI includes <code>decay = 0.5^(age_days/30)</code> in retrieval scoring. Hermes marks a skill STALE after 30 unused days and moves it into a recoverable <code>.archive/</code> after 90 days; it never physically deletes the skill.</p>
<p><strong>4. Tombstone-based logical forgetting.</strong> OpenHands models conversation history as an append-only event log. When context must be compressed, its condenser writes a <code>Condensation</code> tombstone saying that a group of events has been replaced by a summary. A replayed View filters those events and shows the summary, but the original evidence remains physically present. One dataset supports both a compact model-facing view and a complete audit view.</p>
<table tabindex="0">
<thead>
<tr>
<th>Strategy</th>
<th>Projects</th>
<th>Trigger</th>
<th>Physical deletion?</th>
</tr>
</thead>
<tbody>
<tr>
<td>Soft invalidation/versioning</td>
<td>Graphiti; reused by AutoGPT</td>
<td>New fact contradicts old fact</td>
<td>No; invalidate and preserve time travel</td>
</tr>
<tr>
<td>Usage-count driven</td>
<td>Codex, OpenClaw</td>
<td>Retrieval frequency and <code>max_unused_days</code></td>
<td>No; archive or filter by use</td>
</tr>
<tr>
<td>Time decay/state machine</td>
<td>OpenClaw, Hermes, crewAI</td>
<td>Time since last use</td>
<td>No; decay or STALE → archive</td>
</tr>
<tr>
<td>Tombstone forgetting</td>
<td>OpenHands</td>
<td>Context needs compaction</td>
<td>No; write a tombstone and filter on replay</td>
</tr>
</tbody>
</table>
<p>The common pattern is striking: mature systems prefer <strong>logical forgetting over physical deletion</strong>. Physical deletion permanently destroys evolution and audit history, which are often the only way to explain why an agent acted as it did. The scarce capability is not clean deletion; it is reversible forgetting.</p>
<p>Do not expect the main conversation agent to maintain memory casually between tasks. Reliable systems either gate writes or assign consolidation to a constrained, dedicated process. Memory maintenance must be a first-class workload.</p>
<h2 id="four-memory-writing-philosophies" tabindex="-1">Four Memory-Writing Philosophies <a class="header-anchor" href="#four-memory-writing-philosophies" aria-label="Permalink to &quot;Four Memory-Writing Philosophies&quot;">&ZeroWidthSpace;</a></h2>
<table tabindex="0">
<thead>
<tr>
<th>Dimension</th>
<th>Passive extraction (Mem0)</th>
<th>Active editing (Letta)</th>
<th>Temporal graph (Zep)</th>
<th>Files (Claude/Letta FS)</th>
</tr>
</thead>
<tbody>
<tr>
<td>Write decision</td>
<td>LLM extraction</td>
<td>Agent tool call</td>
<td>Entity/relation extraction</td>
<td>Agent edits files</td>
</tr>
<tr>
<td>Predictability</td>
<td>High</td>
<td>Model-dependent</td>
<td>High</td>
<td>High</td>
</tr>
<tr>
<td>Token cost</td>
<td>Low</td>
<td>High</td>
<td>Medium</td>
<td>Medium</td>
</tr>
<tr>
<td>Conflict handling</td>
<td>ADD/UPDATE/DELETE decision</td>
<td>Agent rewrites memory</td>
<td>Bi-temporal invalidation</td>
<td>File overwrite/history</td>
</tr>
<tr>
<td>Auditability</td>
<td>Medium</td>
<td>High</td>
<td>High, point-in-time</td>
<td>Highest, plain-text Git history</td>
</tr>
<tr>
<td>Operations</td>
<td>Low to medium</td>
<td>Medium</td>
<td>High, often Neo4j</td>
<td>Lowest</td>
</tr>
<tr>
<td>Best fit</td>
<td>User memory for an existing app</td>
<td>Complex autonomous agents</td>
<td>Dynamic or regulated enterprise facts</td>
<td>Coding agents</td>
</tr>
</tbody>
</table>
<p>The table contains four core tensions.</p>
<p><strong>Cost versus control.</strong> Passive extraction gives a separate, relatively cheap LLM call responsibility for deciding what matters. It is predictable and does not spend the main agent's tokens, but any signal outside the extraction prompt is lost. Letta's active editing makes the best-informed model decide, but every <code>core_memory_append</code> or <code>memory_replace</code> spends inference tokens and memory quality becomes model-dependent.</p>
<p><strong>When to resolve conflict.</strong> Mem0 decides ADD, UPDATE, DELETE, or NOOP before data enters the store. Letta rewrites a core-memory block later. A plain file can simply overwrite the old value. Zep/Graphiti alone preserves both sides through bi-temporal invalidation. Historical fidelity increases along roughly overwrite &lt; LLM decision &lt; temporal invalidation, but so does mechanism weight.</p>
<p><strong>Auditability versus operations.</strong> Files appear to offer both the best auditability and the lowest operations cost, but their hidden price is context-bound capacity. Index-then-fetch moves the scaling problem into layered retrieval. Zep pays for Neo4j operations to obtain temporal reasoning and point-in-time audits.</p>
<p><strong>There is no silver bullet, only scenario fit.</strong> Mem0 suits unattended user memory for an existing agent; Letta suits autonomous agents built from scratch; Zep suits changing or regulated enterprise facts; files suit coding agents.</p>
<p>Letta's filesystem experiment reinforces the point: a plain filesystem with GPT-4o-mini reached <strong>74.0%</strong> on LoCoMo, above Mem0's reported <strong>68.5%</strong> best graph variant. How the agent manages context can matter more than whether retrieval uses vectors or graphs.</p>
<h2 id="where-mainstream-products-are-converging" tabindex="-1">Where Mainstream Products Are Converging <a class="header-anchor" href="#where-mainstream-products-are-converging" aria-label="Permalink to &quot;Where Mainstream Products Are Converging&quot;">&ZeroWidthSpace;</a></h2>
<p>ChatGPT, Gemini, Claude, and coding agents are converging on <strong>a compressed long-term profile plus raw recent working memory</strong>. The profile is compact and persistent; recent conversation provides a delta because summaries are inevitably stale.</p>
<p><strong>ChatGPT optimizes for frictionless, always-on personalization.</strong> Saved memories are explicit, user-editable facts such as names, preferences, and goals. They appear with timestamps in the system prompt's Model Set Context. Reference chat history, launched on April 10, 2025, maintains a rolling history and implicit profile rather than literally searching every old chat. It is not directly inspectable. The benefit is zero-wait personalization; the cost is less predictable provenance and auditability.</p>
<p><strong>Gemini optimizes for a single source of truth.</strong> Personal Context, launched in August 2025, centers on one structured <code>user_context</code> document. Each short fact carries a Statement, Rationale, and timestamp, then recent raw turns provide the delta. Timestamps make conflict resolution straightforward: today's “I joined a new company” can replace a year-old current role, while “considered moving to San Francisco in June 2024” remains a time-bounded event rather than a permanent identity. Despite Google's enormous data advantage, the design is conservative about what becomes personalization.</p>
<p><strong>Claude optimizes for transparent, work-oriented control through two separate systems.</strong> Search and reference chats, introduced in September 2025, performs on-demand RAG through <code>conversation_search</code> and <code>recent_chats</code>, linking results back to the original conversation. Generate memory from chat history synthesizes an editable profile refreshed every 24 hours; edits apply immediately, and the feature expanded to free users in March 2026. Project isolation gives each project its own memory and summary, while the cross-chat summary explicitly excludes project chats. Claude.ai chat memory, the API <code>/memories</code> tool with <code>create</code>/<code>str_replace</code>/<code>insert</code>, and Claude Code's cascaded <code>CLAUDE.md</code> files are three different systems and should not be conflated.</p>
<p><strong>Coding agents have converged even further:</strong> codebase index, rules files, and automatic memories are becoming a standard stack. Cursor semantically splits code by function and class, stores embeddings in Turbopuffer, and uses a Merkle tree to check hashes every 5–10 minutes so only changed files are reprocessed; raw code is not uploaded with the embeddings. Its v1.0 Memories sidecar proposes project-scoped entries for developer approval. GitHub Copilot separates repository facts—with citations back to supporting code and validation against the current branch—from cross-repository user preferences. Unused facts can expire after 28 days, while successful use resets the timer. <code>CLAUDE.md</code>, <code>AGENTS.md</code>, <code>.windsurfrules</code>, and <code>copilot-instructions.md</code> tie the ecosystem together as a de facto file-based standard.</p>
<p>Three shared principles emerge: long-term profiles must be compressed, recent raw conversation must compensate for stale summaries, and conflict resolution increasingly depends on time—timestamps, validation-before-use, or refresh cycles.</p>
<h2 id="do-not-trust-benchmarks-too-much" tabindex="-1">Do Not Trust Benchmarks Too Much <a class="header-anchor" href="#do-not-trust-benchmarks-too-much" aria-label="Permalink to &quot;Do Not Trust Benchmarks Too Much&quot;">&ZeroWidthSpace;</a></h2>
<p>LoCoMo and similar benchmarks can be inflated by aggressive retrieval: provide enough likely answers in the candidate context and the score rises, even if the memory system has little real understanding.</p>
<blockquote>
<p>Letta used a <strong>plain filesystem</strong>, GPT-4o-mini, and minimal prompt tuning to score <strong>74.0%</strong> on LoCoMo—higher than the <strong>68.5%</strong> reported for Mem0's best graph variant.</p>
</blockquote>
<p>Cross-vendor numbers are rarely comparable because evaluation models and retrieval settings differ. Even Mem0's own pages report LoCoMo/LongMemEval values of 92.5%/94.4% in one place and 91.6%/93.4% elsewhere, with the hosted version including proprietary optimizations unavailable to the open-source release. Treat public scores as hints. <strong>Evaluate on your own real data.</strong></p>
<h2 id="four-practical-routes—no-silver-bullet" tabindex="-1">Four Practical Routes—No Silver Bullet <a class="header-anchor" href="#four-practical-routes—no-silver-bullet" aria-label="Permalink to &quot;Four Practical Routes—No Silver Bullet&quot;">&ZeroWidthSpace;</a></h2>
<table tabindex="0">
<thead>
<tr>
<th>Scenario</th>
<th>Recommended route</th>
<th>References</th>
</tr>
</thead>
<tbody>
<tr>
<td>Unattended memory for SaaS or consumer users</td>
<td>Database plus merge gating at write time</td>
<td>Mem0, crewAI</td>
</tr>
<tr>
<td>Rapidly changing facts and point-in-time queries</td>
<td>Bi-temporal knowledge graph</td>
<td>Graphiti, Zep</td>
</tr>
<tr>
<td>Coding or personal agent; human-readable and Git-managed</td>
<td>Files plus index-then-fetch</td>
<td>Codex, Claude Code</td>
</tr>
<tr>
<td>Long-running self-improvement</td>
<td>Files plus two-speed offline consolidation</td>
<td>Hermes, OpenClaw</td>
</tr>
</tbody>
</table>
<p>Whatever route you choose:</p>
<ul>
<li><strong>Do not adopt a graph database too early.</strong> A vector store plus LLM extraction covers most cases; graphs pay off only when relationship reasoning is central.</li>
<li><strong>Timestamp every memory.</strong> Time is the foundation of conflict resolution and temporal queries. Early OpenAI memory entries lacked timestamps and performed poorly on LoCoMo temporal questions: Mem0's graph variant reported 58.13% versus OpenAI's 21.71%. A timestamp is nearly free; without one, “what was I doing last Wednesday?” cannot be answered reliably.</li>
<li><strong>Separate user, session, and project scopes.</strong> This is necessary for relevance and safety.</li>
<li><strong>Use benchmarks as references, not truth.</strong></li>
</ul>
<p>Codex's two-stage maintenance pipeline is a strong integrated example:</p>
<p><img src="https://oss.justin3go.com/blogs/codex-two-phase-pipeline.png" alt="Codex's two-stage memory maintenance pipeline"></p>
<p>Phase one distills historical sessions into structured SQLite records. Phase two runs a dedicated consolidation agent inside a networkless, approval-free sandbox and uses the baseline-to-worktree diff in <code>~/.codex/memories/.git</code> as the signal for ingestion and forgetting. Memory maintenance becomes constrained, incremental, reversible, and informed by usage counts instead of being an unmanaged append operation.</p>
<h2 id="conclusion-converging-principles-and-two-unsolved-gaps" tabindex="-1">Conclusion: Converging Principles and Two Unsolved Gaps <a class="header-anchor" href="#conclusion-converging-principles-and-two-unsolved-gaps" aria-label="Permalink to &quot;Conclusion: Converging Principles and Two Unsolved Gaps&quot;">&ZeroWidthSpace;</a></h2>
<p>Across open-source systems and mainstream products, two principles are converging.</p>
<p>First, <strong>merge before adding</strong>. Aggressive append slowly corrupts a memory store with duplicates, obsolete facts, and contradictions. Some systems gate at write time; others consolidate offline. Both recognize that the main conversation agent should not be expected to maintain memory casually.</p>
<p>Second, <strong>separate raw records from compressed views</strong>. OpenHands keeps events behind tombstones, Codex separates rollout logs from distilled summaries, and Graphiti invalidates edges without deleting them. Daily retrieval uses the compact view; audits and corrections can still return to original evidence.</p>
<p>Two gaps remain.</p>
<p>The first is <strong>human review before writing</strong>. None of the surveyed systems provides a complete confirmation gate before memory enters the store. AutoGPT uses a two-step confirmation for deletion—find candidates, ask the user, then execute—but writes remain automatic. Hermes can emit a curator dry-run <code>REPORT.md</code> for approval, but only for skill organization. The industry has chosen prompt constraints and automated safeguards over systematic human approval in order to preserve unattended operation.</p>
<p>The second—and more serious—gap is <strong>security</strong>. Memory systems are naturally vulnerable to indirect prompt injection. Malicious instructions hidden in ordinary-looking content can persuade an agent to read or write memory without the user's awareness. Once poisoned memory is stored, it can influence future behavior repeatedly and invisibly.</p>
<p>Memory can make an agent smarter the longer it is used, but it can also make one incident of poisoning persist. The field is converging on sound engineering principles, yet these gaps remain open—which is precisely why now is such an interesting time to build.</p>
]]></content:encoded>
            <author>just@justin3go.com (Justin3go)</author>
        </item>
        <item>
            <title><![CDATA[Shedding Heavy Memories: Context Compaction in Codex, Claude Code, and OpenCode]]></title>
            <link>https://justin3go.com/en/posts/2026/04/09-context-compaction-in-codex-claude-code-and-opencode</link>
            <guid>https://justin3go.com/en/posts/2026/04/09-context-compaction-in-codex-claude-code-and-opencode</guid>
            <pubDate>Thu, 09 Apr 2026 00:00:00 GMT</pubDate>
            <description><![CDATA[<h1 id="shedding-heavy-memories-context-compaction-in-codex-claude-code-and-opencode" tabindex="-1">Shedding Heavy Memories: Context Compaction in Codex, Claude Code, and OpenCode <a class="header-anchor" href="#shedding-heavy-memories-context-compaction-in-codex-claude-code-and-opencode" aria-label="Permalink to &quot;Shedding Heavy Memories: Context Compaction in Codex, Claude Code, and OpenCode&quot;">&ZeroWidthSpace;</a></h1>
<blockquote>
<p>✨Article Summary (AI Generated)</p>
</blockquote>
<!-- DESC SEP -->
<blockquote></blockquote>
<p>This article uses a 15,400-token login bug fix scenario to dissect the context compaction strategies of three mainstream CLI agents: <strong>Codex CLI</strong>, <strong>Claude Code</strong>, and <strong>OpenCode</strong>. Codex CLI takes a single-layer &quot;handoff summary&quot; approach; Claude Code employs a three-tier progressive mechanism — tool result trimming, <strong>Prompt Cache-friendly strategies</strong>, and a 9-section structured LLM summary; OpenCode implements &quot;stepped governance&quot; through non-destructive timestamp-based message hiding paired with a 5-heading LLM summary. The article reveals a core insight: the best context management isn't about endlessly expanding memory capacity, but learning to <strong>forget with precision</strong>.</p>
<blockquote></blockquote>
<!-- DESC SEP -->
<p>When using AI agents for deep programming tasks, you've surely encountered this predicament: at first, the AI is sharp and responsive, hitting every mark; but as conversation turns accumulate, it seems to get progressively dumber.</p>
<p>When context is nearly exhausted, the AI rushes to finish, leading to poor results — the community calls this Context Anxiety, and just like us humans, haste makes waste. To keep the conversation going, the agent must shed some memories (compress — compact). But how to shed, what to shed, and how to recover afterward have become key markers of whether an agent runtime is truly mature.</p>
<p>Today, let's tear apart three mainstream CLI agents — <strong>Codex CLI</strong>, <strong>Claude Code</strong>, and <strong>OpenCode</strong> — and see how each performs their &quot;compression magic&quot; when facing the same login bug.</p>
<blockquote>
<p>Note: This analysis is based on the open-source repository logic of Codex CLI and OpenCode, along with community reverse engineering and leaked source code verification of the Claude Code runtime.</p>
</blockquote>
<h2 id="scenario-replay-a-15-400-token-login-bug-fix" tabindex="-1">Scenario Replay: A 15,400-Token Login Bug Fix <a class="header-anchor" href="#scenario-replay-a-15-400-token-login-bug-fix" aria-label="Permalink to &quot;Scenario Replay: A 15,400-Token Login Bug Fix&quot;">&ZeroWidthSpace;</a></h2>
<p>Imagine you're fixing a login endpoint returning 401 Unauthorized. You summon your AI agent and embark on an intense debugging session.</p>
<p>Here's the complete conversation log:</p>
<p>| # | Role | Summary | Est. Tokens |
| :</p>
]]></description>
            <content:encoded><![CDATA[<h1 id="shedding-heavy-memories-context-compaction-in-codex-claude-code-and-opencode" tabindex="-1">Shedding Heavy Memories: Context Compaction in Codex, Claude Code, and OpenCode <a class="header-anchor" href="#shedding-heavy-memories-context-compaction-in-codex-claude-code-and-opencode" aria-label="Permalink to &quot;Shedding Heavy Memories: Context Compaction in Codex, Claude Code, and OpenCode&quot;">&ZeroWidthSpace;</a></h1>
<blockquote>
<p>✨Article Summary (AI Generated)</p>
</blockquote>
<!-- DESC SEP -->
<blockquote></blockquote>
<p>This article uses a 15,400-token login bug fix scenario to dissect the context compaction strategies of three mainstream CLI agents: <strong>Codex CLI</strong>, <strong>Claude Code</strong>, and <strong>OpenCode</strong>. Codex CLI takes a single-layer &quot;handoff summary&quot; approach; Claude Code employs a three-tier progressive mechanism — tool result trimming, <strong>Prompt Cache-friendly strategies</strong>, and a 9-section structured LLM summary; OpenCode implements &quot;stepped governance&quot; through non-destructive timestamp-based message hiding paired with a 5-heading LLM summary. The article reveals a core insight: the best context management isn't about endlessly expanding memory capacity, but learning to <strong>forget with precision</strong>.</p>
<blockquote></blockquote>
<!-- DESC SEP -->
<p>When using AI agents for deep programming tasks, you've surely encountered this predicament: at first, the AI is sharp and responsive, hitting every mark; but as conversation turns accumulate, it seems to get progressively dumber.</p>
<p>When context is nearly exhausted, the AI rushes to finish, leading to poor results — the community calls this Context Anxiety, and just like us humans, haste makes waste. To keep the conversation going, the agent must shed some memories (compress — compact). But how to shed, what to shed, and how to recover afterward have become key markers of whether an agent runtime is truly mature.</p>
<p>Today, let's tear apart three mainstream CLI agents — <strong>Codex CLI</strong>, <strong>Claude Code</strong>, and <strong>OpenCode</strong> — and see how each performs their &quot;compression magic&quot; when facing the same login bug.</p>
<blockquote>
<p>Note: This analysis is based on the open-source repository logic of Codex CLI and OpenCode, along with community reverse engineering and leaked source code verification of the Claude Code runtime.</p>
</blockquote>
<h2 id="scenario-replay-a-15-400-token-login-bug-fix" tabindex="-1">Scenario Replay: A 15,400-Token Login Bug Fix <a class="header-anchor" href="#scenario-replay-a-15-400-token-login-bug-fix" aria-label="Permalink to &quot;Scenario Replay: A 15,400-Token Login Bug Fix&quot;">&ZeroWidthSpace;</a></h2>
<p>Imagine you're fixing a login endpoint returning 401 Unauthorized. You summon your AI agent and embark on an intense debugging session.</p>
<p>Here's the complete conversation log:</p>
<table tabindex="0">
<thead>
<tr>
<th style="text-align:left">#</th>
<th style="text-align:left">Role</th>
<th style="text-align:left">Summary</th>
<th style="text-align:left">Est. Tokens</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align:left">#1</td>
<td style="text-align:left">System</td>
<td style="text-align:left">System prompt (40+ tool definitions)</td>
<td style="text-align:left">~800</td>
</tr>
<tr>
<td style="text-align:left">#2</td>
<td style="text-align:left">User</td>
<td style="text-align:left">&quot;Login page returns 401, help me debug&quot;</td>
<td style="text-align:left">~100</td>
</tr>
<tr>
<td style="text-align:left">#3</td>
<td style="text-align:left">Assistant</td>
<td style="text-align:left">&quot;Let me search for auth-related logic&quot;</td>
<td style="text-align:left">~150</td>
</tr>
<tr>
<td style="text-align:left">#4</td>
<td style="text-align:left">Tool Call</td>
<td style="text-align:left"><code>grep &quot;auth&quot; --include=&quot;*.ts&quot;</code></td>
<td style="text-align:left">~50</td>
</tr>
<tr>
<td style="text-align:left">#5</td>
<td style="text-align:left"><strong>Tool Result</strong></td>
<td style="text-align:left"><strong>(50 search results returned)</strong></td>
<td style="text-align:left"><strong>~2,000</strong></td>
</tr>
<tr>
<td style="text-align:left">#6</td>
<td style="text-align:left">Assistant</td>
<td style="text-align:left">&quot;Found several hits, let me check auth.ts&quot;</td>
<td style="text-align:left">~150</td>
</tr>
<tr>
<td style="text-align:left">#7</td>
<td style="text-align:left">Tool Call</td>
<td style="text-align:left"><code>read_file &quot;src/auth.ts&quot;</code></td>
<td style="text-align:left">~50</td>
</tr>
<tr>
<td style="text-align:left">#8</td>
<td style="text-align:left"><strong>Tool Result</strong></td>
<td style="text-align:left"><strong>(Full file content, ~300 lines)</strong></td>
<td style="text-align:left"><strong>~3,500</strong></td>
</tr>
<tr>
<td style="text-align:left">#9</td>
<td style="text-align:left">Assistant</td>
<td style="text-align:left">&quot;Found it — token validation doesn't handle expiry&quot;</td>
<td style="text-align:left">~300</td>
</tr>
<tr>
<td style="text-align:left">#10</td>
<td style="text-align:left">User</td>
<td style="text-align:left">&quot;OK, but keep backward compatibility with old sessions&quot;</td>
<td style="text-align:left">~80</td>
</tr>
<tr>
<td style="text-align:left">#11</td>
<td style="text-align:left">Assistant</td>
<td style="text-align:left">&quot;Got it, let me also check the middleware&quot;</td>
<td style="text-align:left">~150</td>
</tr>
<tr>
<td style="text-align:left">#12</td>
<td style="text-align:left">Tool Call</td>
<td style="text-align:left"><code>read_file &quot;src/middleware.ts&quot;</code></td>
<td style="text-align:left">~50</td>
</tr>
<tr>
<td style="text-align:left">#13</td>
<td style="text-align:left"><strong>Tool Result</strong></td>
<td style="text-align:left"><strong>(Full middleware content)</strong></td>
<td style="text-align:left"><strong>~2,500</strong></td>
</tr>
<tr>
<td style="text-align:left">#14</td>
<td style="text-align:left">Assistant</td>
<td style="text-align:left">&quot;Middleware needs changes too, I'll handle it&quot;</td>
<td style="text-align:left">~200</td>
</tr>
<tr>
<td style="text-align:left">#15</td>
<td style="text-align:left">Tool Call</td>
<td style="text-align:left"><code>edit_file &quot;src/auth.ts&quot; (patch)</code></td>
<td style="text-align:left">~100</td>
</tr>
<tr>
<td style="text-align:left">#16</td>
<td style="text-align:left">Tool Result</td>
<td style="text-align:left">&quot;Successfully applied.&quot;</td>
<td style="text-align:left">~30</td>
</tr>
<tr>
<td style="text-align:left">#17</td>
<td style="text-align:left">Tool Call</td>
<td style="text-align:left"><code>edit_file &quot;src/middleware.ts&quot; (patch)</code></td>
<td style="text-align:left">~100</td>
</tr>
<tr>
<td style="text-align:left">#18</td>
<td style="text-align:left">Tool Result</td>
<td style="text-align:left">&quot;Successfully applied.&quot;</td>
<td style="text-align:left">~30</td>
</tr>
<tr>
<td style="text-align:left">#19</td>
<td style="text-align:left">Assistant</td>
<td style="text-align:left">&quot;Code changes done, let me run the tests&quot;</td>
<td style="text-align:left">~100</td>
</tr>
<tr>
<td style="text-align:left">#20</td>
<td style="text-align:left">Tool Call</td>
<td style="text-align:left"><code>bash &quot;npm test&quot;</code></td>
<td style="text-align:left">~50</td>
</tr>
<tr>
<td style="text-align:left">#21</td>
<td style="text-align:left"><strong>Tool Result</strong></td>
<td style="text-align:left"><strong>(3 tests failed with stack traces)</strong></td>
<td style="text-align:left"><strong>~3,000</strong></td>
</tr>
<tr>
<td style="text-align:left">#22</td>
<td style="text-align:left">Assistant</td>
<td style="text-align:left">&quot;3 tests failed, let me fix the test cases&quot;</td>
<td style="text-align:left">~200</td>
</tr>
<tr>
<td style="text-align:left">#23</td>
<td style="text-align:left">Tool Call</td>
<td style="text-align:left"><code>edit_file &quot;src/auth.test.ts&quot; (patch)</code></td>
<td style="text-align:left">~150</td>
</tr>
<tr>
<td style="text-align:left">#24</td>
<td style="text-align:left">Tool Result</td>
<td style="text-align:left">&quot;Successfully applied.&quot;</td>
<td style="text-align:left">~30</td>
</tr>
<tr>
<td style="text-align:left">#25</td>
<td style="text-align:left">Tool Call</td>
<td style="text-align:left"><code>bash &quot;npm test&quot;</code></td>
<td style="text-align:left">~50</td>
</tr>
<tr>
<td style="text-align:left">#26</td>
<td style="text-align:left"><strong>Tool Result</strong></td>
<td style="text-align:left"><strong>(All tests passing, full output)</strong></td>
<td style="text-align:left"><strong>~1,500</strong></td>
</tr>
</tbody>
</table>
<p>Just 26 messages, yet they've consumed roughly <strong>15,400 tokens</strong>. The five bolded tool results (#5, #8, #13, #21, #26) alone total about <strong>12,500 tokens</strong> — <strong>81%</strong> of the total. This data was critical during debugging, but once the bug is fixed, it becomes dead weight in the context. If left uncleaned, the next conversation turn might overflow the window and lose the system prompt or the user's core requirements.</p>
<h2 id="codex-cli-writing-a-crisp-handoff-memo" tabindex="-1">Codex CLI: Writing a Crisp &quot;Handoff Memo&quot; <a class="header-anchor" href="#codex-cli-writing-a-crisp-handoff-memo" aria-label="Permalink to &quot;Codex CLI: Writing a Crisp &quot;Handoff Memo&quot;&quot;">&ZeroWidthSpace;</a></h2>
<p>OpenAI's Codex CLI (<a href="https://github.com/openai/codex" target="_blank" rel="noreferrer">source</a>, Rust implementation) takes an approach that feels very intuitive to humans: <strong>summarize and replace</strong>.</p>
<p>Its core idea can be captured in one sentence: <strong>hand the entire conversation to an LLM to write a &quot;handoff summary,&quot; then replace the original history with that summary.</strong></p>
<h3 id="dual-path-design" tabindex="-1">Dual-Path Design <a class="header-anchor" href="#dual-path-design" aria-label="Permalink to &quot;Dual-Path Design&quot;">&ZeroWidthSpace;</a></h3>
<p>Codex offers two compression paths:</p>
<ol>
<li><strong>Local path</strong> (<code>compact.rs</code>): The client calls an LLM to generate the summary, compatible with any model provider.</li>
<li><strong>Remote path</strong> (<code>compact_remote.rs</code>): Directly calls OpenAI's internal API endpoint <code>responses/compact</code>, letting the server handle compression. OpenAI models only.</li>
</ol>
<p>Note that &quot;local&quot; and &quot;remote&quot; here don't refer to whether an LLM call is needed — both paths require LLM involvement. The difference is <strong>where the core &quot;generate summary&quot; step runs</strong>. In the local path, the client constructs the summarization prompt (loaded from the built-in template <code>templates/compact/prompt.md</code>), streams the LLM API call via <code>ModelClientSession</code>, and processes the returned result — the entire orchestration happens on your machine, so it works with any model provider. In the remote path, the client sends the prepared conversation history and tool definitions to OpenAI's <code>compact_conversation_history</code> endpoint for server-side summary generation — but the client is far from hands-off. Before the call, it trims overly long function call histories and builds the complete prompt object including tool specifications and system instructions; after the call, it filters the results (e.g., discarding stale <code>developer</code> role messages, keeping only genuine user and assistant content), restores ghost snapshots for <code>/undo</code> functionality, and recalculates token usage.</p>
<p>In short, the remote path only outsources <strong>the &quot;compression&quot; step</strong> to OpenAI's server — pre-processing and post-processing remain client-side. The advantage is that OpenAI's server likely has dedicated optimizations for this endpoint (such as more economical models or internal caching) that aren't available through the generic API. This reflects OpenAI's vertical integration of their own infrastructure.</p>
<h3 id="the-compression-flow-in-detail" tabindex="-1">The Compression Flow in Detail <a class="header-anchor" href="#the-compression-flow-in-detail" aria-label="Permalink to &quot;The Compression Flow in Detail&quot;">&ZeroWidthSpace;</a></h3>
<p>When taking the local path, Codex first extracts recent user messages (hard-capped at ~20,000 tokens), then sends a brief summarization prompt to the LLM. This prompt has just 4 core points:</p>
<blockquote>
<p>You are performing a &quot;context checkpoint compression.&quot; Generate a handoff summary for another LLM that will continue the task, including: current progress and key decisions, important constraints and user preferences, remaining TODOs, and critical data needed to continue work.</p>
</blockquote>
<p>The keyword is <strong>&quot;handoff&quot;</strong> — it's not writing meeting minutes, but a briefing that lets the next person (model) hit the ground running.</p>
<p>Applied to our login bug scenario:</p>
<p><img src="https://oss.justin3go.com/blogs/codex-compression.png" alt="Codex CLI before and after compression"></p>
<p><strong>Breaking it down:</strong></p>
<p>Notice the before-and-after — all messages collapse to just 4. Codex deeply respects &quot;user intent&quot;: it physically deletes all assistant replies and tool-related messages, but <strong>preserves all user messages verbatim</strong> (#2 and #10).</p>
<p>It then inserts a fabricated assistant message containing a structured handoff summary. This summary includes the task objective, completed items, key architectural decisions, and remaining TODOs. For the new model, it doesn't need to see those massive file dumps and test stack traces — it just needs to know &quot;the tests are fixed&quot; and that's enough.</p>
<h3 id="auto-trigger-and-fallback" tabindex="-1">Auto-Trigger and Fallback <a class="header-anchor" href="#auto-trigger-and-fallback" aria-label="Permalink to &quot;Auto-Trigger and Fallback&quot;">&ZeroWidthSpace;</a></h3>
<p>When token usage approaches the model's context window limit, Codex automatically triggers compression (no need for manual <code>/compact</code>). If space is still insufficient after compression, it falls back to more aggressive &quot;head trimming&quot; — chopping from the earliest messages to ensure the conversation can continue.</p>
<p>The biggest advantage of Codex's approach is its <strong>intuitiveness</strong>: the handoff summary concept is something every working professional understands. The downside is it's rather &quot;all-or-nothing&quot; — all AI replies and tool results get replaced by a summary, and if that summary misses a critical detail, it's truly gone forever.</p>
<h2 id="claude-code-three-tier-precision-forgetting" tabindex="-1">Claude Code: Three-Tier &quot;Precision Forgetting&quot; <a class="header-anchor" href="#claude-code-three-tier-precision-forgetting" aria-label="Permalink to &quot;Claude Code: Three-Tier &quot;Precision Forgetting&quot;&quot;">&ZeroWidthSpace;</a></h2>
<p>Anthropic's Claude Code takes a more nuanced approach. Rather than pursuing one-shot physical deletion, it designs <strong>three progressively stronger cleanup mechanisms</strong> — from light to heavy, avoiding LLM calls whenever possible.</p>
<blockquote>
<p>Note: Claude Code is not open source. The following analysis is based on community reverse engineering and public materials; actual implementation may vary across versions.</p>
</blockquote>
<h3 id="layer-1-tool-result-trimming-zero-llm-cost" tabindex="-1">Layer 1: Tool Result Trimming (Zero LLM Cost) <a class="header-anchor" href="#layer-1-tool-result-trimming-zero-llm-cost" aria-label="Permalink to &quot;Layer 1: Tool Result Trimming (Zero LLM Cost)&quot;">&ZeroWidthSpace;</a></h3>
<p>This is the most frequent and lightweight layer. <strong>No LLM call needed</strong> — it's purely a local rules engine that runs automatically before every request.</p>
<p>The logic is simple:</p>
<ul>
<li>Always protect the results of the most recent tool calls (active data can't be deleted)</li>
<li>Older tool results beyond the protection window → replaced with <code>[Old tool result content cleared]</code> placeholder</li>
</ul>
<p>Applied to our scenario:</p>
<p><img src="https://oss.justin3go.com/blogs/claude-layer1.png" alt="Claude Code Layer 1 compression"></p>
<p>This approach is remarkably clever: it maintains the AI's &quot;flow state.&quot; The AI remembers it searched the code (#4's tool_call is still there), and remembers it read files (#7's tool_call is still there) — it just doesn't remember what the search returned or what the file contained. If it truly needs to look again, it will simply re-issue a <code>read_file</code>.</p>
<p>I find this layer's design exquisitely elegant — it achieves <strong>&quot;selective amnesia&quot; rather than &quot;total forgetting.&quot;</strong> Like remembering you read a great book last year but forgetting the specifics — you can always flip through it again when needed.</p>
<h3 id="layer-2-cache-friendly-strategy-prompt-cache" tabindex="-1">Layer 2: Cache-Friendly Strategy (Prompt Cache) <a class="header-anchor" href="#layer-2-cache-friendly-strategy-prompt-cache" aria-label="Permalink to &quot;Layer 2: Cache-Friendly Strategy (Prompt Cache)&quot;">&ZeroWidthSpace;</a></h3>
<p>This is Claude Code's signature move, and the <strong>unique differentiating advantage</strong> among the three.</p>
<p>Anthropic's API supports Prompt Cache — if the prefix of your message to the API matches the previous request, the server can reuse prior computation results, dramatically reducing cost and latency.</p>
<p>What does this mean? When cleaning messages, Claude Code strives to avoid modifying the first half of the message sequence. It takes a &quot;surgical&quot; approach: trimming only at the tail, ensuring the beginning of the message sequence remains absolutely consistent. The trade-off is slightly lower cleanup efficiency, but the payoff is <strong>maximized cache hit rate</strong>.</p>
<p>Applied to our scenario. Suppose after Layer 1 cleanup, the message sequence is #1-#26 (tool results already replaced with placeholders). Context still exceeds the limit and needs further trimming. A &quot;naive&quot; approach would delete from the earliest messages — but Claude Code <strong>doesn't do that</strong>:</p>
<p><img src="https://oss.justin3go.com/blogs/claude-cache-strategy.png" alt="Cache strategy comparison"></p>
<p>The naive strategy on the left deletes the oldest messages, which seems reasonable, but the cost is that <strong>the entire prefix changes</strong> — the API cache completely invalidates, and the next request must compute from scratch. Claude Code's strategy on the right is the opposite: it would rather delete less, as long as the <strong>prefix portion of the message sequence remains identical to the previous request</strong>, allowing Anthropic's Prompt Cache to hit.</p>
<p>For long-running tasks (like having the AI help you refactor an entire module), this strategy yields significant cost savings — because most of each API request's content can hit cache, and you only pay for the newly added tail content.</p>
<h3 id="layer-3-9-section-structured-llm-summary-last-resort" tabindex="-1">Layer 3: 9-Section Structured LLM Summary (Last Resort) <a class="header-anchor" href="#layer-3-9-section-structured-llm-summary-last-resort" aria-label="Permalink to &quot;Layer 3: 9-Section Structured LLM Summary (Last Resort)&quot;">&ZeroWidthSpace;</a></h3>
<p>When the first two layers can't prevent context from continuing to grow, the system triggers a final full summary. According to the source code, the auto-compaction threshold is <code>effective context window - 13,000 tokens</code> (where effective window = model context window - min(max output tokens, 20,000)).</p>
<p>However, even when the threshold is reached, the system doesn't jump straight to an LLM summary. When auto-compaction triggers, the system <strong>first tries Session Memory Compact</strong> — leveraging structured information already in session memory to substitute for a full LLM call. This means most auto-compactions don't even need an LLM call. Only when the session memory path is unavailable or insufficient does the system fall back to the traditional LLM summary flow, generating a <strong>structured summary with 9 fixed sections</strong>:</p>
<ol>
<li>User's original intent</li>
<li>Core technical concepts</li>
<li>Files and code of interest</li>
<li>Errors encountered and how they were fixed</li>
<li>Problem-solving logic chain</li>
<li>Summary of all user messages</li>
<li>TODO items</li>
<li>What's currently being worked on</li>
<li>Suggested next steps</li>
</ol>
<p>This summary has extremely strict requirements — the prompt demands the model <strong>directly quote key phrases from the original text</strong> rather than paraphrasing everything. This prevents &quot;context drift&quot; (the model subtly diverging from the original meaning during retelling).</p>
<p>Applied to our scenario:</p>
<p><img src="https://oss.justin3go.com/blogs/claude-layer3.png" alt="Claude Code Layer 3 compression"></p>
<p>After compression, Claude Code performs a series of post-processing steps — what I call <strong>&quot;state reconstruction&quot;</strong>:</p>
<ul>
<li>Injects a lead-in at the beginning of the new conversation (&quot;This session continues from a previous conversation...&quot;)</li>
<li><strong>Automatically re-reads</strong> recently edited files (up to 5 files, total budget 50,000 tokens, 5,000 tokens per file), ensuring the AI has the latest code</li>
<li>Re-declares tool and skill definitions</li>
<li>Project specifications in <code>CLAUDE.md</code>, as part of the system prompt, remain permanently resident and are unaffected by compression</li>
</ul>
<p>Users can also attach custom instructions during manual compaction, such as <code>/compact Focus on API changes</code>, to steer the compression toward a specific focus.</p>
<p>Additionally, there's a <strong>passive fallback path</strong>: when the API returns a <code>prompt_too_long</code> error, the system automatically initiates a reactive compression and retries the request, ensuring users don't encounter an abrupt error from context overflow. To prevent infinite loops from repeated compression failures, automatic compaction pauses after 3 consecutive failures.</p>
<p>Claude Code's approach is the most complex of the three, but also the most &quot;cost-effective&quot; — most of the time it only needs to execute the Layer 1 rules engine cleanup, or complete compaction via the Session Memory path, requiring no extra LLM calls at all.</p>
<h2 id="opencode-prune-first-summarize-later-—-stepped-governance" tabindex="-1">OpenCode: Prune First, Summarize Later — &quot;Stepped Governance&quot; <a class="header-anchor" href="#opencode-prune-first-summarize-later-—-stepped-governance" aria-label="Permalink to &quot;OpenCode: Prune First, Summarize Later — &quot;Stepped Governance&quot;&quot;">&ZeroWidthSpace;</a></h2>
<p>The open-source newcomer OpenCode (<a href="https://github.com/anomalyco/opencode" target="_blank" rel="noreferrer">source</a>, TypeScript + Effect-TS implementation) offers a more balanced strategy. In <code>session/compaction.ts</code>, it implements a stepped governance flow: <strong>use low-cost measures to free up space first, and only call on the LLM when truly necessary.</strong></p>
<h3 id="step-1-prune-mark-as-hidden-not-physical-deletion" tabindex="-1">Step 1: Prune (Mark as Hidden, Not Physical Deletion) <a class="header-anchor" href="#step-1-prune-mark-as-hidden-not-physical-deletion" aria-label="Permalink to &quot;Step 1: Prune (Mark as Hidden, Not Physical Deletion)&quot;">&ZeroWidthSpace;</a></h3>
<p>OpenCode's first move isn't deletion — it's &quot;marking.&quot; The rules are crystal clear:</p>
<ul>
<li>Only execute when pruning can free more than 20,000 tokens (minor cleanups aren't worth the hassle)</li>
<li>Always preserve the most recent 40,000 tokens as a &quot;safety cushion&quot; (active work can't be touched)</li>
<li><code>skill</code> type tool outputs are never pruned (they contain operational instructions)</li>
<li>Protect the full content of the last 2 user turns</li>
</ul>
<p><strong>Key design</strong>: Unlike Claude Code's placeholder replacement, OpenCode's pruning <strong>is not physical deletion</strong>. Instead, it stamps old messages with a <code>compacted = Date.now()</code> timestamp, making them &quot;invisible&quot; in subsequent requests. The data is still in the database — just hidden.</p>
<p><img src="https://oss.justin3go.com/blogs/opencode-prune.png" alt="OpenCode Prune"></p>
<p><strong>Key point:</strong> The data isn't truly lost. This leaves room for future history traversal features — if developers need auditing, or if the agent triggers some rollback logic, this data can be pulled back into context. This is a very forward-thinking design.</p>
<h3 id="step-2-llm-5-heading-summary" tabindex="-1">Step 2: LLM 5-Heading Summary <a class="header-anchor" href="#step-2-llm-5-heading-summary" aria-label="Permalink to &quot;Step 2: LLM 5-Heading Summary&quot;">&ZeroWidthSpace;</a></h3>
<p>If things are still too bloated after pruning, OpenCode uses a hidden, dedicated agent (without disturbing the user's current interaction) to call an LLM and generate a summary. This summary follows a fixed 5-heading structure:</p>
<p><img src="https://oss.justin3go.com/blogs/opencode-summary.png" alt="OpenCode LLM Summary"></p>
<p>OpenCode has a wonderfully thoughtful design after summarization: it automatically <strong>replays the last user message</strong>. This ensures the agent's most recent memory point stays on the user's latest instruction, rather than on some cold summary text. The user is completely unaware that compression happened — your last message gets resent, the AI continues responding, as if nothing happened.</p>
<p>Another highlight: <strong>OpenCode follows the user's language</strong>. If you've been communicating in Chinese, its summary will also be in Chinese. For non-native English-speaking developers, this is a very friendly design.</p>
<p>I think OpenCode's approach is the most &quot;developer-friendly&quot; of the three — fully open-source code (TypeScript), modern architecture (Effect-TS), and the non-physical deletion design leaves ample room for extension. If you want to deeply customize compression behavior, OpenCode is the easiest to get started with.</p>
<h2 id="the-three-musketeers-face-off" tabindex="-1">The Three Musketeers Face Off <a class="header-anchor" href="#the-three-musketeers-face-off" aria-label="Permalink to &quot;The Three Musketeers Face Off&quot;">&ZeroWidthSpace;</a></h2>
<p>Let's put all three approaches side by side:</p>
<p>Input: 26 messages, ~15,400 tokens (same &quot;fix login bug&quot; scenario)</p>
<p><img src="https://oss.justin3go.com/blogs/three-comparison.png" alt="Three-way comparison"></p>
<table tabindex="0">
<thead>
<tr>
<th style="text-align:left">Dimension</th>
<th style="text-align:left">Codex CLI</th>
<th style="text-align:left">Claude Code</th>
<th style="text-align:left">OpenCode</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align:left"><strong>Compression Layers</strong></td>
<td style="text-align:left">Single (summary)</td>
<td style="text-align:left">Three (trim/cache/summary)</td>
<td style="text-align:left">Two (hide/summary)</td>
</tr>
<tr>
<td style="text-align:left"><strong>LLM Calls</strong></td>
<td style="text-align:left">Required</td>
<td style="text-align:left">Only at Layer 3</td>
<td style="text-align:left">Only at Step 2</td>
</tr>
<tr>
<td style="text-align:left"><strong>User Messages</strong></td>
<td style="text-align:left">Permanently preserved verbatim</td>
<td style="text-align:left">Summarized (Layer 3)</td>
<td style="text-align:left">Summarized + last message replayed</td>
</tr>
<tr>
<td style="text-align:left"><strong>Tool Result Handling</strong></td>
<td style="text-align:left">Physical deletion</td>
<td style="text-align:left">Placeholder replacement</td>
<td style="text-align:left">Timestamp-based hiding</td>
</tr>
<tr>
<td style="text-align:left"><strong>Cache Optimization</strong></td>
<td style="text-align:left">No special design</td>
<td style="text-align:left">Deep Prompt Cache integration</td>
<td style="text-align:left">Focused on reducing redundant reads</td>
</tr>
<tr>
<td style="text-align:left"><strong>Post-Compression Behavior</strong></td>
<td style="text-align:left">Passive waiting</td>
<td style="text-align:left">Proactive re-reading of relevant files</td>
<td style="text-align:left">Auto-replay of last instruction</td>
</tr>
</tbody>
</table>
<h3 id="differences-worth-expanding-on" tabindex="-1">Differences Worth Expanding On <a class="header-anchor" href="#differences-worth-expanding-on" aria-label="Permalink to &quot;Differences Worth Expanding On&quot;">&ZeroWidthSpace;</a></h3>
<p><strong>On whether to preserve user messages verbatim</strong>: Codex chooses to keep user messages intact, compressing only model responses. The advantage is that the AI can always look back at what you said, but the cost is reduced compression efficiency when user messages themselves are lengthy. Claude Code and OpenCode choose to compress everything into summaries — more aggressive but more space-efficient.</p>
<p><strong>On caching</strong>: This is Claude Code's most unique advantage. The other two see significant changes in API request content after compression, essentially invalidating previous caches. Claude Code deliberately maintains prefix stability, allowing post-compression requests to still reuse prior caches. For long-running tasks, this translates to meaningful cost savings.</p>
<p><strong>On non-physical deletion</strong>: OpenCode's timestamp marking approach is a forward-thinking design. While the current version doesn't implement history traversal, the data isn't truly lost, leaving the door open for future possibilities. Both Codex and Claude Code's compressions are irreversible.</p>
<h2 id="final-thoughts" tabindex="-1">Final Thoughts <a class="header-anchor" href="#final-thoughts" aria-label="Permalink to &quot;Final Thoughts&quot;">&ZeroWidthSpace;</a></h2>
<p>If I were to describe these three with an analogy:</p>
<ul>
<li><strong>Codex CLI</strong> is like a senior employee writing a <strong>handoff memo</strong>. They tear up the previous drafts and hand you a clear status report — blunt but effective.</li>
<li><strong>Claude Code</strong> is like a scholar with the ability to <strong>forget with precision</strong>. They first erase minor annotations in their books, and only when the bookshelf truly can't hold any more do they condense entire books into one-page outlines. They care deeply about the efficiency of flipping through books (caching).</li>
<li><strong>OpenCode</strong> is like a pragmatic <strong>stepped governance</strong> administrator. They first box up old files and label them (hide), and only summarize when absolutely necessary. Their most thoughtful touch? After summarizing, they remind you: &quot;The last thing you said was about this, right?&quot;</li>
</ul>
<p>Ultimately, in 2026, the best context management isn't about endlessly expanding an LLM's memory capacity, but learning how to <strong>forget with precision</strong>. After all, an agent that remembers everything is often the one most easily distracted by noise.</p>
<hr>
<p><strong>References:</strong></p>
<ul>
<li>Codex CLI: <a href="https://github.com/openai/codex" target="_blank" rel="noreferrer">openai/codex</a> (see <code>codex-rs/core/src/compact.rs</code>)</li>
<li>Claude Code community resources:
<ul>
<li><a href="https://github.com/Piebald-AI/claude-code-system-prompts" target="_blank" rel="noreferrer">Claude Code System Prompts</a></li>
<li><a href="https://gist.github.com/sam-saffron-jarvis/9d8e291c4e696ac7948702d6c4884448" target="_blank" rel="noreferrer">Sam Saffron's Gist</a></li>
<li><a href="https://barazany.dev/blog/claude-codes-compaction-engine" target="_blank" rel="noreferrer">Claude Code's Compaction Engine</a></li>
<li><a href="https://github.com/yasasbanukaofficial/claude-code" target="_blank" rel="noreferrer">Leaked source repository</a> (unofficial leak, used for verification)</li>
</ul>
</li>
<li>OpenCode: <a href="https://github.com/anomalyco/opencode" target="_blank" rel="noreferrer">anomalyco/opencode</a> (see <code>packages/opencode/src/session/compaction.ts</code>)</li>
</ul>
]]></content:encoded>
            <author>just@justin3go.com (Justin3go)</author>
        </item>
        <item>
            <title><![CDATA[I Distilled Harness Engineering Into a SKILL]]></title>
            <link>https://justin3go.com/en/posts/2026/04/03-harness-engineering-distilled-into-a-skill</link>
            <guid>https://justin3go.com/en/posts/2026/04/03-harness-engineering-distilled-into-a-skill</guid>
            <pubDate>Fri, 03 Apr 2026 00:00:00 GMT</pubDate>
            <description><![CDATA[<h1 id="i-distilled-harness-engineering-into-a-skill" tabindex="-1">I Distilled Harness Engineering Into a SKILL <a class="header-anchor" href="#i-distilled-harness-engineering-into-a-skill" aria-label="Permalink to &quot;I Distilled Harness Engineering Into a SKILL&quot;">&ZeroWidthSpace;</a></h1>
<blockquote>
<p>✨Article Summary (AI Generated)</p>
</blockquote>
<!-- DESC SEP -->
<blockquote></blockquote>
<p>The author shares his experience of distilling Harness Engineering knowledge into a reusable Agent Skill. After systematically studying sources from Anthropic, OpenAI, Martin Fowler, LangChain, and others, he identified seven core layers of harness design: project setup, context engineering, constraints &amp; guardrails, multi-agent architecture, evaluation &amp; feedback, long-running tasks, and diagnostics. The resulting <code>harness-engineering</code> skill covers three scenarios — new project scaffolding, diagnosing poor agent behavior, and continuous improvement — using a progressive-disclosure architecture. Quantitative evaluation showed 100% assertion pass rate with the skill vs. 83% without. The key insight: <strong>80% of agent quality issues stem from harness gaps, not model limitations.</strong></p>
<blockquote></blockquote>
<!-- DESC SEP -->
<h2 id="why-i-wrote-this" tabindex="-1">Why I Wrote This <a class="header-anchor" href="#why-i-wrote-this" aria-label="Permalink to &quot;Why I Wrote This&quot;">&ZeroWidthSpace;</a></h2>
<p>Over the past two years, while using various AI coding assistants (Claude Code, Cursor, Copilot, etc.), I kept running into the same problem: <strong>Agent performance was inconsistent.</strong> While things have generally improved as models get better, the journey has been full of ups and downs.</p>
<p><img src="https://oss.justin3go.com/blogs/20260403201320478.png" alt=""></p>
<p>Sometimes the code it writes perfectly matches the project style. Other times it acts like an intern on their first day — unaware of the project structure, ignoring conventions, and forgetting decisions we'd already agreed on.</p>
<p>I started applying Prompt Engineering techniques like structured prompts, few-shot examples, and demonstrations to stabilize AI output. Then I moved on to Context Engineering to enrich the agent's context and further stabilize its performance.</p>
<p>In recent weeks, a more systematic term has emerged: Harness Engineering.</p>
<blockquote>
<p><strong>When an agent performs poorly, 80% of the time the issue isn't the model — it's the Harness.</strong> — Anthropic</p>
</blockquote>
<p>What is a Harness? Simply put:</p>
<ul>
<li><strong>Model = CPU</strong> (the compute itself)</li>
<li><strong>Context Window = RAM</strong> (working memory)</li>
<li><strong>Harness = Operating System</strong> (scheduling, constraints, feedback, file system — all the infrastructure that makes the CPU work effectively)</li>
</ul>
<p>You wouldn't expect a CPU to run efficiently on bare metal without an operating system. Similarly, you shouldn't expect a model to produce consistent output in a project without a Harness.</p>
<p><img src="https://oss.justin3go.com/blogs/20260403201256128.png" alt=""></p>
<h2 id="what-i-learned" tabindex="-1">What I Learned <a class="header-anchor" href="#what-i-learned" aria-label="Permalink to &quot;What I Learned&quot;">&ZeroWidthSpace;</a></h2>
<p>I systematically read articles from the following sources:</p>
<ul>
<li><strong>Anthropic</strong> — Building effective agents, multi-agent research systems, harness design for long-running agents</li>
<li><strong>OpenAI</strong> — AGENTS.md design patterns, Context Engineering best practices</li>
<li><strong>Martin Fowler</strong> — The engineering philosophy of Harness Engineering (&quot;Relocating Rigor&quot;)</li>
<li><strong>LangChain</strong> — Taxonomy of agent frameworks vs. runtimes vs. harnesses</li>
<li><strong>philschmid</strong> — The importance of Agent Harness in 2026</li>
<li><strong>Independent developers</strong> — Hermes Agent's self-evolution, Vue Lynx's design-notes-driven development</li>
<li><strong>Academic papers</strong> — Formalization of natural language agent harnesses</li>
</ul>
<p>After reading everything, I found that while these articles approached the topic from different angles, their core ideas converged into <strong>seven layers</strong>:</p>
<p><img src="https://oss.justin3go.com/blogs/20260403201232141.png" alt=""></p>
<p>| Layer | What Problem It Solves | One-Line Summary |
|</p>
]]></description>
            <content:encoded><![CDATA[<h1 id="i-distilled-harness-engineering-into-a-skill" tabindex="-1">I Distilled Harness Engineering Into a SKILL <a class="header-anchor" href="#i-distilled-harness-engineering-into-a-skill" aria-label="Permalink to &quot;I Distilled Harness Engineering Into a SKILL&quot;">&ZeroWidthSpace;</a></h1>
<blockquote>
<p>✨Article Summary (AI Generated)</p>
</blockquote>
<!-- DESC SEP -->
<blockquote></blockquote>
<p>The author shares his experience of distilling Harness Engineering knowledge into a reusable Agent Skill. After systematically studying sources from Anthropic, OpenAI, Martin Fowler, LangChain, and others, he identified seven core layers of harness design: project setup, context engineering, constraints &amp; guardrails, multi-agent architecture, evaluation &amp; feedback, long-running tasks, and diagnostics. The resulting <code>harness-engineering</code> skill covers three scenarios — new project scaffolding, diagnosing poor agent behavior, and continuous improvement — using a progressive-disclosure architecture. Quantitative evaluation showed 100% assertion pass rate with the skill vs. 83% without. The key insight: <strong>80% of agent quality issues stem from harness gaps, not model limitations.</strong></p>
<blockquote></blockquote>
<!-- DESC SEP -->
<h2 id="why-i-wrote-this" tabindex="-1">Why I Wrote This <a class="header-anchor" href="#why-i-wrote-this" aria-label="Permalink to &quot;Why I Wrote This&quot;">&ZeroWidthSpace;</a></h2>
<p>Over the past two years, while using various AI coding assistants (Claude Code, Cursor, Copilot, etc.), I kept running into the same problem: <strong>Agent performance was inconsistent.</strong> While things have generally improved as models get better, the journey has been full of ups and downs.</p>
<p><img src="https://oss.justin3go.com/blogs/20260403201320478.png" alt=""></p>
<p>Sometimes the code it writes perfectly matches the project style. Other times it acts like an intern on their first day — unaware of the project structure, ignoring conventions, and forgetting decisions we'd already agreed on.</p>
<p>I started applying Prompt Engineering techniques like structured prompts, few-shot examples, and demonstrations to stabilize AI output. Then I moved on to Context Engineering to enrich the agent's context and further stabilize its performance.</p>
<p>In recent weeks, a more systematic term has emerged: Harness Engineering.</p>
<blockquote>
<p><strong>When an agent performs poorly, 80% of the time the issue isn't the model — it's the Harness.</strong> — Anthropic</p>
</blockquote>
<p>What is a Harness? Simply put:</p>
<ul>
<li><strong>Model = CPU</strong> (the compute itself)</li>
<li><strong>Context Window = RAM</strong> (working memory)</li>
<li><strong>Harness = Operating System</strong> (scheduling, constraints, feedback, file system — all the infrastructure that makes the CPU work effectively)</li>
</ul>
<p>You wouldn't expect a CPU to run efficiently on bare metal without an operating system. Similarly, you shouldn't expect a model to produce consistent output in a project without a Harness.</p>
<p><img src="https://oss.justin3go.com/blogs/20260403201256128.png" alt=""></p>
<h2 id="what-i-learned" tabindex="-1">What I Learned <a class="header-anchor" href="#what-i-learned" aria-label="Permalink to &quot;What I Learned&quot;">&ZeroWidthSpace;</a></h2>
<p>I systematically read articles from the following sources:</p>
<ul>
<li><strong>Anthropic</strong> — Building effective agents, multi-agent research systems, harness design for long-running agents</li>
<li><strong>OpenAI</strong> — AGENTS.md design patterns, Context Engineering best practices</li>
<li><strong>Martin Fowler</strong> — The engineering philosophy of Harness Engineering (&quot;Relocating Rigor&quot;)</li>
<li><strong>LangChain</strong> — Taxonomy of agent frameworks vs. runtimes vs. harnesses</li>
<li><strong>philschmid</strong> — The importance of Agent Harness in 2026</li>
<li><strong>Independent developers</strong> — Hermes Agent's self-evolution, Vue Lynx's design-notes-driven development</li>
<li><strong>Academic papers</strong> — Formalization of natural language agent harnesses</li>
</ul>
<p>After reading everything, I found that while these articles approached the topic from different angles, their core ideas converged into <strong>seven layers</strong>:</p>
<p><img src="https://oss.justin3go.com/blogs/20260403201232141.png" alt=""></p>
<table tabindex="0">
<thead>
<tr>
<th>Layer</th>
<th>What Problem It Solves</th>
<th>One-Line Summary</th>
</tr>
</thead>
<tbody>
<tr>
<td><strong>Project Setup</strong></td>
<td>Agent doesn't know what the project is</td>
<td>AGENTS.md is a table of contents, not an encyclopedia</td>
</tr>
<tr>
<td><strong>Context Engineering</strong></td>
<td>Agent sees the wrong information</td>
<td>Give a map, not a manual</td>
</tr>
<tr>
<td><strong>Constraints &amp; Guardrails</strong></td>
<td>Agent keeps making the same mistakes</td>
<td>Every mistake → add a rule</td>
</tr>
<tr>
<td><strong>Multi-Agent Architecture</strong></td>
<td>Single agent can't handle complex tasks</td>
<td>Clear division of labor, clear protocols</td>
</tr>
<tr>
<td><strong>Evaluation &amp; Feedback</strong></td>
<td>Don't know if the agent is doing well</td>
<td>Let AI check AI</td>
</tr>
<tr>
<td><strong>Long-Running Tasks</strong></td>
<td>Agent drifts off course over time</td>
<td>Progress files + context resets</td>
</tr>
<tr>
<td><strong>Diagnostics</strong></td>
<td>Users complain the agent is bad</td>
<td>The problem is the Harness, not the model</td>
</tr>
</tbody>
</table>
<h2 id="so-i-built-a-skill" tabindex="-1">So I Built a Skill <a class="header-anchor" href="#so-i-built-a-skill" aria-label="Permalink to &quot;So I Built a Skill&quot;">&ZeroWidthSpace;</a></h2>
<p>After reading all these articles, I realized these patterns are entirely <strong>reusable</strong>. Whether your project is a React frontend, Python backend, or Rust CLI tool — the design principles of a Harness are universal.</p>
<p>So I distilled this knowledge into an <strong>Agent Skill</strong> called <code>harness-engineering</code>.</p>
<h3 id="what-it-does" tabindex="-1">What It Does <a class="header-anchor" href="#what-it-does" aria-label="Permalink to &quot;What It Does&quot;">&ZeroWidthSpace;</a></h3>
<p>This skill has three core use cases:</p>
<p><strong>Scenario 1: New Project Setup</strong></p>
<p>When you start a new project and tell the agent &quot;help me set up Harness engineering,&quot; it will:</p>
<ol>
<li>Assess your project type, tech stack, and team size</li>
<li>Create an <code>AGENTS.md</code> (a table-of-contents-style agent navigation file)</li>
<li>Set up a <code>docs/</code> directory (architecture, conventions, data models, etc.)</li>
<li>Configure the constraints layer (lint rules, type checking, pre-commit hooks)</li>
<li>Set up evaluation and feedback mechanisms</li>
</ol>
<p><strong>Scenario 2: Diagnosing Poor Agent Performance</strong></p>
<p>This is the most interesting scenario. When you start complaining —</p>
<ul>
<li>&quot;Why does it keep making the same mistake?&quot;</li>
<li>&quot;It completely ignores our conventions!&quot;</li>
<li>&quot;The code quality is terrible&quot;</li>
</ul>
<p>This skill gets triggered and guides the agent to diagnose <strong>gaps in the Harness layer</strong>, rather than blaming the model:</p>
<table tabindex="0">
<thead>
<tr>
<th>Your Complaint</th>
<th>Most Likely Cause</th>
<th>Fix</th>
</tr>
</thead>
<tbody>
<tr>
<td>Keeps making the same mistake</td>
<td>No constraint preventing it</td>
<td>Add a lint rule</td>
</tr>
<tr>
<td>Doesn't follow conventions</td>
<td>Conventions aren't written down or agent can't find them</td>
<td>Write in docs/, reference in AGENTS.md</td>
</tr>
<tr>
<td>Forgets previous decisions</td>
<td>Cross-session context not persisted</td>
<td>Use progress.md to record decisions</td>
</tr>
<tr>
<td>Poor code quality</td>
<td>No examples of good code</td>
<td>Add examples in DESIGN_NOTES.md</td>
</tr>
</tbody>
</table>
<p><strong>Scenario 3: Continuous Improvement</strong></p>
<p>Every time a new reusable Harness pattern is discovered, update it in the skill so other projects can benefit too.</p>
<h3 id="how-it-s-organized" tabindex="-1">How It's Organized <a class="header-anchor" href="#how-it-s-organized" aria-label="Permalink to &quot;How It's Organized&quot;">&ZeroWidthSpace;</a></h3>
<p>The skill uses a <strong>progressive disclosure</strong> architecture:</p>
<div class="language- vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang"></span><pre class="shiki shiki-themes github-light github-dark vp-code" tabindex="0" v-pre=""><code><span class="line"><span>harness-engineering/</span></span>
<span class="line"><span>├── SKILL.md              # Entry file (&#x3C;60 lines), routes to specific references</span></span>
<span class="line"><span>└── references/</span></span>
<span class="line"><span>    ├── 01-project-setup.md       # Project setup</span></span>
<span class="line"><span>    ├── 02-context-engineering.md  # Context engineering</span></span>
<span class="line"><span>    ├── 03-constraints.md          # Constraints &#x26; guardrails</span></span>
<span class="line"><span>    ├── 04-multi-agent.md          # Multi-agent architecture</span></span>
<span class="line"><span>    ├── 05-eval-feedback.md        # Evaluation &#x26; feedback</span></span>
<span class="line"><span>    ├── 06-long-running.md         # Long-running tasks</span></span>
<span class="line"><span>    └── 07-diagnosis.md            # Diagnostics</span></span></code></pre>
</div><p>SKILL.md itself is very concise — it acts like a router, directing the agent to read the relevant reference document based on the current scenario. This follows a core principle of Harness Engineering itself: <strong>progressive disclosure, load on demand</strong>.</p>
<h2 id="patterns-that-impressed-me" tabindex="-1">Patterns That Impressed Me <a class="header-anchor" href="#patterns-that-impressed-me" aria-label="Permalink to &quot;Patterns That Impressed Me&quot;">&ZeroWidthSpace;</a></h2>
<p>A few patterns particularly resonated with me. Let me discuss them individually.</p>
<h3 id="give-a-map-not-a-manual" tabindex="-1">&quot;Give a Map, Not a Manual&quot; <a class="header-anchor" href="#give-a-map-not-a-manual" aria-label="Permalink to &quot;&quot;Give a Map, Not a Manual&quot;&quot;">&ZeroWidthSpace;</a></h3>
<p>I saw this concept in a tweet. The traditional approach is to write detailed step-by-step instructions (a manual) for the agent, but this makes the agent fragile — any deviation leaves it lost.</p>
<p>A better approach is to give the agent a <strong>map</strong>:</p>
<div class="language-markdown vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">markdown</span><pre class="shiki shiki-themes github-light github-dark vp-code" tabindex="0" v-pre=""><code><span class="line"><span style="--shiki-light:#005CC5;--shiki-light-font-weight:bold;--shiki-dark:#79B8FF;--shiki-dark-font-weight:bold"># Bad approach (manual)</span></span>
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">Step 1: Open src/auth/login.ts</span></span>
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">Step 2: Find the handleLogin function</span></span>
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">Step 3: Add ... at line 42</span></span>
<span class="line"></span>
<span class="line"><span style="--shiki-light:#005CC5;--shiki-light-font-weight:bold;--shiki-dark:#79B8FF;--shiki-dark-font-weight:bold"># Good approach (map)</span></span>
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">Auth system is in src/auth/. Login flow: login.ts → validate.ts → session.ts.</span></span>
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">Rate limiting middleware is in src/middleware/rateLimit.ts — follow its pattern.</span></span>
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">Every auth change needs a test in src/auth/</span><span style="--shiki-light:#24292E;--shiki-light-font-weight:bold;--shiki-dark:#E1E4E8;--shiki-dark-font-weight:bold">__tests__</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8">/.</span></span></code></pre>
</div><p>A map lets the agent navigate autonomously; a manual turns it into a fragile execution machine.</p>
<h3 id="every-mistake-→-add-a-rule" tabindex="-1">&quot;Every Mistake → Add a Rule&quot; <a class="header-anchor" href="#every-mistake-→-add-a-rule" aria-label="Permalink to &quot;&quot;Every Mistake → Add a Rule&quot;&quot;">&ZeroWidthSpace;</a></h3>
<p>This pattern comes from cross-referencing multiple articles. The core idea:</p>
<ol>
<li>The agent makes a mistake</li>
<li>You fix the mistake</li>
<li><strong>Then you add a rule to permanently prevent that type of mistake from happening again</strong></li>
</ol>
<p>This rule can be a lint rule, a type constraint, a test case, or simply a convention in the documentation. Over time, the Harness accumulates more and more rules, and the agent's error rate for known patterns approaches zero.</p>
<p>This is exactly what Martin Fowler calls <strong>&quot;Relocating Rigor&quot;</strong> — moving the quality gates that humans enforce through code review, experience, and intuition into automated checks. The agent runs freely within the checked boundaries.</p>
<p><img src="https://oss.justin3go.com/blogs/20260403201204929.png" alt=""></p>
<h3 id="harness-dataset" tabindex="-1">Harness = Dataset <a class="header-anchor" href="#harness-dataset" aria-label="Permalink to &quot;Harness = Dataset&quot;">&ZeroWidthSpace;</a></h3>
<p>This perspective comes from Anthropic. Every agent interaction is a training signal:</p>
<ul>
<li>What it tried</li>
<li>What succeeded</li>
<li>What failed</li>
<li>What the fix was</li>
</ul>
<p>These traces are your <strong>competitive advantage</strong>. They're the data that makes your Harness better over time — not fine-tuning the model, but optimizing the operating system.</p>
<h2 id="skill-evaluation-does-it-work" tabindex="-1">Skill Evaluation: Does It Work? <a class="header-anchor" href="#skill-evaluation-does-it-work" aria-label="Permalink to &quot;Skill Evaluation: Does It Work?&quot;">&ZeroWidthSpace;</a></h2>
<p>Following the skill-creator process, I conducted a quantitative evaluation of this skill. I designed 3 test scenarios, running with-skill and without-skill versions for each:</p>
<table tabindex="0">
<thead>
<tr>
<th>Test Scenario</th>
<th>With Skill</th>
<th>Without Skill</th>
</tr>
</thead>
<tbody>
<tr>
<td>New project setup</td>
<td>6/6 ✅</td>
<td>4/6</td>
</tr>
<tr>
<td>Agent behavior diagnosis</td>
<td>6/6 ✅</td>
<td>5/6</td>
</tr>
<tr>
<td>Cross-module dependency issues</td>
<td>6/6 ✅</td>
<td>6/6</td>
</tr>
<tr>
<td><strong>Total</strong></td>
<td><strong>18/18 (100%)</strong></td>
<td><strong>15/18 (83%)</strong></td>
</tr>
</tbody>
</table>
<p>The with-skill version passed all assertions in every scenario. The without-skill version had the most gaps in the &quot;new project setup&quot; scenario — it didn't know to create AGENTS.md, didn't know how to organize docs/, and couldn't set up the progressive disclosure context architecture.</p>
<p>Of course, a 17% difference isn't enormous. But the key point is: with the skill, the agent's output was <strong>consistent and complete</strong>; without it, results were hit or miss. For an engineering practice skill, consistency is more valuable than occasional brilliance.</p>
<h2 id="how-to-install" tabindex="-1">How to Install <a class="header-anchor" href="#how-to-install" aria-label="Permalink to &quot;How to Install&quot;">&ZeroWidthSpace;</a></h2>
<p>This skill can be installed via GitHub:</p>
<div class="language-bash vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">bash</span><pre class="shiki shiki-themes github-light github-dark vp-code" tabindex="0" v-pre=""><code><span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0">npx</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF"> skills</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF"> add</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF"> 10xChengTu/harness-engineering</span></span></code></pre>
</div><p>After installation, when working in Claude Code, OpenCode, or other agents that support Skills:</p>
<ul>
<li>Starting a new project → the skill auto-triggers to guide Harness setup</li>
<li>Encountering agent quality issues → the skill intervenes for diagnosis when you start complaining</li>
<li>Proactive inquiry → &quot;Help me improve this project's Harness&quot;</li>
</ul>
<h2 id="final-thoughts" tabindex="-1">Final Thoughts <a class="header-anchor" href="#final-thoughts" aria-label="Permalink to &quot;Final Thoughts&quot;">&ZeroWidthSpace;</a></h2>
<p>Harness Engineering is still a very early field. Models are getting stronger, and constraints needed today might be unnecessary tomorrow — so this skill itself follows a core principle: <strong>build for deletion</strong>.</p>
<p>If you're also doing development with AI Agents, try adding a Harness to your project. Start simple — an <code>AGENTS.md</code> file, a few lint rules, a progress.md. Then observe how the agent's performance changes.</p>
<p>You'll most likely feel the same way I do: <strong>It's not that the model isn't good enough — we just haven't given it a good working environment.</strong></p>
<blockquote>
<p>All referenced articles and the complete skill source code can be found in the <a href="https://github.com/10xChengTu/harness-engineering" target="_blank" rel="noreferrer">GitHub repository</a>.</p>
</blockquote>
]]></content:encoded>
            <author>just@justin3go.com (Justin3go)</author>
        </item>
    </channel>
</rss>