<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>Agent Memory Architecture on RockB</title><link>https://baeseokjae.github.io/tags/agent-memory-architecture/</link><description>Recent content in Agent Memory Architecture on RockB</description><image><title>RockB</title><url>https://baeseokjae.github.io/images/og-default.png</url><link>https://baeseokjae.github.io/images/og-default.png</link></image><generator>Hugo</generator><language>en-us</language><lastBuildDate>Thu, 15 Oct 2026 15:15:00 +0000</lastBuildDate><atom:link href="https://baeseokjae.github.io/tags/agent-memory-architecture/index.xml" rel="self" type="application/rss+xml"/><item><title>MyThinkNode Memory Review 2026: An ~8,100-Line Local Coding Agent With a Keyword-Navigated Memory Tree</title><link>https://baeseokjae.github.io/posts/mythinknode-memory-2026/</link><pubDate>Thu, 15 Oct 2026 15:15:00 +0000</pubDate><guid>https://baeseokjae.github.io/posts/mythinknode-memory-2026/</guid><description>Source-verified review of MyThinkNode v1.0.0 at commit 0095fa7e: ~8,100 lines of TypeScript, 16 tools, and three memory subsystems (NodeMind, InferMem, TraitGraph) with no vector database.</description><content:encoded><![CDATA[<p>MyThinkNode is a single-author, MIT-licensed TypeScript coding agent whose memory lives in a keyword-navigated node tree on the local filesystem instead of a vector index. Parent nodes hold <code>keywords[]</code> rather than content, the model walks the tree itself through a <code>Knowledge(read)</code> tool, and one component — the Reflector — is the only writer. Verified at commit <code>0095fa7e</code> (package <code>@wangzt_mw/mythinknode</code> v1.0.0, released 2026-08-26), the repository holds 8,147 lines of TypeScript across 92 <code>.ts</code> files, declares 16 tools, and lists zero runtime dependencies other than <code>zod</code>.</p>
<p>That answers the reader problem directly: for a developer who does not want to run Postgres with pgvector, Qdrant, or a hosted memory API, a filesystem keyword tree is genuinely sufficient to carry experience between sessions — the design needs no embedding model, no index build, and no network service. What it is not is a proven one. The repository has 2 stars and 0 forks, there is no test suite in the tree, the documentation is Chinese-only, and every design claim below traces back to the author&rsquo;s own files. This review is therefore source-verified architecture with a reproducible verification path — not a measured outcome.</p>
<h2 id="how-this-review-was-verified-and-how-you-can-repeat-it">How this review was verified (and how you can repeat it)</h2>
<p>Every factual claim here is anchored to the public repository at one recorded commit, not to the project&rsquo;s marketing summary. The repository is <a href="https://github.com/wangztmw/mythinknode">wangztmw/mythinknode</a>, and the verified revision is <a href="https://github.com/wangztmw/mythinknode/commit/0095fa7e31ead09f592056ed94c2942d4682bdab">commit 0095fa7e</a>, committed 2026-08-27T09:30:55+08:00.</p>
<p>The check is a bounded author-side read, not a service measurement, and it can be repeated in about a minute:</p>
<pre tabindex="0"><code>git clone --depth 1 https://github.com/wangztmw/mythinknode.git
git rev-parse HEAD                      # 0095fa7e31ead09f592056ed94c2942d4682bdab
find . -path ./.git -prune -o -name &#39;*.ts&#39; -print | wc -l    # 92
find . -path ./.git -prune -o -name &#39;*.ts&#39; -print | xargs wc -l | tail -1   # 8147 total
</code></pre><p>Line counts include comments and blank lines; there is no <code>dist/</code> or <code>node_modules/</code> directory in the clone, so the 8,147 figure is the whole tracked source surface, not logical statements. Design statements were read from the files the project itself publishes: the <a href="https://raw.githubusercontent.com/wangztmw/mythinknode/main/README.md">README</a>, the <a href="https://raw.githubusercontent.com/wangztmw/mythinknode/main/CHANGELOG.md">CHANGELOG</a>, <a href="https://raw.githubusercontent.com/wangztmw/mythinknode/main/package.json">package.json</a>, <a href="https://raw.githubusercontent.com/wangztmw/mythinknode/main/src/nodemind/reflector.ts">src/nodemind/reflector.ts</a>, <a href="https://raw.githubusercontent.com/wangztmw/mythinknode/main/src/query_loop.ts">src/query_loop.ts</a> and <a href="https://raw.githubusercontent.com/wangztmw/mythinknode/main/src/session_loop.ts">src/session_loop.ts</a>, each fetched from the <code>main</code> branch whose head is <code>0095fa7e</code>. The raw artifacts of this pass stay in the repository&rsquo;s private evidence directory for controller verification; they are not offered to readers as a downloadable dataset, and nothing on this page depends on receiving them.</p>
<p>No run, benchmark or recall test was performed for this article. Where the author makes a performance claim, it is labelled as the author&rsquo;s claim. The README and CHANGELOG are written in Chinese; the quoted lines below are translations, not the author&rsquo;s exact English wording.</p>
<h2 id="what-mythinknode-is-verified-at-v100">What MyThinkNode is, verified at v1.0.0</h2>
<p>The repository metadata read from the <a href="https://api.github.com/repos/wangztmw/mythinknode">GitHub repository API</a> on 2026-10-15 gives: created 2026-08-13T23:12:36Z, last push 2026-08-27T01:30:58Z, default branch <code>main</code>, MIT license, TypeScript, 2 stars, 0 forks, 0 open issues, and the project description &ldquo;Minimal AI coding agent with cross-session memory — a navigable knowledge tree (NodeMind) that remembers past pitfalls&rdquo;. <a href="https://raw.githubusercontent.com/wangztmw/mythinknode/main/package.json">package.json</a> declares the package as <code>@wangzt_mw/mythinknode</code> version <code>1.0.0</code>, whose 1.0.0 entry in the <a href="https://raw.githubusercontent.com/wangztmw/mythinknode/main/CHANGELOG.md">CHANGELOG</a> is dated 2026-08-26.</p>
<p>The repository was last pushed 49 days before this review read it, so the verified state is genuinely the current state, not a stale branch: the head commit returned by the API is the same <code>0095fa7e</code> revision fetched and cloned here.</p>
<p>Scope correction, recorded explicitly: earlier notes on this project described roughly 4,300 lines of TypeScript, 13 tools and a single memory design (NodeMind). That was the 2026-08-14 snapshot of the same work in progress. At v1.0.0 the verified figures are ~8,100 lines, 16 tools, and three separate memory subsystems. The reader problem is unchanged; the numbers and the subsystem list are not, and the old figures should not be repeated.</p>
<h2 id="the-core-thesis-session_loop--query_loop">The core thesis: session_loop × query_loop</h2>
<p>The README states the project&rsquo;s skeleton in one line: <code>session_loop × query_loop (LLM × tool)</code>, then explains it — the <code>session_loop</code> owns one session&rsquo;s full pipeline (pre-retrieval → execution → reflection → compression) while the <code>query_loop</code> owns a single LLM ↔ tool round, and multiplying the two is the entire agent skeleton (translation of the README). <a href="https://raw.githubusercontent.com/wangztmw/mythinknode/main/src/query_loop.ts">src/query_loop.ts</a> carries that shape in code as a <code>LoopResult</code> interface with the terminal states <code>success</code>, <code>blocked</code>, <code>killed</code>, <code>crashed</code> and <code>max_rounds</code>, plus token counters.</p>
<p>The thesis matters for memory because it fixes where memory belongs. If an agent is two loops, memory is not a subsystem bolted beside them — it is a resource the loops consult, and MyThinkNode makes that consultation explicit and model-driven. The practical consequence is that a memory read costs a decision and a tool call rather than an injection, which is the trade this review keeps returning to.</p>
<h2 id="three-memory-subsystems-one-pipeline">Three memory subsystems, one pipeline</h2>
<p>The 1.0.0 CHANGELOG entry announces three &ldquo;memory/knowledge&rdquo; designs arriving together, and this is the material change since the seed snapshot:</p>
<ul>
<li><strong>NodeMind / Session Graph Map</strong> — the cross-session experience tree with native AI search and logical tree retention, where &ldquo;failure routes are worth more than successes&rdquo;.</li>
<li><strong>InferMem</strong> — a cross-document knowledge DAG that batch-compiles markdown into an evidence-bearing knowledge graph with the atom types <code>concept/definition/theorem/formula/table/case</code>, merging across documents by an <code>identityKey</code>, never merging <code>case</code> atoms, keeping pointers to the source text, inferring implicit edges, and using a cheap model for bulk extraction.</li>
<li><strong>TraitGraph</strong> — a session-level &ldquo;thinking-execution&rdquo; trace graph whose nodes record <code>goal/plan/direction</code> and whose edges record <code>action → result</code>, with <code>backtrack</code> marking a dead end; the model writes these explicitly, indexed by <code>T{n}</code> markers that align with the <code>S{n}</code> raw-session index, and session memory can recall and inject them.</li>
</ul>
<p>The same entry records the tool count rising to 16 with the addition of <code>Infer</code>, <code>InferQuery</code> and <code>TraitGraph</code>, plus a fix to the NodeMind Reflector for the case where the LLM emits a title made only of Chinese characters or symbols, leaving an empty node id after slugging and breaking the <code>upsertNode</code> validation — dirty attributes and nodes are now skipped tolerantly.</p>
<p>The README&rsquo;s own ordering makes the split meaningful: NodeMind stores settled experience (&ldquo;how to do things&rdquo;), InferMem stores knowledge (&ldquo;what is in books and documents&rdquo;), and TraitGraph stores the process of one session (&ldquo;how the model thought and tried, step by step&rdquo;). Whether the three layers behave as described is the author&rsquo;s design intent — no run was performed here to confirm it.</p>
<h2 id="nodemind-parent-nodes-hold-keywords-not-content">NodeMind: parent nodes hold keywords, not content</h2>
<p>NodeMind is described as the project&rsquo;s core original design and the one other coding agents do not have. Its stated problem is that every conversation starts from zero: the agent does not remember the pitfalls it hit, the routes that worked, or the tool combinations that were effective, and conventional RAG vectorises answers and feeds whole blocks back into a context window that then overflows.</p>
<p>The three deliberately counter-intuitive choices are listed in the README:</p>
<ul>
<li><strong>Layered navigation, scattered information</strong> — parent nodes store only <code>keywords[]</code> (&ldquo;what am I related to&rdquo;) and never the body text. The LLM must walk the path: read the root node, decide which branch to descend, read the child, continue or stop. The context stays bounded at every step.</li>
<li><strong>Single-layer search, agent-driven descent</strong> — search queries exactly one layer and returns <code>{ matches, deeperIds, deeperHints }</code>. The right to go deeper belongs to the agent, which loads nodes one at a time with <code>Knowledge(read)</code> and descends only if it decides it needs more. Information is pulled by the agent, not pushed by the system.</li>
<li><strong>Remember marks, Reflector writes</strong> — during the loop the agent tags moments with <code>Remember(action='tag')</code>, which only enqueues a <code>[REMEMBER_TAG]</code>; persistence happens later.</li>
</ul>
<p>The tree is stored under <code>~/.mythinknode/nodemind/</code>, which makes the agent&rsquo;s memory a directory you can open and read. There is no database, no embedding call and no index build in the described path.</p>
<p>The one quantitative claim in that section is the author&rsquo;s: single-layer search is &ldquo;an order of magnitude faster than recursive multi-round LLM routing&rdquo;, and it does not dump a mass of documents into context at once. No method, dataset or measurement accompanies that statement, so it is carried here as an attributed claim and nothing more. No latency figure is published on this page as a result.</p>
<h2 id="the-single-writer-reflector">The single-writer Reflector</h2>
<p>A knowledge base that any component may write to eventually rots, and MyThinkNode&rsquo;s answer is a single writer: the Reflector is the tree&rsquo;s only write entry point. Mid-session the agent only queues tags; after the session the Reflector analyses the full tool logs and decides, per tag, whether to create, update or skip a node.</p>
<p><a href="https://raw.githubusercontent.com/wangztmw/mythinknode/main/src/nodemind/reflector.ts">src/nodemind/reflector.ts</a> shows the write path itself: the node object is assembled with <code>createdAt</code> preserved from any existing node, <code>updatedAt</code> refreshed, and attributes merged rather than replaced (<code>this._mergeAttrs(existing.attrs, attrs)</code>) before <code>this.store.upsertNode(node, parentId)</code> — wrapped in a <code>try/catch</code> that logs <code>[NodeMind] Reflector upsertNode failed:</code> instead of aborting the session.</p>
<p>The architectural benefit is that no write happens mid-session, so a bad mid-session write cannot restructure the tree while the agent is still navigating it; all mutations are batched and applied by one component that has seen the whole session. The honest limit: single-writer is design intent read from documentation and code. No concurrency fault injection, corruption stress test or test-suite run was performed for this review, so &ldquo;the tree stays clean&rdquo; is a structural argument, not a measured reliability result.</p>
<h2 id="pull-versus-push-why-the-memory-primitive-matters">Pull versus push: why the memory primitive matters</h2>
<p>The strongest argument in the project is a distinction about primitives. A vector store retrieves content: it finds the nearest chunk and hands it to the model, which then has to use whatever arrived. NodeMind retrieves location: it tells the model which node exists, and the model decides whether to open it. The model keeps authority over its own context window, and the memory stays inspectable because keywords and node ids are text.</p>
<p>The cost side is equally concrete. Vector retrieval needs no model reasoning to find a relevant chunk, while tree navigation spends tokens and decisions on every level, and it fails differently: a badly named node or a keyword set that does not match the question leaves the answer unreachable even though it was stored. That failure mode is a naming and curation failure, not a similarity-threshold failure, which is why the Reflector&rsquo;s judgement at write time carries most of the system&rsquo;s weight.</p>
<p>Structured non-vector memory is not unique to MyThinkNode — the comparison below includes a temporally aware knowledge graph and a graph-backed memory store — but a plain filesystem tree navigated by keywords is the far end of that spectrum.</p>
<h2 id="failures-over-successes-symptom--root-cause--fix">Failures over successes: Symptom → Root Cause → Fix</h2>
<p>The reflection prompt is documented to require failure routes: &ldquo;tried X, failed; Y, also failed; Z worked&rdquo; is described in the README as ten times more useful than &ldquo;Z worked&rdquo; alone, and each gotcha is persisted as a <strong>Symptom → Root Cause → Fix</strong> triple. The unit of memory is deliberately the debugging path rather than the outcome, on the reasoning that the model already knows what worked but loses why the alternatives failed.</p>
<p>That compression of a debugging session into three fields is portable to any agent memory design, and it is a design choice that does not depend on MyThinkNode at all. The &ldquo;ten times more useful&rdquo; comparison itself is the author&rsquo;s editorial framing, not a measured effect.</p>
<h2 id="delta-context-compression-only-persist-what-the-model-cannot-derive">Delta context compression: only persist what the model cannot derive</h2>
<p>Each session ends with <code>MessageProcessor</code> compressing the round&rsquo;s messages into a five-part summary — <code>GOAL → TIMELINE → FINDINGS → FILES → NUMBERS</code> — with the raw transcript written to <code>raws/S{n}.json</code> and the condensed version appended to context. <a href="https://raw.githubusercontent.com/wangztmw/mythinknode/main/src/session_loop.ts">src/session_loop.ts</a> is the pipeline file named in the README&rsquo;s tree listing.</p>
<p>The principle is delta compression: persist only what the model cannot reconstruct for itself from the codebase or from other stored notes. Filtering happens at write time rather than read time, which keeps the footprint small and future reads cheap, at the cost of lossy judgement — if the model misjudges what is derivable, the fact is simply gone. No before/after recall comparison was run here, so the accuracy of that judgement is untested on this page.</p>
<h2 id="the-cjk-rendering-war-story-seven-failed-attempts">The CJK rendering war story: seven failed attempts</h2>
<p>The README documents a terminal rendering bug in the project&rsquo;s own history: double-width CJK characters were truncated incorrectly, and the fix took seven failed attempts. The root cause is recorded as ANSI escape sequences being physically truncated across a line boundary, corrupting the state machine; the fix was not a patch afterwards but a rebuild from the rendering source, re-injecting the active ANSI SGR stack into continuation lines so formatting survives a wrap. The renderer is also width-adaptive: at 60 columns or more it overwrites in place with <code>\r</code>, and below 60 it suppresses intermediate tick frames to avoid <code>\r</code> plus ANSI wrap flooding the terminal.</p>
<p>This is a first-person account by the project author; the bug was not reproduced and the fix was not verified by execution here, so it is reported as source-verified narrative. Its value in a review is honesty about what &ldquo;minimal&rdquo; costs — a small dependency surface is not the same as simple engineering.</p>
<h2 id="production-grade-reliability-inside-a-minimal-agent">Production-grade reliability inside a &ldquo;minimal&rdquo; agent</h2>
<p>The README describes reliability behaviour that a minimal agent usually lacks, all attributed to <code>src/llm/retry.ts</code>: 10 retries on transient errors with permanent errors (DNS, authentication) failing immediately with an explicit message; exponential backoff with 25% jitter to avoid a thundering herd, preferring the server&rsquo;s <code>retry-after</code> header; <code>ECONNRESET</code> disabling keep-alive for the next request so a dead connection is not reused; and recognition of HTTP 529 / overloaded responses as worth retrying. Concurrency is managed with one semaphore shared by the main agent and all sub-agents (default 2), with overflow queued FIFO behind a 120-second timeout, explicitly to stop parallel agents from hammering the API into 429 responses.</p>
<p>These parameters were read from the project&rsquo;s documentation and file listing, not executed against a live rate-limited endpoint, so they are documented policy rather than observed behaviour. The pattern is still the useful part: the unglamorous retry, backoff and semaphore work is what separates a demo from something you can leave running.</p>
<h2 id="how-mythinknode-compares-to-clawmem-graphiti-memorybank-and-the-mcp-memory-pattern">How MyThinkNode compares to ClawMem, Graphiti, MemoryBank and the MCP memory pattern</h2>
<p>The memory tooling field has three common shapes, and MyThinkNode is a fourth. The rows below were read from each project&rsquo;s <a href="https://api.github.com/repos/wangztmw/mythinknode">repository API</a> on 2026-10-15; star and fork counts move daily and indicate attention, not quality.</p>
<table>
	<thead>
			<tr>
					<th>Project</th>
					<th>Language</th>
					<th>Stars</th>
					<th>Forks</th>
					<th>Memory approach</th>
					<th>Write model</th>
			</tr>
	</thead>
	<tbody>
			<tr>
					<td>MyThinkNode</td>
					<td>TypeScript (MIT)</td>
					<td>2</td>
					<td>0</td>
					<td>Filesystem keyword tree + knowledge DAG + session trace graph</td>
					<td>Single-writer Reflector, after the session</td>
			</tr>
			<tr>
					<td><a href="https://api.github.com/repos/yoloshii/ClawMem">ClawMem</a></td>
					<td>TypeScript (MIT)</td>
					<td>210</td>
					<td>38</td>
					<td>On-device hybrid RAG: SQLite + vectors + llama.cpp</td>
					<td>Hooks + MCP</td>
			</tr>
			<tr>
					<td><a href="https://api.github.com/repos/getzep/graphiti">Graphiti</a></td>
					<td>Python (Apache-2.0)</td>
					<td>31,785</td>
					<td>3,270</td>
					<td>Real-time temporal knowledge graph</td>
					<td>LLM-built graph</td>
			</tr>
			<tr>
					<td><a href="https://api.github.com/repos/feelingsonice/MemoryBank">MemoryBank</a></td>
					<td>Rust (MIT)</td>
					<td>36</td>
					<td>3</td>
					<td>Agentic memory using knowledge graphs</td>
					<td>Graph store</td>
			</tr>
			<tr>
					<td><a href="https://api.github.com/repos/usewire/wire-memory">wire-memory</a></td>
					<td>JavaScript (MIT)</td>
					<td>10</td>
					<td>3</td>
					<td>Persistent memory plugin capturing decisions and corrections</td>
					<td>Claude Code plugin</td>
			</tr>
			<tr>
					<td><a href="https://api.github.com/repos/moonx010/hive-memory">hive-memory</a></td>
					<td>TypeScript (MIT)</td>
					<td>8</td>
					<td>2</td>
					<td>Cross-project memory as an MCP server</td>
					<td>MCP server</td>
			</tr>
	</tbody>
</table>
<p>The table makes the trade legible. ClawMem is the dominant hybrid-RAG pattern — embeddings plus vector retrieval, local-first, embedded in the tool through hooks and MCP. wire-memory and hive-memory choose the MCP-server pattern, exposing memory as a protocol other agents can attach to. Graphiti and MemoryBank build graphs, one temporal and one agentic, with the graph as the retrieval structure.</p>
<p>MyThinkNode is different in two ways that matter operationally. It is native rather than a plugin or a sidecar service, so there is nothing to run next to the agent; and it is keyword-navigated rather than vector-retrieved, so memory inspection needs no special tooling — <code>cat</code> on a node file is the debugger. Against that, Graphiti&rsquo;s temporal edges answer &ldquo;what was true when&rdquo;, which a keyword tree does not model, and ClawMem&rsquo;s hybrid retrieval handles a large unstructured corpus that no hand-curated tree can.</p>
<h2 id="what-breaks-when-the-tree-grows">What breaks when the tree grows</h2>
<p>The reader problem asks what happens as a keyword tree accumulates. Four limits are visible from the sources alone.</p>
<p>First, retrieval quality becomes curation quality. Since search returns one layer of matches with <code>deeperIds</code> and <code>deeperHints</code>, a node whose keyword set does not name the reader&rsquo;s actual question is unreachable, and the only defence is the Reflector naming nodes well after the session. There is no similarity fallback.</p>
<p>Second, growth is unbounded in a way a vector index is not. Node ids, paths and keyword sets are the index, so every new node changes the navigation surface a model has to reason over, and nothing in the published files describes pruning, deduplication of near-identical nodes, or a capacity limit.</p>
<p>Third, the write path is a single component with no test coverage visible in the tree. <a href="https://raw.githubusercontent.com/wangztmw/mythinknode/main/src/nodemind/reflector.ts">src/nodemind/reflector.ts</a> already carries a fix for a malformed-title case from 1.0.0, which is evidence that node creation fails on real inputs; the failure is tolerated rather than prevented.</p>
<p>Fourth, the project itself is young and tiny: 2 stars, 0 forks, one author, a last push 49 days before this review, Chinese-only documentation, and three memory subsystems arriving in a single 1.0.0 release. Tool count rose from 13 to 16 in that release, which is the opposite of the &ldquo;minimal&rdquo; framing in the README.</p>
<h2 id="verdict-is-a-keyword-navigated-tree-worth-building-yourself">Verdict: is a keyword-navigated tree worth building yourself?</h2>
<p>Yes as a primitive, not yet as a dependency. If your constraint is &ldquo;no vector database and no hosted memory service&rdquo;, MyThinkNode is a working demonstration that a filesystem tree plus one disciplined writer carries cross-session experience, and the parts worth copying are the ones that do not require the project: a single writer that sees the whole session before persisting, failure routes stored as Symptom → Root Cause → Fix, write-time delta compression, and keywords as the navigation surface instead of embeddings.</p>
<p>Adopt it as a library and the risks are the ordinary early-stage ones. There is no test suite, no community, one author, and a documented node-creation failure mode already patched once. Every performance claim in the documentation is unattributed to a method, and a bounded search for third-party evaluation of this specific project returned only general agent-memory benchmark literature — no benchmark, review or academic evaluation of MyThinkNode itself.</p>
<p>The design question to answer honestly before choosing either primitive: does your agent need to recall <em>where</em> something is, or does it need the <em>content</em> now? A tree wins when memory is curated, structured and small, and when you want the model to stay in control of its context. A vector or graph store wins when the corpus is large, unstructured, or time-dependent — which is exactly the ground Graphiti&rsquo;s temporal graph and ClawMem&rsquo;s hybrid retrieval occupy. MyThinkNode is a well-argued case that vectorised answers are not the only primitive; it is not yet evidence that the tree wins at scale.</p>
]]></content:encoded></item></channel></rss>