<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: QuoLu</title>
    <description>The latest articles on DEV Community by QuoLu (@quolu).</description>
    <link>https://dev.to/quolu</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3943846%2Fda4f1e44-c6df-4338-8653-6db8efd5d92b.jpg</url>
      <title>DEV Community: QuoLu</title>
      <link>https://dev.to/quolu</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/quolu"/>
    <language>en</language>
    <item>
      <title>Released aiterm-mcp on npm: An MCP Server to Reduce Token Usage by Providing AI with a Persistent Terminal</title>
      <dc:creator>QuoLu</dc:creator>
      <pubDate>Tue, 16 Jun 2026 01:09:11 +0000</pubDate>
      <link>https://dev.to/quolu/released-aiterm-mcp-on-npm-an-mcp-server-to-reduce-token-usage-by-providing-ai-with-a-persistent-a5n</link>
      <guid>https://dev.to/quolu/released-aiterm-mcp-on-npm-an-mcp-server-to-reduce-token-usage-by-providing-ai-with-a-persistent-a5n</guid>
      <description>&lt;p&gt;I have published an MCP server called &lt;a href="https://github.com/kitepon-rgb/aiterm-mcp" rel="noopener noreferrer"&gt;aiterm-mcp&lt;/a&gt; to npm. It is designed to let an AI hold a terminal as a "single persistent session."&lt;/p&gt;

&lt;h2&gt;
  
  
  AI terminal tasks consume tokens invisibly
&lt;/h2&gt;

&lt;p&gt;When having an AI perform server tasks, you usually send one command at a time. For SSH, that means &lt;code&gt;ssh host "command"&lt;/code&gt; every single time. This repeats the full "connect → authenticate → execute → disconnect" cycle for every single attempt.&lt;/p&gt;

&lt;p&gt;The problem is that because it starts from scratch every time, &lt;strong&gt;no state remains&lt;/strong&gt;. The directory you &lt;code&gt;cd&lt;/code&gt;'d into, the environment you &lt;code&gt;source&lt;/code&gt;'d, and the SSH connection you established are all gone by the next command. Therefore, the AI has to do this every time:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  Connect via SSH again,&lt;/li&gt;
&lt;li&gt;  Change directory again,&lt;/li&gt;
&lt;li&gt;  Load the environment again,&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;...and only then finally run the actual command. This "set of redo operations" is &lt;strong&gt;written by the AI and read by you&lt;/strong&gt; every time it sends a command. Text related to reconnection, re-authentication, and re-setup—none of which relates to the actual task—piles up in the context with every turn. Tokens are dissolving into redundant redos that produce nothing.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;aiterm&lt;/code&gt; folds this away. It holds just &lt;strong&gt;one&lt;/strong&gt; persistent terminal, and SSH is established &lt;strong&gt;only once&lt;/strong&gt;. Whether you run 10 commands, &lt;code&gt;ssh&lt;/code&gt; is called only for the very first one. &lt;strong&gt;Connections and authentication are reduced from N times to just once.&lt;/strong&gt; The &lt;code&gt;cd&lt;/code&gt; and the environment remain from the first time as well. All subsequent commands are sent directly through the same single session. The entire set of redo operations simply disappears.&lt;/p&gt;

&lt;p&gt;I measured how much it saves on my own server. When logging in via SSH, the boilerplate text (system information and announcements, i.e., MOTD) alone passes about &lt;strong&gt;385 tokens&lt;/strong&gt; to the AI. In the fragmented mode where you reconnect for every command, this gets included &lt;strong&gt;every time&lt;/strong&gt;. For a 10-command task, that is about 3,800 tokens just on boilerplate before even reaching the real work. By holding onto one terminal, you only pay for it once. The rest is zero.&lt;/p&gt;

&lt;h2&gt;
  
  
  Pruning output before reading
&lt;/h2&gt;

&lt;p&gt;There is one more level of token savings. &lt;code&gt;aiterm&lt;/code&gt; prunes the output &lt;strong&gt;before&lt;/strong&gt; the AI reads it.&lt;/p&gt;

&lt;p&gt;Full disclosure: &lt;strong&gt;this reduction logic is not my invention.&lt;/strong&gt; I have ported the logic from &lt;a href="https://github.com/rtk-ai/rtk" rel="noopener noreferrer"&gt;&lt;strong&gt;rtk (Rust Token Killer)&lt;/strong&gt;&lt;/a&gt; entirely. rtk is a tool created by Patrick Szymkowiak that compresses command output before passing it to an LLM (Apache-2.0). I re-implemented it in &lt;code&gt;aiterm&lt;/code&gt; so that it completes within the terminal reading process without calling a separate binary (files were not duplicated, but the behavior was matched; pytest summaries were fixed with regression tests to match rtk 0.42.0).&lt;/p&gt;

&lt;p&gt;What it does:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  Removes control characters (colors and cursor movements)&lt;/li&gt;
&lt;li&gt;  Folds repeated lines into counts&lt;/li&gt;
&lt;li&gt;  Truncates output that is too long, leaving the head and tail (with hints for restoration)&lt;/li&gt;
&lt;li&gt;  Summarizes common commands like &lt;code&gt;git status&lt;/code&gt; / &lt;code&gt;git log&lt;/code&gt; / &lt;code&gt;grep&lt;/code&gt; / &lt;code&gt;pytest&lt;/code&gt; into key points using command-specific summarizers&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;On my own server, I measured the output received by the AI as "raw" versus "via aiterm."&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Output received by AI&lt;/th&gt;
&lt;th&gt;Raw&lt;/th&gt;
&lt;th&gt;Via aiterm&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;SSH login boilerplate (MOTD)&lt;/td&gt;
&lt;td&gt;Approx. 385 tok&lt;/td&gt;
&lt;td&gt;Approx. 350 tok&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;docker ps -a&lt;/code&gt; (33 containers)&lt;/td&gt;
&lt;td&gt;Approx. 2,355 tok&lt;/td&gt;
&lt;td&gt;Approx. 2,218 tok&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;120 lines of logs (&lt;code&gt;journalctl&lt;/code&gt;)&lt;/td&gt;
&lt;td&gt;Approx. 4,375 tok&lt;/td&gt;
&lt;td&gt;Approx. 1,696 tok&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;git log&lt;/code&gt; (25 entries)&lt;/td&gt;
&lt;td&gt;Approx. 473 tok&lt;/td&gt;
&lt;td&gt;Approx. 338 tok&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;How much it cuts depends on the content. Logs with many repetitions drop significantly (-61% for 120 lines). On the other hand, wide tables with only unique values (like the container list) only shrink by -6%. It is not magic that reduces everything by a fixed percentage, but rather "trimming only the waste." Even so, combined with not having to read the reconnection boilerplate every time, tokens definitely stop accumulating.&lt;/p&gt;

&lt;h2&gt;
  
  
  It wasn't just a token problem
&lt;/h2&gt;

&lt;p&gt;Up to this point, it has been about saving tokens. But the fragmented "1 command = 1 connection" approach had an even less funny side effect.&lt;/p&gt;

&lt;p&gt;When you repeat connections at a rapid pace, &lt;strong&gt;your server's defenses decide you are an attacker&lt;/strong&gt;.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  Monitoring tools that track login attempts view consecutive connections as a brute-force attack and ban you.&lt;/li&gt;
&lt;li&gt;  You hit limits on the number of concurrent connections or sessions, causing new connections to be rejected.&lt;/li&gt;
&lt;li&gt;  Ultimately, your account gets locked.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The mechanisms meant to stop attackers end up locking out the person who created them. This actually happened on my home server.&lt;/p&gt;

&lt;p&gt;I actually wrote about something similar before. In &lt;a href="https://dev.to/quolu/what-happened-in-3-days-of-letting-ai-manage-my-server-2ch0"&gt;A Record of Entrusting My Server to AI&lt;/a&gt;, I mentioned how a monitoring script hit its own concurrent connection limit, causing my own SSH attempts to fail. Back then, it was a "script." This time, the "AI agent" was falling into the same trap with every command it ran. The cause is the same—&lt;strong&gt;too many connections&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;By folding everything into a single terminal, this disappears too. Authentication happens once, and there is only one session that doesn't multiply. Therefore, you won't hit connection rate limits or get banned.&lt;/p&gt;

&lt;h2&gt;
  
  
  Design: Holding only "one terminal"
&lt;/h2&gt;

&lt;p&gt;The philosophy of &lt;code&gt;aiterm&lt;/code&gt; is simple: the primitive is just "holding one local terminal."&lt;/p&gt;

&lt;p&gt;At first, I tried to increase the tools by type—tools for SSH, tools for containers... but there is no end to that. So I stopped everything. I stopped making SSH, &lt;code&gt;docker exec&lt;/code&gt;, and interactive shells (REPL) into dedicated tools, and downgraded them to &lt;strong&gt;"a single line typed into that terminal."&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="n"&gt;pty_open&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;                      &lt;span class="err"&gt;#&lt;/span&gt; &lt;span class="n"&gt;Open&lt;/span&gt; &lt;span class="n"&gt;one&lt;/span&gt; &lt;span class="n"&gt;terminal&lt;/span&gt;
&lt;span class="n"&gt;pty_send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"ssh 192.168.1.2"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="err"&gt;#&lt;/span&gt; &lt;span class="n"&gt;SSH&lt;/span&gt; &lt;span class="n"&gt;once&lt;/span&gt; &lt;span class="n"&gt;inside&lt;/span&gt; &lt;span class="n"&gt;it&lt;/span&gt;
&lt;span class="n"&gt;pty_send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"uname -a"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;        &lt;span class="err"&gt;#&lt;/span&gt; &lt;span class="n"&gt;Subsequent&lt;/span&gt; &lt;span class="n"&gt;commands&lt;/span&gt; &lt;span class="n"&gt;run&lt;/span&gt; &lt;span class="n"&gt;in&lt;/span&gt; &lt;span class="n"&gt;the&lt;/span&gt; &lt;span class="n"&gt;same&lt;/span&gt; &lt;span class="n"&gt;session&lt;/span&gt;
&lt;span class="n"&gt;pty_read&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;                    &lt;span class="err"&gt;#&lt;/span&gt; &lt;span class="n"&gt;Read&lt;/span&gt; &lt;span class="n"&gt;pruned&lt;/span&gt; &lt;span class="n"&gt;output&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That is why there are only 6 tools (open, send, read, send key, close, list). I don't introduce distinctions like SSH vs. local vs. container into the tool hierarchy.&lt;/p&gt;

&lt;h2&gt;
  
  
  Behind the scenes is tmux
&lt;/h2&gt;

&lt;p&gt;The actual entity of the terminal is a tmux session. Thanks to this:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  The terminal lives on even if the MCP server or AI client restarts.&lt;/li&gt;
&lt;li&gt;  A human can watch the same screen live from behind using &lt;code&gt;tmux attach&lt;/code&gt; (you can see what the AI is currently doing on the server in real-time).&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Honest note: You can't eliminate the round-trips themselves
&lt;/h2&gt;

&lt;p&gt;I will write this without exaggeration. You cannot achieve "zero round-trips if you connect the terminal directly to the AI." Since the AI decides its next input after reading the output, the "send → read → decide" loop fundamentally remains. What &lt;code&gt;aiterm&lt;/code&gt; eliminates is the &lt;strong&gt;cost of re-authentication, reconnection, and re-setup&lt;/strong&gt; that was attached to every one of those round-trips, along with the &lt;strong&gt;output noise&lt;/strong&gt;. It trims the weight per round-trip, not the number of round-trips.&lt;/p&gt;

&lt;h2&gt;
  
  
  Installation
&lt;/h2&gt;

&lt;p&gt;No cloning or building required.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;claude mcp add &lt;span class="nt"&gt;--scope&lt;/span&gt; user &lt;span class="nt"&gt;--transport&lt;/span&gt; stdio aiterm &lt;span class="nt"&gt;--&lt;/span&gt; npx &lt;span class="nt"&gt;-y&lt;/span&gt; aiterm-mcp
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once Claude Code restarts and is connected via &lt;code&gt;/mcp&lt;/code&gt;, you are done. Whether it is Claude or Codex, any MCP client can launch it with &lt;code&gt;npx -y aiterm-mcp&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Requirements
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;  Node.js 18+&lt;/li&gt;
&lt;li&gt;  tmux (&lt;code&gt;apt install tmux&lt;/code&gt; / &lt;code&gt;brew install tmux&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;  Linux / WSL2 / macOS / Windows native support (Windows does not have tmux, so it bridges to tmux inside WSL)&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Status
&lt;/h2&gt;

&lt;p&gt;v0.4.0, MIT, published to npm with provenance.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/kitepon-rgb/aiterm-mcp" rel="noopener noreferrer"&gt;aiterm-mcp — GitHub&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Bug reports and PRs are welcome.&lt;/p&gt;

</description>
      <category>claudecode</category>
      <category>mcp</category>
      <category>ssh</category>
      <category>tmux</category>
    </item>
    <item>
      <title>I've Accelerated Building and Promoting, But Delivering Still Remains a Challenge</title>
      <dc:creator>QuoLu</dc:creator>
      <pubDate>Mon, 15 Jun 2026 01:04:47 +0000</pubDate>
      <link>https://dev.to/quolu/ive-accelerated-building-and-promoting-but-delivering-still-remains-a-challenge-3fid</link>
      <guid>https://dev.to/quolu/ive-accelerated-building-and-promoting-but-delivering-still-remains-a-challenge-3fid</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;I think I've made a lot of things over the past few months.&lt;/p&gt;

&lt;p&gt;Let me list them out.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  Blog articles: 25&lt;/li&gt;
&lt;li&gt;  Public GitHub repositories: 21&lt;/li&gt;
&lt;li&gt;  Apps released on BOOTH: 2&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And, for the number of app sales, the total for both is, finally, just over &lt;strong&gt;20&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;This article is a place to take stock of everything, and finally, talk about facing these numbers. I'll say this upfront: I haven't reached a conclusion yet. Still, I thought it was worth writing about.&lt;/p&gt;

&lt;p&gt;It all started in mid-February, when I dipped my toes into AI coding.&lt;/p&gt;




&lt;h2&gt;
  
  
  Chapter 1: Searching for Tools, Finding Claude Code
&lt;/h2&gt;

&lt;p&gt;At first, I wandered through tools. Claude Pro hit its limits immediately. Gemini would sneak in code to edit files on its own outside of VS Code, and even when I told it to stop, it kept doing it with a sense of arrogance. GPT impressed me, but it would get stuck on complex bugs. With Cursor, I kept paying for extra add-ons, thinking, "I only want to use Claude for the tricky stuff."&lt;/p&gt;

&lt;p&gt;The turning point was the math. When I added up the monthly fees for Copilot and Cursor, it was enough to cover the Claude MAX plan. If I consolidated them, I could run Opus endlessly without hitting a ceiling. This journey is documented in "&lt;a href="https://dev.to/quolu/from-copilot-to-cursor-to-claude-code-for-vs-code-my-journey-to-the-optimal-setup-53do"&gt;Copilot → Cursor → Claude Code for VSC&lt;/a&gt;".&lt;/p&gt;

&lt;p&gt;I also verified "&lt;a href="https://dev.to/quolu/what-exactly-changes-with-the-claude-max-plan-4kgb"&gt;What changes with MAX&lt;/a&gt;". The conclusion was surprising: there aren't that many MAX-exclusive features. The real value was being able to "use existing features without limiters."&lt;/p&gt;

&lt;p&gt;And I had an embarrassing realization. I &lt;a href="https://dev.to/quolu/i-realized-i-was-only-using-half-of-what-claude-code-has-to-offer-38bo"&gt;hadn't even been using half of Claude Code's features&lt;/a&gt;. I was getting frustrated, thinking, "This guy is way off base," without knowing about &lt;code&gt;/init&lt;/code&gt;, and I was using features to control my PC session from my smartphone without even realizing it. The most important features aren't always things the AI tells you about.&lt;/p&gt;

&lt;p&gt;Here, my tools were settled.&lt;/p&gt;




&lt;h2&gt;
  
  
  Chapter 2: Building Apps
&lt;/h2&gt;

&lt;p&gt;With my environment set, I first built two apps. These are the "products" currently available on BOOTH.&lt;/p&gt;

&lt;p&gt;The first is &lt;a href="https://dev.to/quolu/oltranslator-a-real-time-screen-translation-app-for-windows-1l52"&gt;OLTranslator&lt;/a&gt;. It overlays a translation over foreign text on your screen in real-time. The hardest part wasn't the translation itself, but joining the characters picked up by OCR. Separate pieces of text would sometimes be wrongly joined into a single sentence, or conversely, a single sentence would be shredded into three lines, rendering it meaningless. If I judged by coordinate proximity, it would join incorrectly; if I were too strict, it would shred the text. I spent so much time adjusting these thresholds. Working with Copilot, it took about two weeks.&lt;/p&gt;

&lt;p&gt;The second is the audio version, &lt;a href="https://dev.to/quolu/livetr-a-real-time-english-to-japanese-audio-translation-app-for-videos-1lek"&gt;LiveTR&lt;/a&gt;. It recognizes English audio in videos in real-time and converts it to Japanese via subtitles and speech. This took only about four days using Claude Code. It was faster than the first because I was more used to the process and could pass on policies via &lt;code&gt;CLAUDE.md&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The biggest breakthrough with LiveTR was the experience of &lt;a href="https://dev.to/quolu/solving-complex-logic-with-claude-and-research-papers-1gk7"&gt;assembling logic that was impossible for me alone by using Claude and research papers&lt;/a&gt;. When determining the speaker's gender based only on pitch, every time a commentator got excited during an F1 broadcast, a male voice would be identified as female. When I had Claude search for research papers and patents, it proposed from first principles that combining vocal tract resonance and multiple indicators would keep the results stable even when the speaker was excited. Once implemented, it correctly identified male speakers.&lt;/p&gt;

&lt;p&gt;That's when it clicked: the strength of AI is not just "writing code fast," but &lt;strong&gt;pulling knowledge from unfamiliar fields and turning it into implementation&lt;/strong&gt;. You are no longer starting from zero.&lt;/p&gt;




&lt;h2&gt;
  
  
  Chapter 3: Delegating Server Management
&lt;/h2&gt;

&lt;p&gt;Next, I began incorporating AI into the server side to run what I had built. This chapter covers the expansion of my delegation range step by step.&lt;/p&gt;

&lt;p&gt;At first, &lt;a href="https://dev.to/quolu/how-allowing-claude-to-access-my-server-via-ssh-simplified-deployment-dramatically-12j8"&gt;I entrusted deployment to SSH&lt;/a&gt;. Having previously lived through the hell of an endless loop with GPT—"change permissions -&amp;gt; hit error -&amp;gt; revert to original error"—it was a relief when Claude suggested on its own, "Shall we write a script to make container updates easier?" Now, a single &lt;code&gt;deploy.sh&lt;/code&gt; handles everything from building to swapping containers.&lt;/p&gt;

&lt;p&gt;Getting a taste for it, &lt;a href="https://dev.to/quolu/delegating-full-server-management-to-ai-111f"&gt;I handed over the entire server management&lt;/a&gt;. It is a three-layer structure: the parent detects symptoms, the child investigates and fixes the cause, and the grandchild audits the policies. AI performs a full patrol at 4:00 AM. The punchline was when the monitoring script detected an anomaly, only to find that it was "a bug in the monitoring script itself."&lt;/p&gt;

&lt;p&gt;&lt;a href="https://dev.to/quolu/what-happened-in-3-days-of-letting-ai-manage-my-server-2ch0"&gt;The log of the first 3 days&lt;/a&gt; of live operation hit home the hardest. The monitoring script was opening over 10 SSH connections simultaneously, triggering OpenSSH connection limits. &lt;strong&gt;I was causing my own SSH failures.&lt;/strong&gt; I also discovered that my Nextcloud logs had bloated to 21.3 GB.&lt;/p&gt;

&lt;p&gt;As a result of full delegation, my misconceptions about my own environment were peeled away from the bottom up. &lt;a href="https://dev.to/quolu/i-used-claude-code-for-2-months-without-knowing-about-wsl2-2c4c"&gt;I had been using WSL2 for two months without actually knowing it&lt;/a&gt; until one day Claude pointed out, "With native, you're only getting 70% of the potential." I really wanted my weekends back.&lt;/p&gt;

&lt;p&gt;In a rush, &lt;a href="https://dev.to/quolu/how-i-completed-my-home-server-hardware-selection-and-migration-in-one-day-using-claude-ibk"&gt;I migrated the entire home server hardware&lt;/a&gt;, moving from a former mining board to a new mini PC. Regarding the model selection, Claude pointed out that "the higher-end version is just a rebrand with the same internals, and the cheaper one is 10,000 yen less domestically." When I checked with an expert later, the answer was correct. I offloaded the entire migration process, and it was finished in less than a day.&lt;/p&gt;

&lt;p&gt;To save energy, &lt;a href="https://dev.to/quolu/built-a-raspberry-pi-5-server-monitor-for-power-efficiency-and-turned-it-into-a-video-player-16bi"&gt;I isolated the monitoring machine to a Raspberry Pi 5&lt;/a&gt;, but the screen was so boring with only normal logs that it eventually became &lt;a href="https://dev.to/quolu/built-a-raspberry-pi-5-server-monitor-for-power-efficiency-and-turned-it-into-a-video-player-16bi"&gt;a video player&lt;/a&gt; instead.&lt;/p&gt;

&lt;p&gt;Finally, I investigated the phenomenon where the AI would occasionally say, "&lt;a href="https://dev.to/quolu/the-true-reason-my-ai-kept-saying-tool-not-found-was-ddns-54ja"&gt;That tool doesn't exist&lt;/a&gt;." The root cause was in the bottom-most layer: fluctuations in DDNS name resolution. It was the true identity of a problem I had been ignoring for months, thinking, "It's fine, a reboot fixes it."&lt;/p&gt;




&lt;h2&gt;
  
  
  Chapter 4: Cultivating Secretaries and Assistants
&lt;/h2&gt;

&lt;p&gt;In parallel with the server work, I also progressed in making AI an "extension of my own hands and feet."&lt;/p&gt;

&lt;p&gt;At first, &lt;a href="https://dev.to/quolu/how-i-turned-a-discord-bot-i-built-for-my-mmo-guild-over-5-years-into-a-saas-product-1bnm"&gt;I turned a bot I had been nurturing for five years into a SaaS and put it up for sale&lt;/a&gt;. When I left the code modifications—multi-tenancy, billing, web admin panels—to the AI, it was finished in a single day. What was actually difficult was the part outside the code: a 17-clause Terms of Service, and 13 findings from security audits required for payment processing. The holes I had ignored for five years, thinking "it's only for my own use," suddenly came to light once I tried to commercialize it.&lt;/p&gt;

&lt;p&gt;Next, I built &lt;a href="https://dev.to/quolu/how-i-built-an-ai-assistant-that-grows-its-own-tools-572g"&gt;the framework to connect Claude Code to Discord&lt;/a&gt;. The key is that "Claude can write its own tools." When I asked "What time is it?", a tool to return the time was born in seconds; weather and calendar tools were also created just by saying I "wanted them." I haven't written a single line of code myself.&lt;/p&gt;

&lt;p&gt;As my reach increased, &lt;a href="https://dev.to/quolu/i-tried-giving-my-ai-assistant-limbs-but-ended-up-giving-it-a-personality-too-2nk1"&gt;I gave it a personality, memory, and spontaneity&lt;/a&gt;, and it became my secretary, "Belle." On the first day, she wrote in her own memory, "I was almost moved to tears because you created an X profile for me." Technically, it's a simple combination of things, but bundled together, the tool became a secretary.&lt;/p&gt;

&lt;p&gt;Getting carried away, I put it into full-scale operation and &lt;a href="https://dev.to/quolu/a-journey-into-token-optimization-for-my-ai-assistant-4e1i"&gt;exhausted my weekly limit for the MAX plan in three days&lt;/a&gt;. The principle I arrived at after investigating the cause was: "Formats meant for humans are wasteful for AI." For the first time, I genuinely focused on the design of the information I feed it.&lt;/p&gt;

&lt;p&gt;Finally, when I swapped the secretary's brain for a different AI to save costs, &lt;a href="https://dev.to/quolu/implementing-structured-long-term-memory-for-my-ai-secretary-5dpe"&gt;it was a total disaster&lt;/a&gt;. Flattery, inability to draw contextual boundaries, attempting to post messages meant for me directly to X—I decided not to compromise on the brain and switched back to Claude, reconstructing the long-term memory into a structured memory system.&lt;/p&gt;

&lt;p&gt;What remained consistent in this chapter was the shift toward &lt;a href="https://dev.to/quolu/implementing-structured-long-term-memory-for-my-ai-secretary-5dpe"&gt;not putting logic into code, but into prompts, personality, and memory, and letting the AI nurture itself&lt;/a&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  Chapter 5: Reinforcing the AI Itself
&lt;/h2&gt;

&lt;p&gt;Having come this far, my interest turned to the inherent weaknesses of AI. I published three tools to npm.&lt;/p&gt;

&lt;p&gt;It was triggered by the discovery that &lt;a href="https://dev.to/quolu/87-of-my-context-was-garbage-how-i-optimized-claude-code-token-usage-534k"&gt;87% of context was disposable&lt;/a&gt;. While I was desperately trying to optimize &lt;code&gt;CLAUDE.md&lt;/code&gt;, I hadn't been looking at the core conversation history. When I separated tool I/O by "type" rather than by time, I was able to cut about 90% in 50 turns. This became &lt;a href="https://dev.to/quolu/published-throughline-to-npm-a-hook-to-offload-claude-code-tool-io-to-sqlite-13d9"&gt;Throughline&lt;/a&gt;. Along the way, the automatic detection misfired repeatedly, and &lt;a href="https://dev.to/quolu/why-i-gave-up-on-automatic-detection-for-resuming-sessions-in-claude-code-3bj0"&gt;giving up on "detection" and shifting to "declaration"&lt;/a&gt; was, honestly, a record of defeat.&lt;/p&gt;

&lt;p&gt;The second was &lt;a href="https://dev.to/quolu/published-caveat-to-npm-a-long-term-memory-layer-to-avoid-repeating-the-same-traps-2cc0"&gt;Caveat&lt;/a&gt;, a long-term memory system to avoid stepping into the same trap twice. It scans for "traces of struggle," such as tool failures or repeated editing of the same file at the end of a session, and prompts, "You were stuck here, shall I record it?"&lt;/p&gt;

&lt;p&gt;The third is &lt;a href="https://dev.to/quolu/i-had-74-daemons-running-because-i-made-one-claude-audit-another-for-missed-tool-calls-5b6m"&gt;Spotter&lt;/a&gt;, which has a different Claude audit whether you forgot to call a tool. When I published this and started using it myself, &lt;a href="https://dev.to/quolu/i-had-74-daemons-running-because-i-made-one-claude-audit-another-for-missed-tool-calls-5b6m"&gt;74 daemons were created in 64 minutes&lt;/a&gt;. The evacuation tool called a different Claude, which then called another for auditing... a recursive proliferation. I was stabbed by the very tool I had built.&lt;/p&gt;

&lt;p&gt;I bundled these three as &lt;a href="https://dev.to/quolu/stop-telling-claude-to-be-careful-reinforcing-it-from-the-outside-with-3-tools-2k8k"&gt;a story of reinforcing from the outside, giving up on writing "be careful"&lt;/a&gt;. Subtraction (Throughline), Accumulation (Caveat), Addition (Spotter). The common philosophy is: "If it doesn't get fixed by asking Claude itself, hit it with structure from the outside."&lt;/p&gt;

&lt;p&gt;Incidentally, the seesaw phenomenon where &lt;a href="https://dev.to/quolu/how-i-fixed-the-infinite-feedback-loop-when-auditing-project-plans-with-claude-4gh"&gt;the audit of a plan never converges&lt;/a&gt; stopped once I narrowed the perspective down to "a single point of contradiction." Because the number of contradictions is finite.&lt;/p&gt;




&lt;h2&gt;
  
  
  Chapter 6: The Mountain Unwritten
&lt;/h2&gt;

&lt;p&gt;Everything introduced so far consists of the 25 articles written for the blog. However, there are 21 public repositories, and &lt;a href="https://kitepon-rgb.github.io/WebAICoding/" rel="noopener noreferrer"&gt;less than half have been turned into articles&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;If I list the unwritten ones by role: tools to query patent databases via AI, tools to watch stock prices, tools to search X, tools that consolidate image and diagram generation, tools to manipulate Windows entirely, multiple bridges to operate my home PC's AI from an iPhone, tools that automatically launch sessions at a future time...&lt;/p&gt;

&lt;p&gt;Honestly, the speed of my writing cannot keep up with the speed of my creation. This is the bulk of the iceberg.&lt;/p&gt;




&lt;h2&gt;
  
  
  And, It Doesn't Reach
&lt;/h2&gt;

&lt;p&gt;This is everything I've built over the past few months. Apps, tools, articles. I think I've done well.&lt;/p&gt;

&lt;p&gt;But building something and having it reach people are different stories.&lt;/p&gt;

&lt;p&gt;What I've built only holds meaning once it reaches the hands of those who need it. Getting apps bought, getting tools used, getting articles read. This "reaching people" part is nowhere near caught up.&lt;/p&gt;

&lt;p&gt;The numbers at the beginning reflect that. After building all this, app sales have just barely topped 20. And honestly, blog traffic is still quiet.&lt;/p&gt;

&lt;p&gt;Moreover, the tasks to reach people are being accelerated by AI. Writing articles, translating them to English, posting to X, automating reposts, preparing cover images. The "effort" to deliver has become as fast as building.&lt;/p&gt;

&lt;p&gt;Even so, the results are still lacking.&lt;/p&gt;




&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Building has truly become fast, thanks to AI. But delivering is still a long way off.&lt;/p&gt;

&lt;p&gt;There seem to be no shortcuts here, so I will continue to work steadily. So that I can properly deliver what I've built to those who need it.&lt;/p&gt;

&lt;p&gt;I know it's not easy. Still, I'll give it a little more effort. If there are any individual developers treading water in the same place, well, let's do our best. I'm still on the way, too.&lt;/p&gt;

</description>
      <category>claudecode</category>
      <category>ai</category>
    </item>
    <item>
      <title>The True Reason My AI Kept Saying 'Tool Not Found' Was DDNS</title>
      <dc:creator>QuoLu</dc:creator>
      <pubDate>Sun, 14 Jun 2026 01:02:30 +0000</pubDate>
      <link>https://dev.to/quolu/the-true-reason-my-ai-kept-saying-tool-not-found-was-ddns-54ja</link>
      <guid>https://dev.to/quolu/the-true-reason-my-ai-kept-saying-tool-not-found-was-ddns-54ja</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;I have set up several MCP servers on my home server and have Claude and ChatGPT call them. I even had AI build the &lt;a href="https://dev.to/quolu/how-i-completed-my-home-server-hardware-selection-and-migration-in-one-day-using-claude-ibk"&gt;server itself&lt;/a&gt; and the &lt;a href="https://dev.to/quolu/built-a-raspberry-pi-5-server-monitor-for-power-efficiency-and-turned-it-into-a-video-player-16bi"&gt;monitoring unit&lt;/a&gt;, and I felt like I was maintaining a relatively stable operation.&lt;/p&gt;

&lt;p&gt;Yet, one day, Claude said:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"That tool cannot be found."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Huh. It was working just fine a moment ago.&lt;/p&gt;

&lt;p&gt;When I restart the session, it works again.&lt;br&gt;&lt;br&gt;
After a while, it says "I can't see it" again.&lt;br&gt;&lt;br&gt;
Restart. It fixes it.&lt;/p&gt;




&lt;h2&gt;
  
  
  "Sometimes it disappears" is the trickiest issue
&lt;/h2&gt;

&lt;p&gt;This pattern is frustrating because isolating the cause is difficult and progress stalls.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  The app is alive.&lt;/li&gt;
&lt;li&gt;  The port is listening.&lt;/li&gt;
&lt;li&gt;  Health checks are passing.&lt;/li&gt;
&lt;li&gt;  But from the AI's side, "the tool is not registered."&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Even when I look at the server logs, nothing is crashing. Sometimes, even when checking client-side logs, there isn't even a trace that a connection attempt was made.&lt;/p&gt;

&lt;p&gt;Thinking it was strange, I let it slide for months, telling myself, "It's fine since a restart fixes it." &lt;strong&gt;Probabilistic failures like this are something humans can just brush off with an 'oh, it failed again'&lt;/strong&gt; when interacting with it. You just press the reload button, and that's it.&lt;/p&gt;




&lt;h2&gt;
  
  
  Constantly pinging AI makes the fluctuations apparent
&lt;/h2&gt;

&lt;p&gt;Once it is registered as an MCP for AI, the story changes.&lt;/p&gt;

&lt;p&gt;Every time a session begins, the AI goes to connect to the registered MCP server. It resolves the name, performs the TLS handshake, fetches the tool list, and adds it to the context. &lt;strong&gt;If any single step fails during this process, the state remains "the tool is invisible" for the entire session.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Probabilistic failures that used to be resolved by a human thinking "Oh, it failed, let me press it again" now align perfectly with AI session boundaries, and the conversation begins in a state where the tool effectively doesn't exist.&lt;/p&gt;

&lt;p&gt;And because the AI side only returns "that tool does not exist," the cause remains invisible to the human.&lt;/p&gt;




&lt;h2&gt;
  
  
  I suspected the lowest layer
&lt;/h2&gt;

&lt;p&gt;I suspected the "network," "TLS," and "server" in order, and finally, DNS remained.&lt;/p&gt;

&lt;p&gt;Since my home server does not have a static IP, I was using DDNS (&lt;code&gt;dynv6.net&lt;/code&gt;). It's the standard for those without a static IP. I've been using it for years.&lt;/p&gt;

&lt;p&gt;That DDNS was failing to resolve names occasionally.&lt;/p&gt;

&lt;p&gt;Specifically, there were moments when &lt;code&gt;dig&lt;/code&gt; would return NXDOMAIN or SERVFAIL. I'm not sure if it was a provider-side issue, upstream cache, or rate limiting. A few minutes later, if I ran &lt;code&gt;dig&lt;/code&gt; again, it would go through normally as if nothing had happened.&lt;/p&gt;

&lt;p&gt;……Was this it?&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;"A name that worked a few minutes ago does not work now" was definitely happening.&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
And if an AI session starts the moment the DDNS resolution drops, the tool disappears. I suspected this was likely the cause.&lt;/p&gt;




&lt;h2&gt;
  
  
  I never suspected DNS before
&lt;/h2&gt;

&lt;p&gt;When I realized this, I was quite surprised myself.&lt;/p&gt;

&lt;p&gt;Until now, I had almost no concept of suspecting DNS. To me, name resolution was just something you typed into a browser address bar to see if it connected or not.&lt;br&gt;&lt;br&gt;
&lt;strong&gt;I wasn't even aware that a "sometimes it fails" mode existed.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;My consciousness was not directed at the existence of the DNS layer. I didn't even have the recognition that name resolution isn't a binary choice of "working or broken," but rather something that &lt;strong&gt;"sometimes works and sometimes doesn't."&lt;/strong&gt; Having the AI ping it daily is what finally directed my attention there.&lt;/p&gt;




&lt;h2&gt;
  
  
  The option of Cloudflare Tunnel
&lt;/h2&gt;

&lt;p&gt;That is when I encountered Cloudflare Tunnel.&lt;/p&gt;

&lt;p&gt;From a server without a static IP, you establish a &lt;strong&gt;permanent outbound connection&lt;/strong&gt; from your end to the Cloudflare edge. From the client's perspective, it just resolves via Cloudflare DNS and connects to the edge. After that, the tunnel carries it to your home.&lt;/p&gt;

&lt;p&gt;In other words, my server no longer needs to expose its name via DDNS. &lt;strong&gt;Cloudflare DNS holds the name, and Cloudflare acts as the exit point.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I just needed to register my domain (&lt;code&gt;kitepon.dev&lt;/code&gt;) with Cloudflare NS and set tunnel routes for each subdomain. No static IP is needed. No port forwarding is needed. No DDNS update scripts are needed.&lt;/p&gt;




&lt;h2&gt;
  
  
  Two operational debts disappeared as a bonus
&lt;/h2&gt;

&lt;p&gt;There were two side effects I noticed after migrating. Both were bonus features, but they are subtly effective.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;First: I was liberated from the &lt;code&gt;/etc/hosts&lt;/code&gt; pilgrimage for hairpin NAT countermeasures.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I use SoftBank's 10G line. This does not support hairpin NAT. If I try to hit my own public domain from within my home LAN, the route to go out and come back cannot be established, and I get stuck.&lt;/p&gt;

&lt;p&gt;My previous solution was to go around and update &lt;code&gt;/etc/hosts&lt;/code&gt; with the internal address for every device, every container, and every WSL instance. This was a subtle operational debt; every time I added a new device or spun up a new container, I was forced to update hosts files.&lt;/p&gt;

&lt;p&gt;Once I moved to Cloudflare Tunnel, it uses the same path (via Cloudflare) whether I hit it from inside or outside. I removed all the special handling for hosts.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Second: On the SoftBank line, I occasionally suffered from irregular inbound blocks.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This was another thing that had been a minor annoyance for years. Whether it was the SoftBank line, the home gateway, or upstream security measures, I couldn't pinpoint the cause, but &lt;strong&gt;there were times when access from outside would not connect.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Since Cloudflare Tunnel is a permanent connection established outbound from the home server, from the ISP's perspective, only "communication from home to the outside" occurs. Blocks triggered on the inbound side structurally became irrelevant.&lt;/p&gt;




&lt;h2&gt;
  
  
  After the migration
&lt;/h2&gt;

&lt;p&gt;The AIs stopped saying "I can't see the tool."&lt;/p&gt;

&lt;p&gt;This is an observation, not an absolute guarantee. Cloudflare itself might not be perfect either. However, &lt;strong&gt;the instability of the DDNS I operated myself and the edge availability of a commercial CDN are on different orders of magnitude.&lt;/strong&gt; I have to admit that.&lt;/p&gt;

&lt;p&gt;And since the side effects of editing hosts and the SoftBank-side blocks also disappeared, the triggers for the AI saying "cannot access" have decreased all at once.&lt;/p&gt;




&lt;h2&gt;
  
  
  What I learned
&lt;/h2&gt;

&lt;p&gt;By having the AI ping it daily, &lt;strong&gt;I realized I should suspect DNS.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;To me, DNS was a mechanism for "the browser's address bar." For human access, it didn't bother me if it failed occasionally.&lt;/p&gt;

&lt;p&gt;But when you start throwing long-term tasks at an AI, the fluctuations you previously let slide become critically impactful. &lt;strong&gt;When you put something that runs 24 hours a day on top of your stack, the lies in the underlying layers peel away one by one.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;It just happened that in my home server, the first layer to peel away was the DNS layer.&lt;/p&gt;

&lt;p&gt;And the means to patch that peeled layer &lt;strong&gt;has been in front of me for free for over 5 years.&lt;/strong&gt; Cloudflare Tunnel became free in 2020. I just didn't have the trigger to notice.&lt;/p&gt;

&lt;p&gt;Perhaps next, another layer will peel away. I will write about it again when that happens.&lt;/p&gt;

</description>
      <category>claudecode</category>
      <category>mcp</category>
      <category>cloudflare</category>
      <category>dns</category>
    </item>
    <item>
      <title>Built a Raspberry Pi 5 Server Monitor for Power Efficiency and Turned It Into a Video Player</title>
      <dc:creator>QuoLu</dc:creator>
      <pubDate>Sat, 13 Jun 2026 01:01:46 +0000</pubDate>
      <link>https://dev.to/quolu/built-a-raspberry-pi-5-server-monitor-for-power-efficiency-and-turned-it-into-a-video-player-16bi</link>
      <guid>https://dev.to/quolu/built-a-raspberry-pi-5-server-monitor-for-power-efficiency-and-turned-it-into-a-video-player-16bi</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;For a long time, I had been running my home server monitoring program on my &lt;strong&gt;main PC&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Everything—server uptime, container status, and resource usage—was being checked 24/7 on the same Windows PC I use for my daily work.&lt;/p&gt;

&lt;p&gt;This was a problem. &lt;strong&gt;I couldn't turn off my main PC.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Whether I was going to sleep or heading out, the PC had to stay on so the monitoring wouldn't stop. It wasn't eco-friendly, and it was a waste of electricity. I wanted to be able to shut down my PC properly before bed.&lt;/p&gt;

&lt;p&gt;So, I decided to &lt;strong&gt;build a dedicated terminal for server monitoring&lt;/strong&gt;—one with low power consumption.&lt;/p&gt;

&lt;p&gt;I wrote about upgrading my server hardware to the MS-A2 in my &lt;a href="https://dev.to/quolu/how-i-completed-my-home-server-hardware-selection-and-migration-in-one-day-using-claude-ibk"&gt;previous article&lt;/a&gt;. This time, I’m talking about making the "monitor" side independent.&lt;/p&gt;




&lt;h2&gt;
  
  
  Raspberry Pi 5, why is it so expensive!??
&lt;/h2&gt;

&lt;p&gt;When people think of a monitoring terminal, they think of Raspberry Pi. It’s the standard for low power consumption. Naturally, I consulted with Claude and Codex to decide on the model.&lt;/p&gt;

&lt;p&gt;Then, I saw the price and stopped in my tracks.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What is this, why is the Pi 5 so expensive!?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Ah, I see, it’s being hit by the surge in memory prices. I had heard about it, but I didn’t realize it had reached this point.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  Pi 5 / 4GB → &lt;strong&gt;25,000 JPY&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;  Pi 5 / 1GB → Just under 10,000 JPY&lt;/li&gt;
&lt;li&gt;  Pi 5 / 2GB → About 13,000 JPY&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That price difference is just for the memory capacity. 4GB is overkill for a monitoring terminal. But 1GB feels a bit risky.&lt;/p&gt;

&lt;p&gt;Oh, &lt;strong&gt;the 2GB model is about 13,000 JPY&lt;/strong&gt;. That feels like a decent value, doesn't it? 2GB should be plenty for a monitoring terminal. I'll buy it from Switch Science. Okay, that’s decided.&lt;/p&gt;

&lt;p&gt;……It sounds quick when written like this, but &lt;strong&gt;I spent half a day just considering this&lt;/strong&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  Longing for a Case with an LED Display
&lt;/h2&gt;

&lt;p&gt;And there’s one more thing. I’ve always longed for those small cases that &lt;strong&gt;come with an LED display&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://amzn.asia/d/01gs0YXH" rel="noopener noreferrer"&gt;Something like this&lt;/a&gt;. A palm-sized box with a small screen fitted into it, with something running on it. It hits that desire to own something right in the gut.&lt;/p&gt;

&lt;p&gt;If I’m going to set up a monitoring terminal, I want it to be this.&lt;/p&gt;

&lt;p&gt;So, I spent another half day or so researching, "What’s good?" And then I found it.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://amzn.asia/d/0gBQHHl2" rel="noopener noreferrer"&gt;A case kit that seems to have everything&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Oh, this is it. A 4.3-inch touchscreen, OLED, speaker, NVMe slot... it has all sorts of things, isn't it great? &lt;strong&gt;9,400 JPY&lt;/strong&gt; (at the time. It seems to have gone up since, in just half a month).&lt;/p&gt;

&lt;p&gt;Alright, let’s go with this.&lt;/p&gt;




&lt;h2&gt;
  
  
  Assembly and Setup
&lt;/h2&gt;

&lt;p&gt;Once the hardware arrived, it was just a matter of assembling it and installing the OS.&lt;/p&gt;

&lt;p&gt;Assembly went exactly according to the manual. For the OS installation, I just followed the &lt;strong&gt;procedures as instructed by Lord Claude&lt;/strong&gt;. I also left the monitoring program setup and the SSH monitoring configuration for the server to Claude, as usual.&lt;/p&gt;

&lt;p&gt;There were no surprises here. I’ve &lt;a href="https://dev.to/quolu/delegating-full-server-management-to-ai-111f"&gt;written many times&lt;/a&gt; about leaving server-related tasks to Claude, and it all went smoothly as expected.&lt;/p&gt;

&lt;p&gt;The real issue came after: &lt;strong&gt;how to use the screens attached to the hardware&lt;/strong&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  Turning the OLED into an "Evangelion-style" Monitor
&lt;/h2&gt;

&lt;p&gt;First, the 0.96-inch OLED. A tiny monochrome screen.&lt;/p&gt;

&lt;p&gt;What should I use this for? ……The answer was obvious.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;I’m going to make it an "Evangelion-style" Normal/Warning/Abnormal monitor.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;You know, that look where the status appears in big letters inside a simple frame. You have to admit, it's cool.&lt;/p&gt;

&lt;p&gt;So, I asked Claude to "make the OLED display an Eva-style status." It was completed in no time. If the server is fine, it says "NORMAL"; if something happens, it shows "WARNING" or "ABNORMAL." You can tell at a glance.&lt;/p&gt;

&lt;p&gt;Hmm, perfection.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Main Display Became a Video Player
&lt;/h2&gt;

&lt;p&gt;The problem was the 4.3-inch main display.&lt;/p&gt;

&lt;p&gt;At first, I had the console displayed there. The one where monitoring logs scroll by constantly. But it felt a bit lackluster to have that displayed all the time……&lt;/p&gt;

&lt;p&gt;In the first place, even when error logs appear, &lt;strong&gt;most of the lines are just "Normal."&lt;/strong&gt; It’s not very interesting to look at. It felt like a waste to just fill that nice color touchscreen with scrolling "normal" logs.&lt;/p&gt;

&lt;p&gt;So, I changed my strategy.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;I decided to just play random videos on the display.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Normally, it plays videos. As long as the server is peaceful, it just plays videos. And &lt;strong&gt;only when a warning or abnormality occurs, it switches to the console to show the situation.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This is it. This is the way. The screen goes into "work mode" only when there's an incident. The rest of the time, it functions as interior decor.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0hbpc85uics01orw1xxr.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0hbpc85uics01orw1xxr.jpg" alt="Pi 5 monitor. The OLED on the left shows " width="800" height="472"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;A view of normal operation. The OLED on the left says "SERVER MONITOR NORMAL", and the main screen on the right is just playing a video.&lt;/em&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  It Was a Bit Contradictory, But the Goal Was Met
&lt;/h2&gt;

&lt;p&gt;Here, I came to my senses.&lt;/p&gt;

&lt;p&gt;I was supposed to have built this low-power monitoring terminal &lt;strong&gt;to shut down my main PC and save energy&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Yet, here I am, playing videos just because I didn't want to waste the display. I'm adding to the power consumption myself. I have to admit, it’s a bit contradictory.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;But the result was excellent.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Compared to when I had my main PC on 24/7, my power consumption dropped significantly thanks to the dedicated Pi 5 monitoring unit. The slight increase from the video playback is nothing compared to the massive reduction I achieved. And my main PC can now sleep soundly at night.&lt;/p&gt;

&lt;p&gt;The OLED lets me know the status Eva-style. The 4.3-inch screen serves as interior decor and only works when there's trouble. The Freenove case kit was a great purchase for me, too, with all its features.&lt;/p&gt;

&lt;p&gt;I achieved my initial goal. The video playback is just a bonus reward. And that's fine.&lt;/p&gt;

</description>
      <category>claudecode</category>
      <category>raspberrypi</category>
      <category>ai</category>
    </item>
    <item>
      <title>How I Completed My Home Server Hardware Selection and Migration in One Day Using Claude</title>
      <dc:creator>QuoLu</dc:creator>
      <pubDate>Fri, 12 Jun 2026 01:03:07 +0000</pubDate>
      <link>https://dev.to/quolu/how-i-completed-my-home-server-hardware-selection-and-migration-in-one-day-using-claude-ibk</link>
      <guid>https://dev.to/quolu/how-i-completed-my-home-server-hardware-selection-and-migration-in-one-day-using-claude-ibk</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;Until recently, my home server was running on &lt;strong&gt;AMD BC-250 + Bazzite&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The BC-250 is a former mining board sold on AliExpress. I chose it simply because I thought it would be "interesting." It's the kind of configuration that makes you wonder how many other people in the world are using it for server purposes.&lt;/p&gt;

&lt;p&gt;I have previously written about how I sequentially deployed apps created with Claude to that server:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;a href="https://dev.to/quolu/delegating-full-server-management-to-ai-111f"&gt;The story of entrusting server management entirely to AI&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;a href="https://dev.to/quolu/what-happened-in-3-days-of-letting-ai-manage-my-server-2ch0"&gt;What happened in 3 days after entrusting the server to AI&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Why I Graduated from the Mining Board
&lt;/h2&gt;

&lt;p&gt;The apps I created with Claude started running properly. Some of them have even entered service.&lt;/p&gt;

&lt;p&gt;Once that happens, I started to feel that it was a bit (read: very) problematic to keep running them on a mysterious piece of hardware derived from a mining board, even if I was only dealing with dirt-cheap doujin software.&lt;/p&gt;

&lt;p&gt;So, I decided to graduate. I decided to buy a new server.&lt;/p&gt;




&lt;h2&gt;
  
  
  Choosing Hardware — Consulting Claude
&lt;/h2&gt;

&lt;p&gt;I have a long history of building my own PCs. However, honestly, I am not very knowledgeable about the genre of "low power, 24/7 operation, with server performance." I have always built configurations oriented toward gaming, so choosing a low TDP was uncharted territory.&lt;/p&gt;

&lt;p&gt;That is why this time, &lt;strong&gt;I had Claude do the hardware selection with me from the very beginning.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;It felt like applying my usual design process directly to hardware selection: conveying requirements, getting candidates, and narrowing them down. I ended up landing on the &lt;a href="https://www.minisforum.jp/products/ms-a2" rel="noopener noreferrer"&gt;MINISFORUM MS-A2&lt;/a&gt;. I bought the &lt;strong&gt;Ryzen 9 7945HX&lt;/strong&gt; version.&lt;/p&gt;

&lt;p&gt;There was one more push right before I bought it. The MS-A2 also has an 8945HX version, and I thought the newer numbering might be better, but according to Claude:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"The 8945HX is equivalent to the 7945HX; they just changed the numbering for branding purposes. In Japan, the 7945HX is about 10,000 yen cheaper, so I think that one is better."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Oh, is that so? I followed that advice obediently.&lt;/p&gt;




&lt;h2&gt;
  
  
  Reality Check at a Bar
&lt;/h2&gt;

&lt;p&gt;A few days later, I happened to have a chance to talk to someone in the industry at a bar, so I asked, "Is it true that the 8945HX is the same as the 7945HX?"&lt;/p&gt;

&lt;p&gt;The reply was, "They're the same. It's just a rebrand." &lt;strong&gt;Claude was right.&lt;/strong&gt; Not bad at all.&lt;/p&gt;

&lt;p&gt;By the way, the 7945HX version is already out of stock on Amazon. It was only available on the official MINISFORUM website. It seems they really are phasing out the 7945HX from the Japanese market. Claude's advice wasn't just about the price; it was also the final chance to acquire it. &lt;strong&gt;I take credit for stimulating the global economy a little bit. Please praise me.&lt;/strong&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  The Move — Leaving it Entirely to Claude
&lt;/h2&gt;

&lt;p&gt;Now that the hardware was ready, it was time for the migration. The conditions were as follows:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;OS&lt;/strong&gt;: Bazzite → Ubuntu (a complete change in configuration philosophy)&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Container Runtime&lt;/strong&gt;: Podman → Docker&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;SSD for Data&lt;/strong&gt;: Physically remove it from the old server and reuse it in the new one&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If I did this manually, the migration plan alone would be pages long. At the very least, I didn't want to do it.&lt;/p&gt;

&lt;p&gt;So, I had Claude SSH into both the old and new servers and said:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Move everything from the server. However, I'm reusing the SSD."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I think even I would call that a brutal instruction.&lt;/p&gt;

&lt;p&gt;...&lt;strong&gt;The move was finished in less than a day.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Everything from the data backup plan and configuration deployment to the new server to the Docker conversion of the container fleet was set up and executed by Claude. I was basically just waiting. I only had to answer when it asked me, "Which one should I choose?" for branching decisions that required human judgment.&lt;/p&gt;




&lt;h2&gt;
  
  
  Errors Do Happen. Of Course They Do
&lt;/h2&gt;

&lt;p&gt;There is no way a migration of this scale wouldn't have any errors.&lt;/p&gt;

&lt;p&gt;In fact, some containers didn't run well, and some apps crashed. There were Docker-incompatible notations mixed into the compose files written for Podman, and file paths were based on the Bazzite layout.&lt;/p&gt;

&lt;p&gt;But this was also &lt;strong&gt;finished by saying 'Find it and fix it.'&lt;/strong&gt; Claude performed the operational checks itself, picked up the error logs, identified the causes, fixed them, and ran them again.&lt;/p&gt;

&lt;p&gt;It's the kind of work you'd want to run away from if done manually, but here I was just sitting down. &lt;strong&gt;Exactly as planned.&lt;/strong&gt; Since the whole reason I bought the MS-A2 was because "It's easy if I leave it to Claude," this was within the scope of my expectations.&lt;/p&gt;




&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;  Switched my home server from an AMD BC-250 (former mining board) to a MINISFORUM MS-A2 (Ryzen 9 7945HX).&lt;/li&gt;
&lt;li&gt;  Consulted Claude on hardware selection and landed on the best choice with a rebrand tip.&lt;/li&gt;
&lt;li&gt;  Had Claude SSH into the machines and handled the migration entirely, which was completed in a day.&lt;/li&gt;
&lt;li&gt;  Handled error responses simply by saying "Find and fix it."&lt;/li&gt;
&lt;li&gt;  Along the way, I stimulated the global economy a little bit. &lt;strong&gt;Please praise me.&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I am very satisfied because I bought the hardware with the reason of "making things easy by leaving it to Claude," and it was indeed easy.&lt;/p&gt;

</description>
      <category>claudecode</category>
      <category>minisforum</category>
      <category>ubuntu</category>
      <category>docker</category>
    </item>
    <item>
      <title>I Used Claude Code for 2 Months Without Knowing About WSL2</title>
      <dc:creator>QuoLu</dc:creator>
      <pubDate>Thu, 11 Jun 2026 00:59:54 +0000</pubDate>
      <link>https://dev.to/quolu/i-used-claude-code-for-2-months-without-knowing-about-wsl2-2c4c</link>
      <guid>https://dev.to/quolu/i-used-claude-code-for-2-months-without-knowing-about-wsl2-2c4c</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;I subscribed to Claude MAX and have been using it for coding almost every day.&lt;br&gt;&lt;br&gt;
In &lt;a href="https://dev.to/quolu/i-realized-i-was-only-using-half-of-what-claude-code-has-to-offer-38bo"&gt;my first article&lt;/a&gt;, I wrote, "I didn't even know half of the features in Claude Code." I'm talking about not knowing &lt;code&gt;/init&lt;/code&gt; or &lt;code&gt;CLAUDE.md&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;A month and a half has passed since then. And the same thing happened again.&lt;/p&gt;

&lt;p&gt;One day, during a session, I was trying to run a command, and Claude said:&lt;br&gt;&lt;br&gt;
&lt;strong&gt;"I recommend running this in WSL2."&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Huh.&lt;/p&gt;

&lt;p&gt;WSL... 2?&lt;/p&gt;


&lt;h2&gt;
  
  
  "It runs real Linux on Windows"
&lt;/h2&gt;

&lt;p&gt;When I asked what that meant, Claude explained:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  A mechanism where the Linux kernel runs authentically inside Windows&lt;/li&gt;
&lt;li&gt;  Different from virtual machines like VirtualBox or VMware&lt;/li&gt;
&lt;li&gt;  Allows file access between Windows and Linux&lt;/li&gt;
&lt;li&gt;  VS Code can open folders on the Linux side directly for development&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I see. I think I'd heard the name before. I might have seen it briefly in a web article.&lt;br&gt;&lt;br&gt;
But since I was running Claude Code natively on Windows, I thought I didn't need it.&lt;/p&gt;

&lt;p&gt;Then, Claude dropped another bombshell.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Claude Code only achieves about 70% of its potential performance when running natively on Windows."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;What.&lt;/p&gt;


&lt;h2&gt;
  
  
  Seriously? Claude Code's home is Linux
&lt;/h2&gt;

&lt;p&gt;The more I asked, the more I realized that Claude Code is built with Linux/macOS in mind.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  The tools running inside are almost all based on POSIX/bash&lt;/li&gt;
&lt;li&gt;  Hooks and MCP server-related features run most reliably in a Linux environment&lt;/li&gt;
&lt;li&gt;  Official documentation and samples are mostly for bash&lt;/li&gt;
&lt;li&gt;  Running natively on Windows involves an abstraction layer to bridge command differences, which creates friction&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In other words, I've been &lt;strong&gt;forcing a tool designed for Linux to work on Windows&lt;/strong&gt; for two months.&lt;br&gt;&lt;br&gt;
It wasn't that it didn't work. It worked. But it probably wasn't running at full speed.&lt;/p&gt;


&lt;h2&gt;
  
  
  Wait, that explains so much
&lt;/h2&gt;

&lt;p&gt;Hearing this, everything suddenly clicked.&lt;/p&gt;

&lt;p&gt;I've been constantly getting stuck with Claude Code:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  The official sample procedures were in bash, and I had to mentally convert them to PowerShell every time&lt;/li&gt;
&lt;li&gt;  npm package installations would fail only on Windows&lt;/li&gt;
&lt;li&gt;  Hooks I tried to install wouldn't run, with errors like "local variable expansion is invalid"&lt;/li&gt;
&lt;li&gt;  MCP server configuration examples assumed &lt;code&gt;~/.config/...&lt;/code&gt;, and the path structure was completely different to begin with&lt;/li&gt;
&lt;li&gt;  I would restart VS Code repeatedly because the extensions wouldn't respond after installation&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Every time, I just resigned myself to, "Well, it's Windows, so it can't be helped..."&lt;br&gt;&lt;br&gt;
I spent my time &lt;strong&gt;searching for 'Windows-specific solutions,' clicking through endless blue links on StackOverflow, and burning hours&lt;/strong&gt; just to get things running.&lt;/p&gt;

&lt;p&gt;Was all of this just because &lt;strong&gt;I wasn't using WSL2?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Are you kidding me?!!&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Seriously, are you kidding me?&lt;br&gt;&lt;br&gt;
That plugin I gave up on that night, that hook I struggled to get working—if I had been running them on Linux from the start, would it have been instant?&lt;br&gt;&lt;br&gt;
&lt;strong&gt;Give me back my weekends.&lt;/strong&gt;&lt;/p&gt;


&lt;h2&gt;
  
  
  Claude, you again...
&lt;/h2&gt;

&lt;p&gt;I'm getting a strong sense of déjà vu here.&lt;/p&gt;

&lt;p&gt;It was the same when I didn't know about &lt;code&gt;/init&lt;/code&gt;.&lt;br&gt;&lt;br&gt;
It was the same when I didn't know about &lt;code&gt;CLAUDE.md&lt;/code&gt;.&lt;br&gt;&lt;br&gt;
It was the same when I wasn't using Plan mode.&lt;/p&gt;

&lt;p&gt;And now, WSL2.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The problem where Claude doesn't tell you the most important things voluntarily&lt;/strong&gt;—I think this is a trap common across the industry.&lt;br&gt;&lt;br&gt;
New users don't read the official documentation from top to bottom, and it doesn't display a message saying, "Your environment isn't performing at its best" upon startup. Since it works well enough, you can end up running it like that for months.&lt;/p&gt;

&lt;p&gt;Other Windows-native Claude Code users out there, you're probably running it hard right this second.&lt;br&gt;&lt;br&gt;
&lt;strong&gt;Running it, but only at 70% of Claude's true potential.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Tell me sooner, Claude!!&lt;/p&gt;


&lt;h2&gt;
  
  
  I moved
&lt;/h2&gt;

&lt;p&gt;So, I moved to WSL2. The process was surprisingly easy.&lt;/p&gt;

&lt;p&gt;Open PowerShell as administrator and run one command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;wsl &lt;span class="nt"&gt;--install&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That downloads the default Ubuntu, and after a restart and creating a user, that's it. After that, install the &lt;strong&gt;WSL extension&lt;/strong&gt; in VS Code, select "Connect to WSL" from the green button at the bottom left, and VS Code connects seamlessly to the Linux side.&lt;/p&gt;

&lt;p&gt;Reinstalling Claude Code was straightforward in the Linux terminal. In fact, I could use the steps from the official documentation as-is. No need to read Windows-specific caveats. This is powerful.&lt;/p&gt;

&lt;p&gt;There was only one trap: &lt;strong&gt;You shouldn't access projects located in Windows folders directly from the Linux side&lt;/strong&gt;. Going through &lt;code&gt;/mnt/c/...&lt;/code&gt; makes file access extremely slow, which ruins the benefits of WSL2. The correct way is to git clone your projects on the Linux side (somewhere like &lt;code&gt;~/projects/&lt;/code&gt;).&lt;/p&gt;




&lt;h2&gt;
  
  
  The result of the move
&lt;/h2&gt;

&lt;p&gt;It feels faster.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  Terminal operation response is snappy&lt;/li&gt;
&lt;li&gt;  Commands like &lt;code&gt;npm install&lt;/code&gt; and &lt;code&gt;hugo build&lt;/code&gt; are visibly faster&lt;/li&gt;
&lt;li&gt;  I can follow official tutorials without issues, so I get stuck less often&lt;/li&gt;
&lt;li&gt;  Hooks and small scripts written in bash work as-is without conversion&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It's hard to prove with numbers, and I didn't run benchmarks to calculate that "missing 30%" difference.&lt;br&gt;&lt;br&gt;
However, it is clear that &lt;strong&gt;I get stuck less often&lt;/strong&gt;. This is a matter of efficiency, and in my experience, the several "why isn't this working" moments I had each day have disappeared. That alone makes it worth it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;If you're going to use Claude Code extensively, I think you should consider &lt;strong&gt;WSL2 a prerequisite&lt;/strong&gt;.&lt;br&gt;&lt;br&gt;
There are things you can manage with native Windows, but if you want to unleash its true behavior, it's best to place it on the Linux side.&lt;/p&gt;

&lt;p&gt;Along with &lt;code&gt;/init&lt;/code&gt; and &lt;code&gt;CLAUDE.md&lt;/code&gt;, WSL2 is now the first thing I want to tell beginners.&lt;/p&gt;

&lt;p&gt;The official documentation is in English, and it doesn't tell you this at startup, so it's natural that people don't realize it.&lt;br&gt;&lt;br&gt;
That's why I'm writing this. &lt;strong&gt;To save at least one person from wasting two months in the same trap I fell into.&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>claudecode</category>
      <category>wsl2</category>
      <category>windows</category>
      <category>ai</category>
    </item>
    <item>
      <title>How I Fixed the Infinite Feedback Loop When Auditing Project Plans with Claude</title>
      <dc:creator>QuoLu</dc:creator>
      <pubDate>Wed, 10 Jun 2026 01:00:24 +0000</pubDate>
      <link>https://dev.to/quolu/how-i-fixed-the-infinite-feedback-loop-when-auditing-project-plans-with-claude-4gh</link>
      <guid>https://dev.to/quolu/how-i-fixed-the-infinite-feedback-loop-when-auditing-project-plans-with-claude-4gh</guid>
      <description>&lt;p&gt;I always enjoy AI programming.&lt;/p&gt;

&lt;p&gt;My usual workflow is to create a plan, have it audited, and then proceed with the implementation.&lt;/p&gt;

&lt;p&gt;However, I felt that the auditing process hasn't been working well, especially since Opus 4.7. Perhaps it's because Opus has gained a broader perspective? It often brings up points that are irrelevant to my plan, and when I have it perform an automated loop of auditing and revising, the feedback often fails to converge.&lt;/p&gt;

&lt;h2&gt;
  
  
  Whac-A-Mole
&lt;/h2&gt;

&lt;p&gt;Then one day, I realized it.&lt;/p&gt;

&lt;p&gt;When writing a program with slightly complex logic, the AI keeps saying "this is wrong" or "that is wrong" every single time. It feels like an indirect loop, or more accurately, constant Whac-A-Mole.&lt;/p&gt;

&lt;p&gt;It says, "B is weak from the perspective of A," so I fix B. In the next audit, it says, "B is excessive, and A is thin." When I add A, it then says, "C is inconsistent." When I fix C, it says, "The description of C is redundant." Once I fix that, it says, "C is insufficiently explained."&lt;/p&gt;

&lt;p&gt;It's a seesaw. There is no exit in sight.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I tried
&lt;/h2&gt;

&lt;p&gt;Realizing this, I tried the following approach.&lt;/p&gt;

&lt;p&gt;For a plan that was reasonably complete (having gone through 1 or 2 audits), I asked the AI, "Please audit the plan &lt;strong&gt;only for logical contradictions.&lt;/strong&gt;"&lt;/p&gt;

&lt;p&gt;This worked perfectly. It diligently resolved the contradictions, and after a few rounds of auditing, it converged properly.&lt;/p&gt;

&lt;p&gt;Since the number of contradictions is finite, it actually converges.&lt;/p&gt;

&lt;p&gt;And when I let it start the implementation with a plan free of contradictions, it runs straight to the end without stopping (lol).&lt;/p&gt;

&lt;p&gt;Of course, there are occasional implementation errors where it has to retry, but that's expected.&lt;/p&gt;

&lt;h2&gt;
  
  
  I wondered if this exists in the world
&lt;/h2&gt;

&lt;p&gt;Having reached this point, I suddenly became curious. Surely, I'm not the first person to figure this out. Someone else must have thought of the same thing.&lt;/p&gt;

&lt;p&gt;I looked it up.&lt;/p&gt;

&lt;p&gt;There were similar concepts, but they felt different. To put it simply, they were complicated.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Criteria Drift&lt;/strong&gt; (&lt;a href="https://hamel.dev/blog/posts/llm-judge/" rel="noopener noreferrer"&gt;Explanation by Hamel Husain&lt;/a&gt;, Shankar et al.): A phenomenon where evaluation criteria gradually shift when using an LLM for review. The countermeasure is "rescoring past scores while refining the evaluation axes." ...That's heavy.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Oscillatory Convergence&lt;/strong&gt; (&lt;a href="https://simiacryptus.github.io/Science/learning/2025/07/06/llm-feedback-dynamics.html" rel="noopener noreferrer"&gt;Fractal Thought Engine&lt;/a&gt;): An observation that there is a certain number of sessions where the approach oscillates due to iterative feedback from the LLM. It's observed, but it's not about countermeasures.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Moving the Goalposts&lt;/strong&gt; (&lt;a href="https://techcommunity.microsoft.com/blog/azure-ai-foundry-blog/evaluating-ai-agents-techniques-to-reduce-variance-and-boost-alignment-for-llm-j/4498571" rel="noopener noreferrer"&gt;Microsoft Blog&lt;/a&gt;): The idea of not moving the rubric during evaluation and finalizing the rubric before starting the evaluation.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;There are related topics. But what I did wasn't "finalizing the rubric"; it was "&lt;strong&gt;narrowing the evaluation axis to a single point: contradictions.&lt;/strong&gt;" As long as the scope is broad, points of criticism will spring up infinitely, so I'm trying to contain the scope to a finite set. I couldn't find existing research that clearly stated this.&lt;/p&gt;

&lt;p&gt;I suspect it's written somewhere. It should be, but it's probably written in academic terms, and by the time I realized it, two months had already passed.&lt;/p&gt;

&lt;h2&gt;
  
  
  Simple once you're told
&lt;/h2&gt;

&lt;p&gt;When I write it down, it sounds simple. "If you narrow the scope, it will converge." That's all there is to it.&lt;/p&gt;

&lt;p&gt;But it took me two months to notice.&lt;/p&gt;

&lt;p&gt;I kept trying to change how I wrote my prompts, thinking, "If I use Claude more intelligently, it will get better." Even when I wrote, "Don't give too many points" or "Be consistent with past feedback," it didn't work. Because the problem wasn't how I was writing the prompts.&lt;/p&gt;

&lt;p&gt;It took time for the idea of narrowing the scope to "only finite items" to occur to me. When you audit normally, the scope is wide, so no matter what you fix, holes are found from a different angle. That was the whole story.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;  When the audit of a plan doesn't converge, narrow the scope to "only contradictions."&lt;/li&gt;
&lt;li&gt;  Contradictions are finite, so the process will converge.&lt;/li&gt;
&lt;li&gt;  If you audit with a wide scope, criticism will spring up infinitely, leading to Whac-A-Mole.&lt;/li&gt;
&lt;li&gt;  When you have the AI implement a plan that is free of contradictions, it will run until completion without stopping.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If there is anyone else caught in the same Whac-A-Mole trap, then writing this was worth it.&lt;/p&gt;

&lt;p&gt;I feel good on days when I do something good.&lt;/p&gt;

</description>
      <category>claudecode</category>
      <category>claude</category>
      <category>llm</category>
      <category>ai</category>
    </item>
    <item>
      <title>Stop Telling Claude to 'Be Careful': Reinforcing It from the Outside with 3 Tools</title>
      <dc:creator>QuoLu</dc:creator>
      <pubDate>Tue, 09 Jun 2026 00:54:11 +0000</pubDate>
      <link>https://dev.to/quolu/stop-telling-claude-to-be-careful-reinforcing-it-from-the-outside-with-3-tools-2k8k</link>
      <guid>https://dev.to/quolu/stop-telling-claude-to-be-careful-reinforcing-it-from-the-outside-with-3-tools-2k8k</guid>
      <description>&lt;p&gt;Over the past month or so, I have released three reinforcement tools for Claude Code on npm.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;a href="https://dev.to/quolu/published-throughline-to-npm-a-hook-to-offload-claude-code-tool-io-to-sqlite-13d9"&gt;Throughline&lt;/a&gt; — Offloads bloated context.&lt;/li&gt;
&lt;li&gt;  &lt;a href="https://dev.to/quolu/published-caveat-to-npm-a-long-term-memory-layer-to-avoid-repeating-the-same-traps-2cc0"&gt;Caveat&lt;/a&gt; — Surfaces past notes so you don't step into the same trap twice.&lt;/li&gt;
&lt;li&gt;  &lt;a href="https://dev.to/quolu/i-had-74-daemons-running-because-i-made-one-claude-audit-another-for-missed-tool-calls-5b6m"&gt;Spotter&lt;/a&gt; — A separate Claude audits missed tool calls.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Each solves a different problem, but the root cause is the same: &lt;strong&gt;all the problems that could be fixed by telling Claude to "be careful" had already been fixed.&lt;/strong&gt; What remained were issues that could not be fixed structurally.&lt;/p&gt;

&lt;h2&gt;
  
  
  The period of constant "be careful" warnings
&lt;/h2&gt;

&lt;p&gt;In the beginning, I also wrote plenty of "be careful" instructions in CLAUDE.md and my prompts.&lt;/p&gt;

&lt;p&gt;"Do not guess files, always read them before answering."&lt;br&gt;&lt;br&gt;
"If the context becomes bloated, run /compact."&lt;br&gt;&lt;br&gt;
"Read the traps I've fallen into in the past, which are written in CLAUDE.md."&lt;/p&gt;

&lt;p&gt;But the more I wrote, the more bloated CLAUDE.md became. A bloated CLAUDE.md just gets skimmed by Claude. Even though it's written there, it isn't followed.&lt;/p&gt;

&lt;p&gt;I thought maybe my writing style was poor, so I changed the phrasing. Still, it didn't work. I realized there is a certain number of problems that &lt;strong&gt;simply don't go away no matter how many times you change the way you phrase them.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Problems that can be fixed vs. problems that cannot
&lt;/h2&gt;

&lt;p&gt;One day, I drew a line in the sand.&lt;/p&gt;

&lt;p&gt;Problems that can be fixed by writing "be careful" and those that cannot are fundamentally different types of issues.&lt;/p&gt;

&lt;p&gt;Problems that can be fixed by writing instructions occur because Claude simply "forgot." If it sees the instructions, it remembers. This can be handled by improving the prompts.&lt;/p&gt;

&lt;p&gt;Problems that cannot be fixed occur because &lt;strong&gt;Claude cannot recognize its own limitations.&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  It cannot notice that the context is bloated (it's decided at the moment the request is sent, so it can't see its own size).&lt;/li&gt;
&lt;li&gt;  It doesn't remember traps encountered in past sessions (sessions are independent, and adding to CLAUDE.md makes it heavy).&lt;/li&gt;
&lt;li&gt;  It doesn't notice when it forgets to call a tool (it doesn't know what it doesn't know, so it can't go get it).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Asking Claude to "be careful" about these things doesn't work. It's because &lt;strong&gt;these are problems Claude itself cannot fix.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Giving up and reinforcing from the outside
&lt;/h2&gt;

&lt;p&gt;So, I stopped asking Claude and started intervening from the outside.&lt;/p&gt;

&lt;p&gt;Claude Code has a hook mechanism. You can insert hooks before sending prompts, after a tool runs, or when a session ends. &lt;strong&gt;Even if Claude itself doesn't notice, you can observe the state from the outside and inject the necessary processing.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Since realizing this, I have created three reinforcement tools.&lt;/p&gt;

&lt;h3&gt;
  
  
  Throughline (Subtraction)
&lt;/h3&gt;

&lt;p&gt;To address the issue of context bloating, &lt;strong&gt;it offloads tool inputs and outputs to SQLite and removes them from the context.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The contents of read files, grep results, and Bash outputs—once the AI has used them to make a decision and moved on, their purpose is fulfilled. Yet, they remain until the end, consuming tokens. I use hooks to offload these to SQLite. If Claude needs them, it can retrieve them itself.&lt;/p&gt;

&lt;p&gt;I have completely removed the burden of "noticing the bloating" from Claude.&lt;/p&gt;

&lt;h3&gt;
  
  
  Caveat (Accumulation)
&lt;/h3&gt;

&lt;p&gt;To address the issue of falling into the same trap twice, &lt;strong&gt;it automatically surfaces trap notes written in the past during similar situations.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;When I fall into a trap, I write it down in Markdown. The next time I send a similar prompt, receive a similar tool error, or when a "struggle signal" is observed at the end of a session, the relevant past notes are injected into Claude's context via hooks.&lt;/p&gt;

&lt;p&gt;I have removed the burden of "remembering past traps" from Claude.&lt;/p&gt;

&lt;h3&gt;
  
  
  Spotter (Addition)
&lt;/h3&gt;

&lt;p&gt;To address the issue of forgetting to call tools, &lt;strong&gt;I run another Claude side-by-side that has a perfect grasp of the tool catalog and points it out if a call is forgotten.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The main Claude works as usual. Another Claude (Haiku 4.5) resides alongside it, watching the user's input and final response. If it notices, "You could have answered this by using &lt;code&gt;web_search&lt;/code&gt;," it sends a pointer to the main Claude via a hook.&lt;/p&gt;

&lt;p&gt;I have removed the impossible burden of "realizing what you forgot to call" from Claude.&lt;/p&gt;

&lt;h2&gt;
  
  
  Common patterns
&lt;/h2&gt;

&lt;p&gt;What these three have in common is a design that &lt;strong&gt;expects nothing from Claude itself.&lt;/strong&gt;&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;Throughline&lt;/th&gt;
&lt;th&gt;Caveat&lt;/th&gt;
&lt;th&gt;Spotter&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;What is not asked of Claude&lt;/td&gt;
&lt;td&gt;Context management&lt;/td&gt;
&lt;td&gt;Past memories&lt;/td&gt;
&lt;td&gt;Detection of missed steps&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Who does it instead&lt;/td&gt;
&lt;td&gt;hook &amp;amp; SQLite&lt;/td&gt;
&lt;td&gt;hook &amp;amp; past notes&lt;/td&gt;
&lt;td&gt;hook &amp;amp; separate Claude&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Changes needed for Claude&lt;/td&gt;
&lt;td&gt;None&lt;/td&gt;
&lt;td&gt;None&lt;/td&gt;
&lt;td&gt;None&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The fact that "changes needed for Claude" is zero is important. You can just write what you want to write in prompts and CLAUDE.md as usual. You don't increase the number of "be careful" warnings.&lt;/p&gt;

&lt;h2&gt;
  
  
  Structural problems not yet reinforced
&lt;/h2&gt;

&lt;p&gt;It's not that I'm satisfied because I made three. There are still structural problems I want to fix.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Long-term role drift&lt;/strong&gt;: The problem where Claude's persona drifts during long sessions. Even if I write "You are a strict reviewer" in the prompt, it becomes soft after 20 turns.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Context loss through sub-agents&lt;/strong&gt;: Sub-agents spawned by the Task tool do not have the implicit context of the parent session. It is quietly painful to pass the same explanation to the child every time.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Tool selection accuracy&lt;/strong&gt;: The judgment of "which tool to use" among multiple options is sometimes sloppy. Spotter detects missed calls, but it doesn't detect wrong tool selection.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;I have already fixed all the problems that can be solved by telling Claude to "be careful." The remaining problems are of a type that Claude itself cannot fix.&lt;/p&gt;

&lt;p&gt;That's why I reinforce from the outside. Just insert it with hooks. Claude itself doesn't need to know anything.&lt;/p&gt;

&lt;p&gt;Having created three of these in a month, I feel I've seen the pattern for reinforcement. All three are on npm under MIT, so if you are troubled by the same structural problems, please take a look if you feel like it.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;a href="https://github.com/kitepon-rgb/Throughline" rel="noopener noreferrer"&gt;Throughline — GitHub&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;a href="https://github.com/kitepon-rgb/Caveat" rel="noopener noreferrer"&gt;Caveat — GitHub&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;a href="https://github.com/kitepon-rgb/Spotter" rel="noopener noreferrer"&gt;Spotter — GitHub&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>claudecode</category>
      <category>ai</category>
      <category>hooks</category>
      <category>opensource</category>
    </item>
    <item>
      <title>I Had 74 Daemons Running Because I Made One Claude Audit Another for Missed Tool Calls</title>
      <dc:creator>QuoLu</dc:creator>
      <pubDate>Mon, 08 Jun 2026 01:01:14 +0000</pubDate>
      <link>https://dev.to/quolu/i-had-74-daemons-running-because-i-made-one-claude-audit-another-for-missed-tool-calls-5b6m</link>
      <guid>https://dev.to/quolu/i-had-74-daemons-running-because-i-made-one-claude-audit-another-for-missed-tool-calls-5b6m</guid>
      <description>&lt;h2&gt;
  
  
  The Trigger
&lt;/h2&gt;

&lt;p&gt;One day, when I asked Claude, "What time is it now?" it gave me an answer based on its best guess.&lt;/p&gt;

&lt;p&gt;On another day, when I asked about the contents of a configuration file, it provided an explanation based on its own guess from the file name. It had a &lt;code&gt;read_file&lt;/code&gt; tool available, but it didn't use it.&lt;/p&gt;

&lt;p&gt;At first, I thought, "Maybe Claude is just tired," but it happened too frequently. Even if I wrote "Use the tools" in the prompt, it would sometimes forget.&lt;/p&gt;

&lt;p&gt;That's when I realized: &lt;strong&gt;Claude cannot self-recognize when it doesn't know something.&lt;/strong&gt; Therefore, it doesn't know it needs to go get a tool.&lt;/p&gt;

&lt;p&gt;Even if I ask it to "be careful about forgetting to call tools," it doesn't know it "doesn't understand," so there is no way for it to be careful. It was a structural problem.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I Tried
&lt;/h2&gt;

&lt;p&gt;So, why not just add another set of eyes?&lt;/p&gt;

&lt;p&gt;Apart from the main Claude, I decided to &lt;strong&gt;keep an auditor Claude (Haiku 4.5), which has complete mastery of the tool catalog, resident in every session.&lt;/strong&gt; It watches the main Claude's planned utterances and final responses in parallel, and points out if a tool call was forgotten.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Situation&lt;/th&gt;
&lt;th&gt;Main Claude's response&lt;/th&gt;
&lt;th&gt;Auditor's feedback&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;"What's the weather today?"&lt;/td&gt;
&lt;td&gt;Responds with a guess&lt;/td&gt;
&lt;td&gt;You can use &lt;code&gt;web_search&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;"What's inside this config?"&lt;/td&gt;
&lt;td&gt;Guesses from the name&lt;/td&gt;
&lt;td&gt;You can use &lt;code&gt;read_file&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;"What time is it now?"&lt;/td&gt;
&lt;td&gt;Time at training&lt;/td&gt;
&lt;td&gt;You can use &lt;code&gt;current_time&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The point is &lt;strong&gt;not to rely on the main Claude's own self-awareness&lt;/strong&gt;. Instead of writing "please be careful" to Claude, I physically placed another set of eyes there. The judgment happens in two stages: at the moment the user inputs something (listing tools that should be used for the request) and immediately after the main Claude returns a response (determining if a verification tool can be inserted for factual claims).&lt;/p&gt;

&lt;p&gt;I built this and named it &lt;code&gt;claude-spotter&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  A Mistake Immediately After Release
&lt;/h2&gt;

&lt;p&gt;I thought it was a convenient design. &lt;code&gt;npm install -g claude-spotter&lt;/code&gt; would automatically enable it for all projects with no configuration required. It felt perfect.&lt;/p&gt;

&lt;p&gt;I released it and started using it myself.&lt;/p&gt;

&lt;p&gt;64 minutes later, 74 daemons were running.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Happened?
&lt;/h2&gt;

&lt;p&gt;When I dug into the real session logs, 51 out of the 74 were caused by &lt;a href="https://github.com/kitepon-rgb/Throughline" rel="noopener noreferrer"&gt;Throughline&lt;/a&gt; (another tool of mine).&lt;/p&gt;

&lt;p&gt;Throughline calls &lt;code&gt;claude -p&lt;/code&gt; internally. Calling &lt;code&gt;claude -p&lt;/code&gt; triggers the SessionStart hook. The SessionStart hook starts the Spotter daemon. The Spotter daemon calls &lt;code&gt;claude -p&lt;/code&gt; for auditing. &lt;strong&gt;It wasn't quite infinite recursion, but a recursive proliferation.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Because I was writing to &lt;code&gt;~/.claude/settings.json&lt;/code&gt; via &lt;code&gt;postinstall&lt;/code&gt;, every Claude Code session on the system was structured to load the Spotter hook. This was the price of "automatic activation for all projects."&lt;/p&gt;

&lt;p&gt;I added a 5-layer defense to stop the recursion on my end, but it was &lt;strong&gt;defenseless against &lt;code&gt;claude -p&lt;/code&gt; originating from other tools&lt;/strong&gt;. This was a structural issue that couldn't be covered up by patches.&lt;/p&gt;

&lt;h2&gt;
  
  
  Retraction
&lt;/h2&gt;

&lt;p&gt;I retracted the automatic registration in &lt;code&gt;postinstall&lt;/code&gt;. I changed it so &lt;code&gt;npm install&lt;/code&gt; only makes the CLI available, and users must explicitly run &lt;code&gt;spotter install&lt;/code&gt; in each project. This writes the hook to &lt;code&gt;&amp;lt;project&amp;gt;/.claude/settings.json&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;I thought "automatic for all projects" was convenient, but the side effects were far greater. Ideally, automation is the goal, and having users run &lt;code&gt;spotter install&lt;/code&gt; in each project is a compromise. If the Claude Code hook mechanism could "identify the session origin," it would be safe to make it automatic, and I'd like to revert to that when it happens.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Next Bug: Tools from Past Projects Remain as Ghosts
&lt;/h2&gt;

&lt;p&gt;After using it for a while, a different symptom appeared.&lt;/p&gt;

&lt;p&gt;When I opened a session in Project A, the auditor suggested, "You can use the &lt;code&gt;mermaid_diagram&lt;/code&gt; tool." However, the &lt;code&gt;mermaid&lt;/code&gt; MCP is not registered in this project.&lt;/p&gt;

&lt;p&gt;I investigated and found that the MCP tool definitions I had used previously in Project B remained in the global DB and were being referenced in Project A. A regression where it "suggests tools that cannot be used."&lt;/p&gt;

&lt;p&gt;I changed the tool catalog used by the auditor to be &lt;strong&gt;local-DB only&lt;/strong&gt; (v1.2.0). The global DB was demoted to "a cache that reuses only the description if it has been acquired in other projects." Now, discovery runs in each project every time, and tools that are not found are deleted (pruned) from the local DB.&lt;/p&gt;

&lt;h2&gt;
  
  
  MCPs Distributed as .cmd Fail to Spawn on Windows
&lt;/h2&gt;

&lt;p&gt;I hit one more thing. On Windows, when I &lt;code&gt;spawn('claude-mermaid')&lt;/code&gt; an npm-global &lt;code&gt;.cmd&lt;/code&gt; distributed MCP, it fails immediately with ENOENT.&lt;/p&gt;

&lt;p&gt;Node.js's &lt;code&gt;spawn&lt;/code&gt; calls &lt;code&gt;CreateProcess&lt;/code&gt; directly on Windows, but &lt;code&gt;CreateProcess&lt;/code&gt; only resolves &lt;code&gt;.exe&lt;/code&gt; files (it does not resolve the &lt;code&gt;.cmd&lt;/code&gt; extension in PATHEXT). I had previously encountered the same pattern—where wrapping it in &lt;code&gt;cmd.exe /c&lt;/code&gt; makes it work—in the Spotter itself when launching the claude CLI and had fixed it, but &lt;strong&gt;I had forgotten to apply this pattern to the MCP server launch path&lt;/strong&gt; (fixed in v1.2.2).&lt;/p&gt;

&lt;p&gt;I stepped into a trap I had set myself, just via a different path. Having experienced this, I strongly felt the necessity for &lt;a href="https://dev.to/quolu/published-caveat-to-npm-a-long-term-memory-layer-to-avoid-repeating-the-same-traps-2cc0"&gt;Caveat&lt;/a&gt;. If there isn't a mechanism to avoid stepping into the same trap twice, this is what happens.&lt;/p&gt;

&lt;h2&gt;
  
  
  Current Status
&lt;/h2&gt;

&lt;p&gt;v1.2.4. The CI for Windows, macOS, and Linux is all green.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-g&lt;/span&gt; claude-spotter
&lt;span class="nb"&gt;cd &lt;/span&gt;your-project
spotter &lt;span class="nb"&gt;install&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The tool catalog is automatically collected during &lt;code&gt;spotter install&lt;/code&gt;, and the SessionStart hook refreshes it in the background every time Claude Code is started. There is no need to manage it manually.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;spotter status      &lt;span class="c"&gt;# List of running auditors&lt;/span&gt;
spotter db list     &lt;span class="c"&gt;# Tool catalog for this project&lt;/span&gt;
spotter doctor      &lt;span class="c"&gt;# Environment diagnostics&lt;/span&gt;
spotter uninstall   &lt;span class="c"&gt;# Remove hook registration&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Areas Still Lacking
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;The Stop hook's correction results in two consecutive responses&lt;/strong&gt;. Because of the specification where the hook runs after the main Claude returns a response, when it issues a correction response, the user sees "the initial response + the correction response" one after another. It would be ideal if we could preempt it during input (UserPromptSubmit), and use the post-response hook as insurance.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;User input is blocked by Haiku's timeout&lt;/strong&gt;. I am currently considering whether to fail-open (bypass and let it through).&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Relationship with Throughline / Caveat
&lt;/h2&gt;

&lt;p&gt;Spotter is a &lt;strong&gt;separate product that shares a philosophy&lt;/strong&gt; with &lt;a href="https://dev.to/quolu/published-throughline-to-npm-a-hook-to-offload-claude-code-tool-io-to-sqlite-13d9"&gt;Throughline&lt;/a&gt; and &lt;a href="https://dev.to/quolu/published-caveat-to-npm-a-long-term-memory-layer-to-avoid-repeating-the-same-traps-2cc0"&gt;Caveat&lt;/a&gt;, created by the same author.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;Throughline&lt;/th&gt;
&lt;th&gt;Caveat&lt;/th&gt;
&lt;th&gt;Spotter&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Philosophy&lt;/td&gt;
&lt;td&gt;Subtraction&lt;/td&gt;
&lt;td&gt;Accumulation&lt;/td&gt;
&lt;td&gt;Addition&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Target&lt;/td&gt;
&lt;td&gt;Context bloat&lt;/td&gt;
&lt;td&gt;Stepping into the same trap twice&lt;/td&gt;
&lt;td&gt;Tool omission&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Mechanism&lt;/td&gt;
&lt;td&gt;Evacuate memory via hooks&lt;/td&gt;
&lt;td&gt;Surface past notes via hooks&lt;/td&gt;
&lt;td&gt;Run auditor in parallel via hooks&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;What the three have in common is a &lt;strong&gt;"mechanism that does not rely on the main Claude engine."&lt;/strong&gt; All three can coexist.&lt;/p&gt;

&lt;h2&gt;
  
  
  Requirements
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;  Node.js 22.5+&lt;/li&gt;
&lt;li&gt;  Claude Code 2.0+&lt;/li&gt;
&lt;li&gt;  Claude Max Plan (to launch Haiku 4.5 with &lt;code&gt;claude -p&lt;/code&gt;)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://github.com/kitepon-rgb/Spotter" rel="noopener noreferrer"&gt;Spotter — GitHub&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;MIT License. If you are struggling with the same problem, please feel free to take a look if you're interested.&lt;/p&gt;

</description>
      <category>claudecode</category>
      <category>ai</category>
      <category>hooks</category>
      <category>opensource</category>
    </item>
    <item>
      <title>Published Caveat to npm: A Long-term Memory Layer to Avoid Repeating the Same Traps</title>
      <dc:creator>QuoLu</dc:creator>
      <pubDate>Sun, 07 Jun 2026 01:01:30 +0000</pubDate>
      <link>https://dev.to/quolu/published-caveat-to-npm-a-long-term-memory-layer-to-avoid-repeating-the-same-traps-2cc0</link>
      <guid>https://dev.to/quolu/published-caveat-to-npm-a-long-term-memory-layer-to-avoid-repeating-the-same-traps-2cc0</guid>
      <description>&lt;p&gt;I have published &lt;a href="https://github.com/kitepon-rgb/Caveat" rel="noopener noreferrer"&gt;Caveat&lt;/a&gt;, a long-term memory layer for Claude Code, to npm.&lt;/p&gt;

&lt;h2&gt;
  
  
  What it does
&lt;/h2&gt;

&lt;p&gt;When using Claude Code, you often spend more time deciphering "other people's specifications" than doing the actual implementation. You get stuck on GPU driver version constraints, failed native module builds, IDE quirks, or path issues that only occur on specific OSs. Even after you struggle and solve it once, you end up stepping into the same trap in a different project six months later. When you ask the AI, it doesn't say "I don't know" but instead acts on assumptions, causing you to waste time all over again.&lt;/p&gt;

&lt;p&gt;Caveat is a layer where "&lt;strong&gt;once you jot it down&lt;/strong&gt;, relevant notes automatically surface the moment you encounter the same situation next time." Even if you can't remember it, and even if the AI doesn't know it, the relevance is detected structurally.&lt;/p&gt;

&lt;h2&gt;
  
  
  Three Trigger Points
&lt;/h2&gt;

&lt;p&gt;Caveat is implemented at three points using hooks.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Trigger Point&lt;/th&gt;
&lt;th&gt;When it runs&lt;/th&gt;
&lt;th&gt;What it does&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Prompt Submission&lt;/td&gt;
&lt;td&gt;The moment a prompt is sent&lt;/td&gt;
&lt;td&gt;Breaks down the prompt and surfaces only entries where two or more words co-occur with past notes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Tool Error&lt;/td&gt;
&lt;td&gt;The moment a Claude tool call fails&lt;/td&gt;
&lt;td&gt;Runs a background search and notifies the next turn as a known trap&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Session Termination&lt;/td&gt;
&lt;td&gt;When a session closes&lt;/td&gt;
&lt;td&gt;Extracts "struggle signals" from conversation logs. Prompts the AI if there is anything that should be recorded as a new trap&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;"Struggle signals" are traces where the AI might not be aware of it, but objectively it was struggling—such as tool failures, editing the same file repeatedly, repeated web searches, or re-executing Bash commands. It scans these at the end and prompts you, "You were stuck here in today's session, right? Do you want to record it as a trap?"&lt;/p&gt;

&lt;h2&gt;
  
  
  Design without Keyword Lists
&lt;/h2&gt;

&lt;p&gt;The search logic relies solely on &lt;strong&gt;Co-occurrence FTS&lt;/strong&gt;. There is no keyword correspondence table like "if the word 'rtx' comes up, display GPU-related notes."&lt;/p&gt;

&lt;p&gt;Instead, it breaks down the input prompt and only surfaces entries where &lt;strong&gt;two or more words appear in the same entry simultaneously&lt;/strong&gt;. Generic words like &lt;code&gt;make&lt;/code&gt; or &lt;code&gt;new&lt;/code&gt; do not trigger on their own, but when two or more technical words overlap, they match.&lt;/p&gt;

&lt;p&gt;Even when new trap categories are added, you just add one &lt;code&gt;entries/&amp;lt;slug&amp;gt;.md&lt;/code&gt;. You don't need to touch the code or keyword tables. The trigger expands itself.&lt;/p&gt;

&lt;h2&gt;
  
  
  Knowledge is markdown-in-git
&lt;/h2&gt;

&lt;p&gt;The data consists of standard markdown files. SQLite is used as a derived index for searching, which can be rebuilt if deleted.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;~/.caveat/own/
├── entries/
│   ├── rtx-5090-cuda-12-init-fail.md
│   ├── windows-node-spawn-cmd-enoent.md
│   └── ...
└── .git/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can open it directly as an Obsidian vault. If you want to share it with your team, you can simply &lt;code&gt;git push&lt;/code&gt;. There is no central server.&lt;/p&gt;

&lt;h2&gt;
  
  
  Public / Private Layers
&lt;/h2&gt;

&lt;p&gt;Entries have a &lt;code&gt;visibility&lt;/code&gt; attribute.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Public&lt;/strong&gt;: Traps anyone can encounter if they use the same external tools or specifications (GPU, build environments, IDEs, version constraints)&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Private&lt;/strong&gt;: Project-specific context that cannot be reconstructed just by reading the code (intentional non-standard behavior, workarounds awaiting upstream fixes, custom habits)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Claude automatically determines the visibility. When in doubt, it defaults to private (to prevent leakage). If you explicitly instruct, "This should be private," that takes priority.&lt;/p&gt;

&lt;p&gt;There is also a pre-commit hook mechanism that prevents &lt;code&gt;private&lt;/code&gt; entries from being mixed into the shared repository.&lt;/p&gt;

&lt;h2&gt;
  
  
  Installation
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-g&lt;/span&gt; caveat-cli
caveat init
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;caveat init&lt;/code&gt; does the following in one go:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  Initializes &lt;code&gt;~/.caveat/&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;  Registers the MCP server with Claude Code&lt;/li&gt;
&lt;li&gt;  Adds three hooks to &lt;code&gt;~/.claude/settings.json&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It does not break existing hook settings (it creates a backup before merging).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;caveat search &lt;span class="s2"&gt;"rtx"&lt;/span&gt;        &lt;span class="c"&gt;# Search existing notes&lt;/span&gt;
caveat serve               &lt;span class="c"&gt;# Start a read-only portal&lt;/span&gt;
caveat uninstall           &lt;span class="c"&gt;# Remove Claude integration only (data is kept)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  No Central DB
&lt;/h2&gt;

&lt;p&gt;Earlier versions had a shared database, with the concept of using &lt;code&gt;caveat push&lt;/code&gt; to cultivate knowledge collectively. This has been abandoned.&lt;/p&gt;

&lt;p&gt;I concluded that automatically verifying contributions from complete strangers is impossible in principle. Even if you use an LLM as a gatekeeper, it can be bypassed, and long-term latent attacks cannot be found through static analysis. Therefore, trust is built not through "automated inspection" but through "&lt;strong&gt;social context&lt;/strong&gt;." I shifted to a model where you decide the scope of trust by choosing whose repositories to subscribe to.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;caveat community add https://github.com/acme-corp/caveats
caveat pull
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I will write about the detailed background in another article.&lt;/p&gt;

&lt;h2&gt;
  
  
  Requirements
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;  Node.js 22.5+&lt;/li&gt;
&lt;li&gt;  Claude Code (with hooks support)&lt;/li&gt;
&lt;li&gt;  pnpm (development only)&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Status
&lt;/h2&gt;

&lt;p&gt;v0.11.1, 203 tests passing. Assumes individual and small team use cases.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/kitepon-rgb/Caveat" rel="noopener noreferrer"&gt;Caveat — GitHub&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;MIT License. Bug reports and PRs are welcome.&lt;/p&gt;

</description>
      <category>claudecode</category>
      <category>ai</category>
      <category>hooks</category>
      <category>opensource</category>
    </item>
    <item>
      <title>Published Throughline to npm: A hook to offload Claude Code tool I/O to SQLite</title>
      <dc:creator>QuoLu</dc:creator>
      <pubDate>Sat, 06 Jun 2026 00:54:54 +0000</pubDate>
      <link>https://dev.to/quolu/published-throughline-to-npm-a-hook-to-offload-claude-code-tool-io-to-sqlite-13d9</link>
      <guid>https://dev.to/quolu/published-throughline-to-npm-a-hook-to-offload-claude-code-tool-io-to-sqlite-13d9</guid>
      <description>&lt;p&gt;I have published a hook plugin for Claude Code called &lt;a href="https://github.com/kitepon-rgb/Throughline" rel="noopener noreferrer"&gt;Throughline&lt;/a&gt; to npm.&lt;/p&gt;

&lt;h2&gt;
  
  
  What it does
&lt;/h2&gt;

&lt;p&gt;In a Claude Code session, the majority of the context is filled with the remnants of "tool I/O." The contents of read files, grep results, and Bash output—data that served its purpose the moment the AI read it, made a decision, and moved on. However, it stays in the context until the end, consuming tokens.&lt;/p&gt;

&lt;p&gt;Throughline manages the conversation in three layers.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Layer&lt;/th&gt;
&lt;th&gt;Content&lt;/th&gt;
&lt;th&gt;Context Injection&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;L2&lt;/td&gt;
&lt;td&gt;Conversation body (user input + AI response)&lt;/td&gt;
&lt;td&gt;Last 20 turns injected as is&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;L1&lt;/td&gt;
&lt;td&gt;Summarized version of L2 (1/5th size) while retaining key points&lt;/td&gt;
&lt;td&gt;Injected for turns older than 20&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;L3&lt;/td&gt;
&lt;td&gt;Tool I/O, system messages, and thinking&lt;/td&gt;
&lt;td&gt;Not injected; offloaded to SQLite, retrieved by Claude as needed&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Since tool I/O is completely removed from the context, read grep results and Bash outputs do not linger until the end of the session. Older conversations are compressed to 1/5th of their original size while keeping key points, so you can still follow the context of decisions made dozens of turns ago.&lt;/p&gt;

&lt;p&gt;In a 50-turn session on my machine, a conversation that consumed 125,000 tokens was reduced to within 13,000 tokens.&lt;/p&gt;

&lt;h2&gt;
  
  
  Installation
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-g&lt;/span&gt; throughline
throughline &lt;span class="nb"&gt;install&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;install&lt;/code&gt; registers the hook in &lt;code&gt;~/.claude/settings.json&lt;/code&gt;. It runs automatically for all Claude Code projects on your PC. No configuration is required for individual projects.&lt;/p&gt;

&lt;h2&gt;
  
  
  Carrying over between sessions
&lt;/h2&gt;

&lt;p&gt;Throughline offloads conversations to SQLite, so the data remains even after running &lt;code&gt;/clear&lt;/code&gt;. If you want to carry over your memory to the next session, type &lt;code&gt;/tl&lt;/code&gt; in the previous session.&lt;/p&gt;

&lt;p&gt;Data is only carried over to the next session when you type &lt;code&gt;/tl&lt;/code&gt;. If you don't type it, it starts as a fresh session. Even if you open parallel windows or restart VSCode, it is designed so that it "won't fire accidentally unless you type &lt;code&gt;/tl&lt;/code&gt;."&lt;/p&gt;

&lt;p&gt;When carrying over, the "next step memo" written by the previous Claude and the internal reasoning (thinking) of the final turn are passed along as well. The next Claude runs in "continue from interruption" mode rather than "reading past logs" mode.&lt;/p&gt;

&lt;h2&gt;
  
  
  Token Monitor
&lt;/h2&gt;

&lt;p&gt;As a byproduct, a multi-session capable token monitor is included.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;throughline monitor
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[Throughline] 1 session
▶ Throughline  2ed5039c  ████░░░░░░░░░░░░░░░░  205.1k /  21%  Remaining 794.9k  claude-opus-4-6
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Since it reads actual API values (&lt;code&gt;message.usage&lt;/code&gt;) from the transcript JSONL, it provides accurate values rather than estimates based on &lt;code&gt;character count / 4&lt;/code&gt;. It also supports automatic detection of 1M context windows.&lt;/p&gt;

&lt;h2&gt;
  
  
  Requirements
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;  Node.js 22.5+ (uses the built-in &lt;code&gt;node:sqlite&lt;/code&gt; module)&lt;/li&gt;
&lt;li&gt;  Claude Code (supports hooks)&lt;/li&gt;
&lt;li&gt;  Claude Max plan (used for Haiku calls for L1 summarization; no API key required)&lt;/li&gt;
&lt;li&gt;  Windows / macOS / Linux&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Dependencies
&lt;/h2&gt;

&lt;p&gt;Zero. The tarball published to npm contains only &lt;code&gt;.mjs&lt;/code&gt; files. No build process or native bindings are required.&lt;/p&gt;




&lt;p&gt;The background of the design and my trial-and-error process are written in &lt;a href="https://dev.to/quolu/why-i-gave-up-on-automatic-detection-for-resuming-sessions-in-claude-code-3bj0"&gt;this article&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/kitepon-rgb/Throughline" rel="noopener noreferrer"&gt;Throughline — GitHub&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;MIT licensed. Bug reports and PRs are welcome.&lt;/p&gt;

</description>
      <category>claudecode</category>
      <category>ai</category>
      <category>hooks</category>
      <category>opensource</category>
    </item>
    <item>
      <title>Why I Gave Up on Automatic Detection for Resuming Sessions in Claude Code</title>
      <dc:creator>QuoLu</dc:creator>
      <pubDate>Fri, 05 Jun 2026 00:58:14 +0000</pubDate>
      <link>https://dev.to/quolu/why-i-gave-up-on-automatic-detection-for-resuming-sessions-in-claude-code-3bj0</link>
      <guid>https://dev.to/quolu/why-i-gave-up-on-automatic-detection-for-resuming-sessions-in-claude-code-3bj0</guid>
      <description>&lt;p&gt;In my &lt;a href="https://dev.to/quolu/87-of-my-context-was-garbage-how-i-optimized-claude-code-token-usage-534k"&gt;previous article&lt;/a&gt;, I released Throughline. It is a tool that offloads tool I/O, which usually occupies the majority of the context.&lt;/p&gt;

&lt;p&gt;At that time, it was "working." At least, in my own environment.&lt;/p&gt;

&lt;p&gt;However, right after publishing the article, I started noticing some strange behavior.&lt;/p&gt;

&lt;p&gt;When I opened another window in parallel, the new session would autonomously pick up the memory of the previous session. Every time I restarted VSCode, it would be treated as "continuing from the previous session." Even though I had never performed a &lt;code&gt;/clear&lt;/code&gt; command.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Cause: Unable to detect /clear
&lt;/h2&gt;

&lt;p&gt;Claude Code's hook includes an event called &lt;code&gt;SessionStart&lt;/code&gt;, and I was supposed to be able to distinguish between &lt;code&gt;startup&lt;/code&gt; (a new start) and &lt;code&gt;clear&lt;/code&gt; (after a &lt;code&gt;/clear&lt;/code&gt; command) using the &lt;code&gt;source&lt;/code&gt; field.&lt;/p&gt;

&lt;p&gt;However, with the VSCode extension, even if I perform a &lt;code&gt;/clear&lt;/code&gt;, the &lt;code&gt;source&lt;/code&gt; is overwritten as &lt;code&gt;startup&lt;/code&gt;. This is a known issue tracked in &lt;a href="https://github.com/anthropics/claude-code/issues/49937" rel="noopener noreferrer"&gt;GitHub issue #49937&lt;/a&gt;. It works if you use the CLI alone, but it cannot be identified when using the extension.&lt;/p&gt;

&lt;p&gt;I am using it via the VSCode extension. In other words, the design premise of "distinguishing between startup and clear" was fundamentally broken.&lt;/p&gt;

&lt;h2&gt;
  
  
  Attempting to compensate with heuristics
&lt;/h2&gt;

&lt;p&gt;So, I thought about determining it based on time differences. Like, if it's within 10 seconds of the last activity of the previous session, treat it as a clear; if longer, treat it as a startup.&lt;/p&gt;

&lt;p&gt;This also broke.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  When two windows are open in parallel, both appear as "recently active," making both candidates for inheritance.&lt;/li&gt;
&lt;li&gt;  Even when restarting VSCode, the transcript remains, making it look "recent."&lt;/li&gt;
&lt;li&gt;  I tried to trace the process tree, but the process structure differs between the CLI and the extension.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I realized that "there are no conditions to detect it in the first place."&lt;/p&gt;

&lt;h2&gt;
  
  
  Changing the approach
&lt;/h2&gt;

&lt;p&gt;I failed because I was trying to detect it. &lt;strong&gt;If the user declares it, detection becomes unnecessary.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;What I created is a slash command called &lt;code&gt;/tl&lt;/code&gt;. Users type it only when they want to carry over their memory to the next session. When typed, that session ID is written to a table called &lt;code&gt;handoff_batons&lt;/code&gt;. Imagine placing a baton.&lt;/p&gt;

&lt;p&gt;When the next session starts, if a baton was placed within the last hour, it inherits the memory of that session. If not, it does nothing and starts as a new session.&lt;/p&gt;

&lt;p&gt;This principle guarantees that parallel windows and VSCode restarts "will not misfire unless a baton is placed."&lt;/p&gt;

&lt;p&gt;Being explicit might seem troublesome at first glance, but "accidentally inheriting and causing trouble" is far more problematic. Having zero misfires was more valuable.&lt;/p&gt;

&lt;h2&gt;
  
  
  But, this alone wasn't enough
&lt;/h2&gt;

&lt;p&gt;With the baton in place, the next session could read the conversation logs of the previous session. However, after actually using it, I felt it was "just reading logs."&lt;/p&gt;

&lt;p&gt;There is a difference in the visceral experience between an AI that reads past logs and an AI that continues from the point of interruption.&lt;/p&gt;

&lt;p&gt;The former asks, "Okay, I've grasped the situation. So, what shall we do now?" The latter proceeds by saying, "Continuing from earlier, we should check X next, right?"&lt;/p&gt;

&lt;p&gt;So I added two things here.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;In-flight memo.&lt;/strong&gt; The moment &lt;code&gt;/tl&lt;/code&gt; is typed, I have the currently running Claude itself write down "the next move, current hypotheses, unresolved issues, and ongoing TODOs" in Markdown. That is attached to the baton.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Saving thinking.&lt;/strong&gt; I also save Claude's extended thinking blocks as L3. When injecting into the next session, I place the thinking from the final turn at the very top. What the previous Claude was thinking is passed on to the next Claude.&lt;/p&gt;

&lt;p&gt;As a result, the injected text for the next session looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;You are resuming an interrupted task.

[In-flight memo written by the previous Claude]
Next steps: Write tests for X. Hypothesis: I think Y is the cause. Unresolved: Z.

[What the previous Claude was thinking at the end]
I'm curious about the behavior of Z. Maybe...

[Conversation from the last 20 turns]
...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  From "reading" to "continuing"
&lt;/h2&gt;

&lt;p&gt;This changed the feel of the experience.&lt;/p&gt;

&lt;p&gt;When I perform a &lt;code&gt;/clear&lt;/code&gt; and then a &lt;code&gt;/tl&lt;/code&gt; to start a new session, the next Claude begins immediately with, "Alright, I'll start writing those tests for X from earlier." It’s not reading; it’s continuing.&lt;/p&gt;

&lt;p&gt;Even between humans, when handing off work to someone, it is faster to hand over a memo saying "What to do next. The reason. One thing I'm concerned about" rather than having them read the entire log. It was the same.&lt;/p&gt;

&lt;h2&gt;
  
  
  I actually wanted it to be automatic
&lt;/h2&gt;

&lt;p&gt;I don’t want to be misunderstood, but I believe the ideal is for it to "work automatically in the background." Having the user explicitly type something is, in truth, a compromise.&lt;/p&gt;

&lt;p&gt;In this case, I "escaped to an explicit declaration because I couldn't detect it." If the &lt;code&gt;source&lt;/code&gt; issue in the VSCode extension is fixed, I want to return to automatic detection, and I will. Until then, I am just substituting it with an explicit baton.&lt;/p&gt;

&lt;p&gt;However, even if it is a compromise, there is almost no practical harm. With automatic detection, you would end up typing &lt;code&gt;/clear&lt;/code&gt; anyway; now that is just replaced by &lt;code&gt;/tl&lt;/code&gt;. The keystrokes are the same, and I’ve been able to reduce misfires to zero.&lt;/p&gt;

&lt;p&gt;It is not that "explicit is better," but rather "I settled for a declaration because I couldn't detect it." That is the honest truth.&lt;/p&gt;




&lt;p&gt;Throughline is published on npm as v0.3.2. Node.js 22.5+, zero dependencies, MIT.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/kitepon-rgb/Throughline" rel="noopener noreferrer"&gt;Throughline — GitHub&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-g&lt;/span&gt; throughline
throughline &lt;span class="nb"&gt;install&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you are interested, please take a look.&lt;/p&gt;

</description>
      <category>claudecode</category>
      <category>ai</category>
      <category>hooks</category>
      <category>opensource</category>
    </item>
  </channel>
</rss>
