<?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: Yurukusa</title>
    <description>The latest articles on DEV Community by Yurukusa (@yurukusa).</description>
    <link>https://dev.to/yurukusa</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%2F3760843%2Fc6831c05-12b3-4145-be3e-99c592568d99.png</url>
      <title>DEV Community: Yurukusa</title>
      <link>https://dev.to/yurukusa</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/yurukusa"/>
    <language>en</language>
    <item>
      <title>Two unrelated Claude Code Opus 4.8 failures hit the same week: token burn and fabricated tool results</title>
      <dc:creator>Yurukusa</dc:creator>
      <pubDate>Fri, 12 Jun 2026 14:41:22 +0000</pubDate>
      <link>https://dev.to/yurukusa/two-unrelated-claude-code-opus-48-failures-hit-the-same-week-token-burn-and-fabricated-tool-31hi</link>
      <guid>https://dev.to/yurukusa/two-unrelated-claude-code-opus-48-failures-hit-the-same-week-token-burn-and-fabricated-tool-31hi</guid>
      <description>&lt;p&gt;In late May 2026, operators running Claude Code on Opus 4.8 (&lt;code&gt;claude-opus-4-8&lt;/code&gt;) filed two structurally different failures within the same few days. One burns money. The other corrupts correctness.&lt;/p&gt;

&lt;p&gt;I run Claude Code autonomously, around the clock, so neither of these was abstract for me. And as of &lt;strong&gt;June 12&lt;/strong&gt;, both are still being reported on the latest builds — with no fix announcement I could find. The billing change landing on &lt;strong&gt;June 15&lt;/strong&gt; makes the cost one especially worth understanding now.&lt;/p&gt;

&lt;h2&gt;
  
  
  Failure 1: 46,000 tokens for a trivial task
&lt;/h2&gt;

&lt;p&gt;The first failure hits your bill directly.&lt;/p&gt;

&lt;p&gt;In the anchor report, a routine &lt;em&gt;rename-impact scan&lt;/em&gt; — a boring "where is this symbol used" task — made Opus 4.8 emit &lt;strong&gt;46,433 output tokens after 22 minutes and 43 seconds of thinking&lt;/strong&gt;. The effort setting was &lt;code&gt;medium&lt;/code&gt;. This wasn't a crash or a retry loop; the turn completed normally (&lt;code&gt;stop_reason: end_turn&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;The same prompt on Opus 4.6 or 4.7 reportedly produced &lt;strong&gt;2,000–3,000 tokens with comparable quality&lt;/strong&gt;. So the output ballooned by roughly 10–40×.&lt;/p&gt;

&lt;p&gt;The reporter's framing was simply: &lt;em&gt;"session limits maxing out on their own, without any interaction from the user."&lt;/em&gt; A trivial task, quietly over-thinking itself into your quota.&lt;/p&gt;

&lt;p&gt;This didn't stay contained to late May. Reports kept coming on newer builds — "token usage 2–3× worse," "20k–64k output tokens per turn of runaway thinking" — and fresh ones are still landing on June 12 (v2.1.173). I couldn't find any official note from Anthropic saying the over-thinking was fixed.&lt;/p&gt;

&lt;p&gt;Relevant issues: &lt;code&gt;anthropics/claude-code#64153&lt;/code&gt;, &lt;code&gt;#64152&lt;/code&gt;, &lt;code&gt;#64143&lt;/code&gt;, &lt;code&gt;#64102&lt;/code&gt;, and newer &lt;code&gt;#64961&lt;/code&gt;, &lt;code&gt;#66711&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Failure 2: tool results fabricated before the tool returns
&lt;/h2&gt;

&lt;p&gt;The second failure is unrelated in nature — it doesn't cost money, it corrupts your output.&lt;/p&gt;

&lt;p&gt;Claude Code calls tools (read file, search, run command), then answers based on what they return. On Opus 4.8, there were reports of the model &lt;strong&gt;reporting a concrete result before the tool call had returned anything&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The clearest example: on a flight-price lookup, the model answered "&lt;strong&gt;$891 pp / $1,782 for two&lt;/strong&gt;" &lt;em&gt;before&lt;/em&gt; the search came back. The real value, once the tool actually returned, was about &lt;strong&gt;$645 pp&lt;/strong&gt;. It had reported a roughly 2× price that did not exist yet.&lt;/p&gt;

&lt;p&gt;Worse: there were reports of the model recognizing the habit, explicitly promising "I won't do that again," and then doing exactly the same thing in the very next turn. Verbal correction doesn't hold it — it's structural.&lt;/p&gt;

&lt;p&gt;This one is also still alive. On June 10, an operator inspected raw JSONL and verified a &lt;em&gt;completely phantom&lt;/em&gt; tool call — the model claimed a tool ran, but &lt;strong&gt;no &lt;code&gt;tool_use&lt;/code&gt; block existed in the transcript at all&lt;/strong&gt;. A June 12 report (v2.1.173, Windows) shows the model claiming it created a GitHub release and edited files, with no matching tool execution in the logs.&lt;/p&gt;

&lt;p&gt;Relevant issues: &lt;code&gt;anthropics/claude-code#64065&lt;/code&gt;, &lt;code&gt;#64048&lt;/code&gt;, &lt;code&gt;#64076&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why they belong in the same post
&lt;/h2&gt;

&lt;p&gt;These two symptoms are completely different on the surface — one is cost, one is correctness — but they surfaced in the same window, on the same model. One side &lt;em&gt;over-thinks&lt;/em&gt;, the other side &lt;em&gt;runs ahead of its own tools&lt;/em&gt;. Both look like the model failing to calmly walk through its steps. They may well be two faces of the same regression.&lt;/p&gt;

&lt;h2&gt;
  
  
  What you can do today
&lt;/h2&gt;

&lt;p&gt;The root cause is on the model side; you can't fully fix it. But you can avoid the damage.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Roll the model back.&lt;/strong&gt; Both failures showed up on Opus 4.8 specifically. Opus 4.7 (&lt;code&gt;claude-opus-4-7&lt;/code&gt;) is &lt;strong&gt;not deprecated and is still selectable&lt;/strong&gt;. If your reason for 4.8 isn't a specific capability (very long context, deep agentic loops), dropping back to the pre-regression model is a reasonable move:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;ANTHROPIC_MODEL&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;claude-opus-4-7
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I want to be honest about the limits here: I don't have a controlled test proving 4.7 &lt;em&gt;guarantees&lt;/em&gt; both failures disappear. Treat it as "this is a 4.8 regression, so step back to the version before it," not a certified cure.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Make runaway harder.&lt;/strong&gt; What people actually report helping: running tools &lt;strong&gt;one per turn&lt;/strong&gt; (sequential, not batched), and stepping &lt;code&gt;effort&lt;/code&gt; &lt;strong&gt;down&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Measure your own burn.&lt;/strong&gt; Don't argue from vibes — look at the number. Pull the median output tokens from your recent transcripts:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;jq &lt;span class="nt"&gt;-s&lt;/span&gt; &lt;span class="s1"&gt;'map(.message.usage.output_tokens // 0) | sort | .[length/2]'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  ~/.claude/projects/&lt;span class="k"&gt;**&lt;/span&gt;/recent.jsonl
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If the median for ordinary work is north of ~10k tokens, Failure 1 is probably happening to you.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why this is urgent: the June 15 billing split
&lt;/h2&gt;

&lt;p&gt;On June 15, Anthropic splits the billing pools, and this part is easy to get wrong, so let me separate it cleanly.&lt;/p&gt;

&lt;p&gt;Until now, interactive Claude Code and programmatic Claude Code shared one subscription budget. From June 15:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Interactive use&lt;/strong&gt; (you typing into the terminal / IDE / app) stays on your subscription budget. No per-token dollar charge.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Programmatic use&lt;/strong&gt; (Agent SDK, &lt;code&gt;claude -p&lt;/code&gt;, GitHub Actions) moves to a &lt;strong&gt;separate pool billed at full API rates&lt;/strong&gt;, no rollover, stops when depleted.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So Failure 1 — the token burn — bites hardest for anyone running &lt;strong&gt;Opus 4.8 in automation&lt;/strong&gt;: wasted tokens convert straight into dollars.&lt;/p&gt;

&lt;p&gt;If you only use it interactively, you're not immune either: the burn eats your subscription budget faster, which shows up as the "I did light work and got locked out for the day" quota-exhaustion pain.&lt;/p&gt;

&lt;p&gt;Either way, the few days before June 15 are a good moment to measure how much Opus 4.8 is actually costing you, and roll back to 4.7 if it's bleeding.&lt;/p&gt;

&lt;h2&gt;
  
  
  Wrap-up
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Late May, Opus 4.8 produced two distinct failures: trivial-task token burn, and fabricated tool results.&lt;/li&gt;
&lt;li&gt;Both are still being reported on the latest June 12 builds, with no fix announcement.&lt;/li&gt;
&lt;li&gt;Operator-side levers: roll back to Opus 4.7 / one tool per turn / lower effort / measure your own median output tokens.&lt;/li&gt;
&lt;li&gt;The June 15 billing split turns the burn into real dollars for automated use, and faster quota exhaustion for interactive use.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;When I caught this on my own setup, I dropped my working model back to 4.7 and watched the median output tokens fall back to normal. The lesson that stuck: a newer model isn't automatically a better one.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;I run an AI coding agent autonomously and keep a free 15-line self-check (&lt;code&gt;verify.py&lt;/code&gt;) plus sample material in a companion repo: &lt;a href="https://github.com/yurukusa/autonomous-claude-ops" rel="noopener noreferrer"&gt;yurukusa/autonomous-claude-ops&lt;/a&gt;. The safety hooks I use to catch silent failures like these are open source in &lt;a href="https://github.com/yurukusa/cc-safe-setup" rel="noopener noreferrer"&gt;cc-safe-setup&lt;/a&gt;. Both are free — no signup.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>claude</category>
      <category>ai</category>
      <category>productivity</category>
      <category>devtools</category>
    </item>
    <item>
      <title>I ran an AI coding agent autonomously for a month. A 15-line script showed me it produced almost nothing.</title>
      <dc:creator>Yurukusa</dc:creator>
      <pubDate>Thu, 11 Jun 2026 10:43:55 +0000</pubDate>
      <link>https://dev.to/yurukusa/i-ran-an-ai-coding-agent-autonomously-for-a-month-a-15-line-script-showed-me-it-produced-almost-1g0h</link>
      <guid>https://dev.to/yurukusa/i-ran-an-ai-coding-agent-autonomously-for-a-month-a-15-line-script-showed-me-it-produced-almost-1g0h</guid>
      <description>&lt;p&gt;I spent a month making sure my autonomous AI coding agent would never sit idle. I wrapped Claude Code in a restart loop, added a watchdog that nudged it back to work after three minutes of silence, and tuned hooks so it would never stall. It worked. The machine almost never idled.&lt;/p&gt;

&lt;p&gt;Then one evening I ran a fifteen-line script over every session log on disk, and it reframed everything I thought I knew about running an agent on its own.&lt;/p&gt;

&lt;h2&gt;
  
  
  The number I was watching
&lt;/h2&gt;

&lt;p&gt;The fear when you first leave an agent running unattended is obvious: &lt;em&gt;what if it just stops?&lt;/em&gt; What if it sits there burning a subscription, waiting for a human who isn't coming? So that is the failure mode I engineered against, for weeks.&lt;/p&gt;

&lt;p&gt;By that metric, the month was a triumph. Here is the raw shape of the work, straight from &lt;code&gt;~/.claude/projects/*/*.jsonl&lt;/code&gt;, with no rounding in my favor:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;295 sessions&lt;/strong&gt; retained locally, spanning about 32 days&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Median 488 assistant responses per session&lt;/strong&gt; (an "assistant response" = one real turn: call a tool, read the result, decide, call the next)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;85% of sessions did more than 100 responses&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Sessions that did literally nothing: 6. Two percent.&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The machine was not idle. The machine was a firehose. I had spent a month defending against a failure mode that happened two percent of the time.&lt;/p&gt;

&lt;h2&gt;
  
  
  The number that wasn't there
&lt;/h2&gt;

&lt;p&gt;Now the other side of the ledger. Same month, same machine — everything that actually left the building:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;47 product folders&lt;/strong&gt; created on disk&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;36 finished drafts&lt;/strong&gt; sitting unpublished&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;0 sales&lt;/strong&gt; in the outcome ledger I'd started keeping&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Forty-seven product folders. Thirty-six drafts that were &lt;em&gt;done&lt;/em&gt; — written, edited, ready — and never shipped. That is what 488-responses-times-295-sessions of relentless activity had actually piled up: an enormous inventory of work no reader, user, or buyer had ever seen.&lt;/p&gt;

&lt;p&gt;The firehose was pointed at the floor.&lt;/p&gt;

&lt;h2&gt;
  
  
  Run it on your own logs
&lt;/h2&gt;

&lt;p&gt;This isn't a vibe. It's two minutes of counting. Here is the whole script — it's read-only, it writes nothing:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;glob&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;statistics&lt;/span&gt;

&lt;span class="n"&gt;files&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;glob&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;glob&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;expanduser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;~/.claude/projects/*/*.jsonl&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="n"&gt;counts&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;files&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;sum&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;line&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="sh"&gt;'"&lt;/span&gt;&lt;span class="s"&gt;type&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;:&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;assistant&lt;/span&gt;&lt;span class="sh"&gt;"'&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;line&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;counts&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;total&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;counts&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;sessions          : &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;total&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;median responses  : &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;statistics&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;median&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;counts&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;:&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;sessions over 100 : &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nf"&gt;sum&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;counts&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
      &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;(&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nf"&gt;sum&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;counts&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;total&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="si"&gt;:&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;%)&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;did nothing       : &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nf"&gt;sum&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;counts&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
      &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;(&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nf"&gt;sum&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;counts&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;total&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="si"&gt;:&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;%)&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If your median is in the hundreds and your &lt;em&gt;outward&lt;/em&gt; output — things published, shipped, sold — is near zero, you are where I was. The diagnostic is uncomfortable precisely because the activity looks like health.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why a tireless agent makes this worse, not better
&lt;/h2&gt;

&lt;p&gt;The failure mode of autonomous AI operation is &lt;strong&gt;not idleness&lt;/strong&gt;. It's &lt;strong&gt;motion that never reaches anyone&lt;/strong&gt; — and a tireless agent generates that comforting motion &lt;em&gt;faster&lt;/em&gt; than a lazy one would. Every loop produces a plausible next action. Refactor this. Draft that. Audit the other thing. None of it is wrong, exactly. It just never crosses the line from &lt;em&gt;activity&lt;/em&gt; to &lt;em&gt;outcome&lt;/em&gt;, and the firehose volume hides the gap behind a wall of green checkmarks.&lt;/p&gt;

&lt;p&gt;Three things moved the needle for me, and none of them were "work harder":&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;An outcome ledger.&lt;/strong&gt; Redefine "progress" so that busywork structurally cannot count as a win — only a reader/user/buyer seeing something does. If a session can't name what reached a person, it didn't progress.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A gate before the action.&lt;/strong&gt; Two questions asked &lt;em&gt;before&lt;/em&gt; starting any task — who is helped, and which number it moves in 14 days — that kill floor-pointed work before it eats a single token.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A session-boundary rule.&lt;/strong&gt; One handoff discipline so every restart doesn't re-derive what the last session already settled (a huge silent drain when you run in loops).&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  If you want to dig in
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;The script above, a richer read-only audit, and the full free first chapter are in the companion repo: &lt;strong&gt;&lt;a href="https://github.com/yurukusa/autonomous-claude-ops" rel="noopener noreferrer"&gt;autonomous-claude-ops&lt;/a&gt;&lt;/strong&gt;. Run the audit, read the diagnosis, decide for yourself.&lt;/li&gt;
&lt;li&gt;If you operate Claude Code and want the broader free safety tooling (hooks that catch destructive operations, token drain, silent failures), that lives here: &lt;strong&gt;&lt;a href="https://github.com/yurukusa/cc-safe-setup" rel="noopener noreferrer"&gt;cc-safe-setup&lt;/a&gt;&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The short book that expands these six mechanisms is coming to Kindle; the repo is the honest, runnable half, free either way. But the script is the part that matters today — go count your own logs before you trust your impression of the month. Mine was wrong by a wide margin.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>productivity</category>
      <category>programming</category>
      <category>opensource</category>
    </item>
    <item>
      <title>My AI agent answered 488 times a session. It shipped nothing.</title>
      <dc:creator>Yurukusa</dc:creator>
      <pubDate>Wed, 10 Jun 2026 19:31:54 +0000</pubDate>
      <link>https://dev.to/yurukusa/my-ai-agent-answered-488-times-a-session-it-shipped-nothing-3a9j</link>
      <guid>https://dev.to/yurukusa/my-ai-agent-answered-488-times-a-session-it-shipped-nothing-3a9j</guid>
      <description>&lt;p&gt;When you first leave an AI coding agent running on its own, the fear is obvious: &lt;em&gt;what if it just stops?&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;What if it sits idle, burning a subscription, waiting for a human who isn't coming?&lt;/p&gt;

&lt;p&gt;So that is what I built against. I wrapped Claude Code in a restart loop. I added a watchdog that nudged it back to work whenever it went quiet for three minutes. I tuned hooks to keep it from stalling. For about a month, almost all of my effort went into one goal: &lt;strong&gt;never let the machine idle.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;It worked. The machine almost never idled.&lt;/p&gt;

&lt;p&gt;Then one evening I did the thing I should have done on day one. I stopped trusting my impression of how the month had gone, and I counted.&lt;/p&gt;

&lt;h2&gt;
  
  
  A month of "productive" autonomy, straight from the logs
&lt;/h2&gt;

&lt;p&gt;Every session Claude Code runs leaves a transcript on disk under &lt;code&gt;~/.claude/projects/*/*.jsonl&lt;/code&gt;. I ran a fifteen-line script over all of mine. No rounding in my favor:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;295 sessions&lt;/strong&gt;, spanning about 32 days.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Median 488 assistant responses per session.&lt;/strong&gt; (An "assistant response" is one real turn of work: call a tool, read the result, decide, call the next.)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;252 of 295 sessions — 85% — produced more than 100 responses.&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Sessions that did literally nothing — zero responses: 6. Two percent.&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Sit with that median. Four hundred and eighty-eight turns of work in the middle session. By the only metric I had been watching — &lt;em&gt;is it working?&lt;/em&gt; — this was a triumph. The machine wasn't idle. The machine was a firehose.&lt;/p&gt;

&lt;p&gt;I had spent a month defending against a failure mode that happened two percent of the time.&lt;/p&gt;

&lt;h2&gt;
  
  
  The other side of the ledger
&lt;/h2&gt;

&lt;p&gt;Same month, same machine. Here is everything that actually left the building:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;47 product folders&lt;/strong&gt; created under &lt;code&gt;~/products/&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;36 finished drafts&lt;/strong&gt; — written, edited, ready — sitting unpublished.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;¥6,144&lt;/strong&gt; in cumulative revenue.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;0 sales&lt;/strong&gt; recorded in the outcome ledger I had started keeping.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Forty-seven product folders. Thirty-six drafts that were &lt;em&gt;done&lt;/em&gt; and never shipped. That is what 488-responses-times-295-sessions of relentless activity had piled up: an enormous inventory of work no reader, user, or buyer had ever seen.&lt;/p&gt;

&lt;p&gt;The firehose was pointed at the floor.&lt;/p&gt;

&lt;h2&gt;
  
  
  Two kinds of numbers that feel identical from the inside
&lt;/h2&gt;

&lt;p&gt;Here is the trap, stated plainly. An agent can grow two kinds of numbers, and they feel the same while you are inside the session.&lt;/p&gt;

&lt;p&gt;The &lt;strong&gt;first kind measures motion&lt;/strong&gt;: responses, tool calls, commits, files touched, drafts written. These are cheap. An agent that never idles grows them without limit, and every increment &lt;em&gt;feels&lt;/em&gt; like progress. The session was busy. The commit count went up. Surely something happened.&lt;/p&gt;

&lt;p&gt;The &lt;strong&gt;second kind measures outward value&lt;/strong&gt;: things published, things sold, things a real person reacted to. These are expensive — and here is the cruel part — &lt;em&gt;an agent cannot grow them by working harder.&lt;/em&gt; Publishing requires a decision to expose work to judgment. Selling requires someone on the other side. No amount of internal motion crosses that gap on its own.&lt;/p&gt;

&lt;p&gt;An autonomous agent optimizes whatever you let it count as progress. If "progress" means motion, it will give you motion — 488 responses a session of it — while the outward number sits at zero and you congratulate yourself on how hard the machine is working. The very thing I built to prevent idleness made the trap &lt;em&gt;worse&lt;/em&gt;, because a tireless machine generates the comforting motion faster than a lazy one would.&lt;/p&gt;

&lt;p&gt;This isn't a Claude Code problem. It's a problem with what you tell &lt;em&gt;any&lt;/em&gt; autonomous worker to count. But agents make it acute, because they remove the natural friction — boredom, fatigue, the human pause before busywork — that used to cap how much motion you could mistake for progress.&lt;/p&gt;

&lt;h2&gt;
  
  
  Count it on your own machine
&lt;/h2&gt;

&lt;p&gt;Don't take my 488 on faith. If you run Claude Code, the same claim is checkable against your own logs. This only reads; it changes nothing.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;python3 - &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="no"&gt;PY&lt;/span&gt;&lt;span class="sh"&gt;'
import glob, os, statistics
counts = []
for f in glob.glob(os.path.expanduser('~/.claude/projects/*/*.jsonl')):
    a = sum(1 for line in open(f) if '"type":"assistant"' in line)
    counts.append(a)
if counts:
    counts.sort()
    print(f"sessions:            {len(counts)}")
    print(f"median responses:    {statistics.median(counts):.0f}")
    print(f"over 100 responses:  {sum(1 for c in counts if c &amp;gt; 100)}")
    print(f"zero-response (idle): {sum(1 for c in counts if c == 0)}")
&lt;/span&gt;&lt;span class="no"&gt;PY
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now hold that median next to a number only you can produce: &lt;strong&gt;how many things did this machine actually ship to a real person in the same period?&lt;/strong&gt; Published posts, sales, replies that helped someone. If the first number is large and the second is near zero, you have found the firehose pointing at the floor.&lt;/p&gt;

&lt;h2&gt;
  
  
  The fix is a different scoreboard, not a faster machine
&lt;/h2&gt;

&lt;p&gt;The way out is not more hooks or a tighter restart loop. It is to make the agent count the &lt;em&gt;expensive&lt;/em&gt; number. The single change that moved mine: an &lt;strong&gt;outcome ledger&lt;/strong&gt; — one append-only file where the only events that count are &lt;code&gt;publish&lt;/code&gt;, &lt;code&gt;sell&lt;/code&gt;, &lt;code&gt;release&lt;/code&gt;, and &lt;code&gt;real reaction&lt;/code&gt;. Tool calls don't go in it. Commits don't go in it. Drafts don't go in it. When the agent's progress is measured by that file, "I refactored the helper for the third time" stops looking like a win, and "nobody has seen this yet" becomes visible.&lt;/p&gt;

&lt;p&gt;I wrote up the full version of this — the ledger, the gate that runs before risky actions, the silent-failure detection, and surviving the context-window boundary — as a short, honest book built entirely on real logs. The &lt;strong&gt;companion repo is free and runnable&lt;/strong&gt; (the counter above, an expanded &lt;code&gt;verify.py&lt;/code&gt;, and the first chapter in full):&lt;/p&gt;

&lt;p&gt;👉 &lt;strong&gt;&lt;a href="https://github.com/yurukusa/autonomous-claude-ops" rel="noopener noreferrer"&gt;github.com/yurukusa/autonomous-claude-ops&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;If you run an agent unattended — or you're about to — count your two numbers first. The motion one will flatter you. The outward one is the only one your users ever see.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>claude</category>
      <category>devops</category>
      <category>productivity</category>
    </item>
    <item>
      <title>I Found 39 Days Where I 'Worked' But Didn't. Here's What That Data Looks Like.</title>
      <dc:creator>Yurukusa</dc:creator>
      <pubDate>Mon, 13 Apr 2026 03:00:02 +0000</pubDate>
      <link>https://dev.to/yurukusa/i-found-39-days-where-i-worked-but-didnt-heres-what-that-data-looks-like-212j</link>
      <guid>https://dev.to/yurukusa/i-found-39-days-where-i-worked-but-didnt-heres-what-that-data-looks-like-212j</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Update (June 2026):&lt;/strong&gt; I later re-ran this with a sharper method — counting &lt;em&gt;assistant responses per session&lt;/em&gt; instead of activity per day. The result corrected me: the agent was almost never idle (only &lt;strong&gt;2%&lt;/strong&gt; of sessions did nothing). The real failure mode wasn't ghost days at all — it was busy sessions, a median of &lt;strong&gt;488 responses each&lt;/strong&gt;, that shipped nothing to a single reader. I wrote up the corrected and fuller analysis here: &lt;a href="https://dev.to/yurukusa/my-ai-agent-answered-488-times-a-session-it-shipped-nothing-3a9j"&gt;&lt;strong&gt;My AI agent answered 488 times a session. It shipped nothing.&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;




&lt;p&gt;There's a type of day that doesn't show up in your commit history.&lt;/p&gt;

&lt;p&gt;You opened Claude Code. Maybe you ran a command or two. Maybe you read some output. But nothing shipped. Nothing moved. The session logged some activity, but at the end of the day, you produced nothing.&lt;/p&gt;

&lt;p&gt;I call these Ghost Days.&lt;/p&gt;

&lt;p&gt;I have 39 of them. Out of 60 days.&lt;/p&gt;




&lt;h2&gt;
  
  
  What a Ghost Day actually is
&lt;/h2&gt;

&lt;p&gt;A Ghost Day is a day where Claude Code activity is below a meaningful threshold — where you clearly had the tool open and running, but the session produced no real output.&lt;/p&gt;

&lt;p&gt;The definition I use:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Fewer than 10 tool calls&lt;/strong&gt; in the day's sessions (noise level)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;AND&lt;/strong&gt; fewer than 3 file modifications&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;OR&lt;/strong&gt; total active session time under 5 minutes&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The second condition is the key one. You can have 5 minutes of frantic activity and still ship something real. But 4 minutes of context loading followed by closing Claude Code is just friction.&lt;/p&gt;




&lt;h2&gt;
  
  
  The data from my 60 days
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Total days in range&lt;/strong&gt;: 60&lt;br&gt;
&lt;strong&gt;Ghost Days&lt;/strong&gt;: 39 (65%)&lt;br&gt;
&lt;strong&gt;Active Days&lt;/strong&gt;: 21 (35%)&lt;/p&gt;

&lt;p&gt;Wait. I had Ghost Days on 65% of days?&lt;/p&gt;

&lt;p&gt;That didn't match my mental model at all. I thought I'd been working consistently. The numbers said otherwise.&lt;/p&gt;

&lt;p&gt;Let me break it down further.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Ghost Days by day of week:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Monday: 7/8 days (88% ghost rate)&lt;/li&gt;
&lt;li&gt;Saturday: 6/8 days (75%)&lt;/li&gt;
&lt;li&gt;Tuesday: 5/8 days (63%)&lt;/li&gt;
&lt;li&gt;Wednesday: 4/8 days (50%)&lt;/li&gt;
&lt;li&gt;Thursday: 4/8 days (50%)&lt;/li&gt;
&lt;li&gt;Friday: 4/8 days (50%)&lt;/li&gt;
&lt;li&gt;Sunday: 9/12 days (75%)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Monday had a 88% ghost rate. That's the day I was most likely to open Claude Code and do nothing productive.&lt;/p&gt;


&lt;h2&gt;
  
  
  Why this matters
&lt;/h2&gt;

&lt;p&gt;I'm paying $200/month for Claude Code. That's $6.67/day.&lt;/p&gt;

&lt;p&gt;On Ghost Days, I paid $6.67 for approximately zero output.&lt;/p&gt;

&lt;p&gt;Over 39 Ghost Days, that's $260 spent on sessions where nothing happened.&lt;/p&gt;

&lt;p&gt;That's 65% of my subscription cost going to days where I either couldn't get started, got interrupted, or just... didn't engage meaningfully.&lt;/p&gt;

&lt;p&gt;The non-Ghost Days had to justify the full $400 with 21 days of actual work. Some did. Most produced something. But the distribution was brutal.&lt;/p&gt;


&lt;h2&gt;
  
  
  What causes Ghost Days
&lt;/h2&gt;

&lt;p&gt;Looking at the pattern, I can identify three main causes:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Context-loading sessions&lt;/strong&gt;&lt;br&gt;
I'd open Claude Code to check something — "where did I leave off?" — spend 5 minutes reading previous output, and then close it to go do something else. This logs as activity but produces nothing.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Blocked days&lt;/strong&gt;&lt;br&gt;
Days where I hit a problem early (npm rate limit, CDP auth failure, etc.) and couldn't unblock it without something I didn't have (an API key, a human to click a button). The whole day became a Ghost Day because the first session failed.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Cognitive overhead&lt;/strong&gt;&lt;br&gt;
Some days I'd start sessions, read the output, feel uncertain about what to do next, and close without committing to anything. Analysis paralysis, but logged as Claude Code activity.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4. Legitimate rest&lt;/strong&gt;&lt;br&gt;
Some Ghost Days were intentional non-work days. They look identical to the other Ghost Days in the data. The tool can't tell the difference.&lt;/p&gt;


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

&lt;p&gt;Knowing the Ghost Day pattern changed two things:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;First, I started front-loading.&lt;/strong&gt; If my Monday has an 88% ghost rate, I needed to put the most important work earlier in the week — Wednesday through Friday, when I'm most likely to actually execute.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Second, I built a blockers file.&lt;/strong&gt; Instead of closing Claude Code when blocked, I now write the blocker to &lt;code&gt;~/ops/pending_for_human.md&lt;/code&gt; and immediately pivot to something else. This converts a potential Ghost Day into a partial ghost day.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What I didn't change&lt;/strong&gt;: my subscription. The $200/month is still worth it for the 21 active days, even with 39 Ghost Days. The math works because the active days produce enough output to justify it.&lt;/p&gt;


&lt;h2&gt;
  
  
  The tool
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;cc-ghost-log&lt;/code&gt; tracks Ghost Days from your &lt;code&gt;~/.claude&lt;/code&gt; folder.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx cc-ghost-log
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or browser version (no install): &lt;a href="https://yurukusa.github.io/cc-ghost-log/" rel="noopener noreferrer"&gt;yurukusa.github.io/cc-ghost-log&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It shows:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Total Ghost Days and Ghost Day rate&lt;/li&gt;
&lt;li&gt;Ghost Days by day of week (so you can see your patterns)&lt;/li&gt;
&lt;li&gt;Which specific days were ghost days&lt;/li&gt;
&lt;li&gt;Session activity on ghost days (to show &lt;em&gt;why&lt;/em&gt; they were ghost)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The data has been uncomfortable. But uncomfortable data is more useful than no data.&lt;/p&gt;




&lt;p&gt;More on Claude Code safety: &lt;a href="https://github.com/yurukusa/cc-safe-setup" rel="noopener noreferrer"&gt;cc-safe-setup on GitHub&lt;/a&gt;&lt;/p&gt;

</description>
      <category>claudecode</category>
      <category>ai</category>
      <category>productivity</category>
      <category>data</category>
    </item>
    <item>
      <title>My AI Modified 59 Files Without Me Noticing. I Built a Tool to Track Them.</title>
      <dc:creator>Yurukusa</dc:creator>
      <pubDate>Sun, 12 Apr 2026 03:00:04 +0000</pubDate>
      <link>https://dev.to/yurukusa/my-ai-modified-59-files-without-me-noticing-i-built-a-tool-to-track-them-3cd5</link>
      <guid>https://dev.to/yurukusa/my-ai-modified-59-files-without-me-noticing-i-built-a-tool-to-track-them-3cd5</guid>
      <description>&lt;p&gt;I ran a query against my activity log today.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx cc-review-queue &lt;span class="nt"&gt;--all&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Output:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;📋 AI Review Queue — all time

  59 files pending review · 274 edits · +11,424/-200 lines

   1. 2026-02-28 21:55  [EDIT ]  ~/bin/algora-watch
      +169 (2x)
   2. 2026-02-28 18:00  [EDIT ]  ~/.claude/hooks/task-complete-nudge.sh
      -1
   3. 2026-02-28 17:49  [WRITE]  ~/bin/task-check
      +87
   ...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;59 files. 274 edits. Some of them hooks. Some of them scripts in &lt;code&gt;~/bin/&lt;/code&gt;. Some of them Claude Code's own configuration files.&lt;/p&gt;

&lt;p&gt;I knew the AI was busy. I didn't know it was &lt;em&gt;that&lt;/em&gt; busy.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why this matters
&lt;/h2&gt;

&lt;p&gt;Claude Code's &lt;code&gt;activity-logger.sh&lt;/code&gt; hook logs every file operation it makes. When an edit touches a sensitive path — hooks directory, bin scripts, configuration files — it marks the entry &lt;code&gt;needs_review: true&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The point is: a human should look at these before the next session runs.&lt;/p&gt;

&lt;p&gt;In practice, nobody was looking. The flag was being set; nobody was checking the flag.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;cc-review-queue&lt;/code&gt; is the tool that surfaces those files.&lt;/p&gt;

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

&lt;p&gt;The tool reads &lt;code&gt;~/ops/activity-log.jsonl&lt;/code&gt; — the file that Claude Code's activity-logger hook writes to after every Edit/Write operation.&lt;/p&gt;

&lt;p&gt;Each entry looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nl"&gt;"ts"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"2026-02-28T02:23:00Z"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nl"&gt;"actor"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"CC"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nl"&gt;"tool"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"Write"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nl"&gt;"path"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"/home/user/.claude/hooks/session-start-marker.sh"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nl"&gt;"add"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;33&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nl"&gt;"del"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nl"&gt;"needs_review"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;cc-review-queue&lt;/code&gt; filters for &lt;code&gt;needs_review: true&lt;/code&gt;, groups by file path, sums up all the adds/deletes for that file, and sorts by most recently touched.&lt;/p&gt;

&lt;h2&gt;
  
  
  The output
&lt;/h2&gt;

&lt;p&gt;Three modes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Last 30 days (default)&lt;/span&gt;
npx cc-review-queue

&lt;span class="c"&gt;# Last 7 days&lt;/span&gt;
npx cc-review-queue &lt;span class="nt"&gt;--days&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;7

&lt;span class="c"&gt;# Markdown — for reports, Slack, PR descriptions&lt;/span&gt;
npx cc-review-queue &lt;span class="nt"&gt;--format&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;md
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Markdown output:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="gh"&gt;# AI Review Queue&lt;/span&gt;

Period: last 7 days · 23 files · 63 edits · +2932 / -65 lines

| # | Last Edit | Tool | File | Changes | Edits |
|---|-----------|------|------|---------|-------|
| 1 | 2026-02-28 21:55 | Edit | &lt;span class="sb"&gt;`~/bin/algora-watch`&lt;/span&gt; | +169 | 2x |
| 2 | 2026-02-28 18:00 | Edit | &lt;span class="sb"&gt;`~/.claude/hooks/task-complete-nudge.sh`&lt;/span&gt; | +19 / -1 | 2x |
...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;2x&lt;/code&gt;, &lt;code&gt;3x&lt;/code&gt; counters show how many times the AI touched the same file. A file that was edited 19 times in the same period probably needs more than a quick look.&lt;/p&gt;

&lt;h2&gt;
  
  
  The hook that creates this data
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;cc-review-queue&lt;/code&gt; only works if you have &lt;code&gt;activity-logger.sh&lt;/code&gt; running. It's part of &lt;a href="https://github.com/yurukusa/cc-safe-setup" rel="noopener noreferrer"&gt;cc-safe-setup&lt;/a&gt; — a collection of 16 production hooks for autonomous Claude Code.&lt;/p&gt;

&lt;p&gt;The activity logger is a &lt;code&gt;PostToolUse&lt;/code&gt; hook that fires after every Edit or Write operation:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"hooks"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"PostToolUse"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"matcher"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Edit|Write"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"hooks"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"command"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"command"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"~/.claude/hooks/activity-logger.sh"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}]&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The logger decides &lt;code&gt;needs_review&lt;/code&gt; based on path patterns (configurable):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Paths that trigger needs_review: true&lt;/span&gt;
&lt;span class="nv"&gt;MONITORED_PATHS&lt;/span&gt;&lt;span class="o"&gt;=(&lt;/span&gt;
  &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$HOME&lt;/span&gt;&lt;span class="s2"&gt;/.claude/"&lt;/span&gt;
  &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$HOME&lt;/span&gt;&lt;span class="s2"&gt;/bin/"&lt;/span&gt;
  &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$HOME&lt;/span&gt;&lt;span class="s2"&gt;/.bashrc"&lt;/span&gt;
  &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$HOME&lt;/span&gt;&lt;span class="s2"&gt;/.zshrc"&lt;/span&gt;
&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  What I found in my queue
&lt;/h2&gt;

&lt;p&gt;My top &lt;code&gt;needs_review&lt;/code&gt; files by edit count:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;~/bin/cc-loop&lt;/code&gt; — edited &lt;strong&gt;29 times&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;~/bin/devto-publish&lt;/code&gt; — edited &lt;strong&gt;17 times&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;~/bin/tweet-post&lt;/code&gt; — edited &lt;strong&gt;19 times&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;~/.claude/hooks/proof-log-session.sh&lt;/code&gt; — edited &lt;strong&gt;6 times&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The AI kept improving its own tooling. That's the interesting part.&lt;/p&gt;

&lt;p&gt;None of these changes caused problems. But that's because I was reviewing them (eventually). The queue just makes the reviewing systematic instead of accidental.&lt;/p&gt;

&lt;h2&gt;
  
  
  Part of cc-toolkit
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;cc-review-queue&lt;/code&gt; is part of &lt;a href="https://yurukusa.github.io/cc-toolkit/" rel="noopener noreferrer"&gt;cc-toolkit&lt;/a&gt; — all free, zero dependencies, local.&lt;/p&gt;

&lt;p&gt;The full oversight picture:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Tool&lt;/th&gt;
&lt;th&gt;What it shows&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://github.com/yurukusa/cc-review-queue" rel="noopener noreferrer"&gt;cc-review-queue&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Files AI touched that need review&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://github.com/yurukusa/cc-session-stats" rel="noopener noreferrer"&gt;cc-session-stats&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Total hours, sessions, autonomy ratio&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://github.com/yurukusa/cc-heatmap" rel="noopener noreferrer"&gt;cc-ai-heatmap&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;52-week activity visualization&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://github.com/yurukusa/cc-standup" rel="noopener noreferrer"&gt;cc-standup&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Daily standup from AI's work log&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;p&gt;More on Claude Code safety: &lt;a href="https://github.com/yurukusa/cc-safe-setup" rel="noopener noreferrer"&gt;cc-safe-setup on GitHub&lt;/a&gt;&lt;/p&gt;

</description>
      <category>claudecode</category>
      <category>ai</category>
      <category>devtools</category>
      <category>productivity</category>
    </item>
    <item>
      <title>Claude Code Safety in 5 Minutes: A Beginner's Complete Guide</title>
      <dc:creator>Yurukusa</dc:creator>
      <pubDate>Thu, 09 Apr 2026 03:00:02 +0000</pubDate>
      <link>https://dev.to/yurukusa/claude-code-safety-in-5-minutes-a-beginners-complete-guide-5bf2</link>
      <guid>https://dev.to/yurukusa/claude-code-safety-in-5-minutes-a-beginners-complete-guide-5bf2</guid>
      <description>&lt;p&gt;You gave Claude Code full access to your terminal. It can run any command, edit any file, push to any branch.&lt;/p&gt;

&lt;p&gt;What could go wrong?&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/anthropics/claude-code/issues/36339" rel="noopener noreferrer"&gt;A lot, actually.&lt;/a&gt; One user lost their entire &lt;code&gt;C:\Users&lt;/code&gt; directory. Another had their &lt;code&gt;.bashrc&lt;/code&gt; overwritten. Someone else watched Claude force-push to &lt;code&gt;main&lt;/code&gt; at 3am.&lt;/p&gt;

&lt;p&gt;These aren't hypotheticals — they're real GitHub Issues.&lt;/p&gt;

&lt;p&gt;Here's how to prevent all of them in 5 minutes.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 1: Install Safety Hooks (30 seconds)
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx cc-safe-setup
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's it. One command installs 890+ example hooks that intercept dangerous commands &lt;strong&gt;before&lt;/strong&gt; they execute:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Hook&lt;/th&gt;
&lt;th&gt;What it blocks&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;destructive-guard&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;rm -rf /&lt;/code&gt;, &lt;code&gt;git reset --hard&lt;/code&gt;, &lt;code&gt;git clean -fd&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;branch-guard&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Push to &lt;code&gt;main&lt;/code&gt;/&lt;code&gt;master&lt;/code&gt;, force-push&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;secret-guard&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;git add .env&lt;/code&gt;, credential files&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;syntax-check&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Catches broken Python/JS/JSON after edits&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;context-monitor&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Warns when context window is filling up&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;comment-strip&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Fixes bash comments breaking permissions&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;cd-git-allow&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Auto-approves safe &lt;code&gt;cd &amp;amp;&amp;amp; git log&lt;/code&gt; compounds&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;api-error-alert&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Notifies when sessions die from API errors&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Step 2: Verify It Works (30 seconds)
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx cc-safe-setup &lt;span class="nt"&gt;--verify&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This sends test inputs to each hook and confirms they block correctly:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;destructive-guard&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="s"&gt;✓ rm -rf / → BLOCKED&lt;/span&gt;
  &lt;span class="s"&gt;✓ rm -rf node_modules → ALLOWED&lt;/span&gt;
&lt;span class="na"&gt;branch-guard&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="s"&gt;✓ git push origin main → BLOCKED&lt;/span&gt;
  &lt;span class="s"&gt;✓ git push origin feature → ALLOWED&lt;/span&gt;
&lt;span class="nn"&gt;...&lt;/span&gt;
&lt;span class="s"&gt;8/890+ example hooks verified&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 3: Check Your Setup Health (30 seconds)
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx cc-safe-setup &lt;span class="nt"&gt;--quickfix&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This auto-detects and fixes common problems:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Missing &lt;code&gt;jq&lt;/code&gt; (hooks need it for JSON parsing)&lt;/li&gt;
&lt;li&gt;Broken file permissions&lt;/li&gt;
&lt;li&gt;Invalid &lt;code&gt;settings.json&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Missing shebang lines&lt;/li&gt;
&lt;li&gt;Broken hook references&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Step 4: Add Hooks for Your Stack (2 minutes)
&lt;/h2&gt;

&lt;p&gt;Browse 330+ example hooks:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx cc-safe-setup &lt;span class="nt"&gt;--examples&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Install any by name:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# If you use databases&lt;/span&gt;
npx cc-safe-setup &lt;span class="nt"&gt;--install-example&lt;/span&gt; block-database-wipe

&lt;span class="c"&gt;# If you use Docker&lt;/span&gt;
npx cc-safe-setup &lt;span class="nt"&gt;--install-example&lt;/span&gt; auto-approve-docker

&lt;span class="c"&gt;# If you deploy&lt;/span&gt;
npx cc-safe-setup &lt;span class="nt"&gt;--install-example&lt;/span&gt; deploy-guard

&lt;span class="c"&gt;# If you want to prevent scope creep&lt;/span&gt;
npx cc-safe-setup &lt;span class="nt"&gt;--install-example&lt;/span&gt; scope-guard
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or generate a custom hook from plain English:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx cc-safe-setup &lt;span class="nt"&gt;--create&lt;/span&gt; &lt;span class="s2"&gt;"block npm publish without running tests first"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 5: Monitor (optional, 1 minute)
&lt;/h2&gt;

&lt;p&gt;See your safety dashboard:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx cc-safe-setup &lt;span class="nt"&gt;--dashboard&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Check what's been blocked:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx cc-safe-setup &lt;span class="nt"&gt;--stats&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  How Hooks Actually Work
&lt;/h2&gt;

&lt;p&gt;Claude Code has a &lt;a href="https://docs.anthropic.com/en/docs/claude-code/hooks" rel="noopener noreferrer"&gt;hooks system&lt;/a&gt; that runs shell scripts at specific lifecycle points:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;PreToolUse&lt;/strong&gt; — before any tool runs (Bash, Edit, Write)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;PostToolUse&lt;/strong&gt; — after a tool completes&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Stop&lt;/strong&gt; — when Claude finishes responding&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A hook that exits with code &lt;code&gt;2&lt;/code&gt; &lt;strong&gt;blocks&lt;/strong&gt; the action. The model cannot bypass this — it's enforced at the process level, not the prompt level.&lt;/p&gt;

&lt;p&gt;This is the key difference from CLAUDE.md rules: rules degrade as context fills up. Hooks run every single time.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# What a hook looks like (simplified)&lt;/span&gt;
&lt;span class="c"&gt;#!/bin/bash&lt;/span&gt;
&lt;span class="nv"&gt;COMMAND&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;cat&lt;/span&gt; | jq &lt;span class="nt"&gt;-r&lt;/span&gt; &lt;span class="s1"&gt;'.tool_input.command // empty'&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$COMMAND&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; | &lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-qE&lt;/span&gt; &lt;span class="s1"&gt;'rm\s+.*-rf\s+/'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
  &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"BLOCKED: rm -rf on root directory"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&amp;amp;2
  &lt;span class="nb"&gt;exit &lt;/span&gt;2  &lt;span class="c"&gt;# Block the action&lt;/span&gt;
&lt;span class="k"&gt;fi
&lt;/span&gt;&lt;span class="nb"&gt;exit &lt;/span&gt;0  &lt;span class="c"&gt;# Allow the action&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Common Questions
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Q: Do hooks slow down Claude Code?&lt;/strong&gt;&lt;br&gt;
No. Each hook runs in ~5ms. You won't notice.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Q: Can Claude disable hooks?&lt;/strong&gt;&lt;br&gt;
No. Hooks are enforced by the Claude Code runtime, not the model. Even if Claude tries to edit &lt;code&gt;settings.json&lt;/code&gt;, the &lt;code&gt;protect-claudemd&lt;/code&gt; hook can block that too.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Q: What about CLAUDE.md — isn't that enough?&lt;/strong&gt;&lt;br&gt;
CLAUDE.md rules work well at the start of a session. But as context fills up (after 100+ tool calls), Claude gradually "forgets" them. Hooks never forget.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Q: I use TypeScript/Python — are there hooks for those?&lt;/strong&gt;&lt;br&gt;
Yes. Check out &lt;a href="https://www.npmjs.com/package/cc-hook-registry" rel="noopener noreferrer"&gt;&lt;code&gt;cc-hook-registry&lt;/code&gt;&lt;/a&gt; which indexes hooks from 7 different projects, including TypeScript and Python implementations.&lt;/p&gt;

&lt;h2&gt;
  
  
  Try It Now
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx cc-safe-setup &lt;span class="nt"&gt;--shield&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;One command. Thirty seconds. Your autonomous Claude Code sessions are now protected against the most common disasters.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Interactive playground&lt;/strong&gt;: &lt;a href="https://yurukusa.github.io/cc-hook-registry/playground.html" rel="noopener noreferrer"&gt;Test commands against hooks&lt;/a&gt; — type any command and see which hooks would fire.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Full hook registry&lt;/strong&gt;: &lt;a href="https://yurukusa.github.io/cc-hook-registry/" rel="noopener noreferrer"&gt;Browse 349+ hooks&lt;/a&gt; from 7 projects.&lt;/p&gt;




&lt;p&gt;More on Claude Code safety: &lt;a href="https://github.com/yurukusa/cc-safe-setup" rel="noopener noreferrer"&gt;cc-safe-setup on GitHub&lt;/a&gt;&lt;/p&gt;

</description>
      <category>claudecode</category>
      <category>ai</category>
      <category>safety</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Which Files Does Your Claude Code Keep Rewriting? I Built a Tool to Find Out</title>
      <dc:creator>Yurukusa</dc:creator>
      <pubDate>Wed, 08 Apr 2026 03:00:04 +0000</pubDate>
      <link>https://dev.to/yurukusa/which-files-does-your-claude-code-keep-rewriting-i-built-a-tool-to-find-out-g30</link>
      <guid>https://dev.to/yurukusa/which-files-does-your-claude-code-keep-rewriting-i-built-a-tool-to-find-out-g30</guid>
      <description>&lt;h2&gt;
  
  
  The Question I Kept Asking
&lt;/h2&gt;

&lt;p&gt;After 60+ days running Claude Code autonomously, I noticed a pattern I couldn't quantify: some files felt like they were getting rewritten constantly. My game's &lt;code&gt;dungeon_game.py&lt;/code&gt; seemed to be in a perpetual state of flux. But was I imagining it?&lt;/p&gt;

&lt;p&gt;Turns out, I wasn't. The top file in my sessions had &lt;strong&gt;933 total tool calls&lt;/strong&gt; — 669 writes, 264 reads.&lt;/p&gt;

&lt;p&gt;I needed a way to see this clearly. So I built &lt;strong&gt;cc-file-churn&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  What cc-file-churn Does
&lt;/h2&gt;

&lt;p&gt;It scans your &lt;code&gt;~/.claude&lt;/code&gt; session logs and ranks every file by how much Claude Code has touched it — broken down by writes (Edit/Write), reads (Read), and searches (Grep/Glob).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx cc-file-churn
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Output looks like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cc-file-churn — top 10 files by total activity (all time)

#1  ~/.claude/plans/staged-hatching-backus.md
    ████████████████████ 933  (w:669 r:264 s:0)

#2  ~/projects/aetheria/dungeon_game.py
    ██████████████████░░ 671  (w:301 r:290 s:80)

#3  ~/projects/cc-loop/cc-toolkit/index.html
    ████████░░░░░░░░░░░░ 312  (w:189 r:123 s:0)

...

755 session files · 2219 unique files · 12476 tool calls
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The bars aren't just decorative. They show exactly where the churn is concentrated.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I Found Surprising
&lt;/h2&gt;

&lt;p&gt;My most-churned file wasn't source code — it was a &lt;strong&gt;planning document&lt;/strong&gt; (&lt;code&gt;staged-hatching-backus.md&lt;/code&gt;). Claude Code had written it 669 times and read it 264 times. That's the AI checking and updating its own work plan.&lt;/p&gt;

&lt;p&gt;Second place was &lt;code&gt;dungeon_game.py&lt;/code&gt;. That one I expected. But the ratio was interesting: roughly equal reads and writes, meaning the AI was reading the file as much as editing it. Understanding context before making changes.&lt;/p&gt;

&lt;p&gt;Third place was &lt;code&gt;cc-toolkit/index.html&lt;/code&gt; — the landing page for this whole tool collection. Heavily written, rarely read. Makes sense for a file that keeps getting cards added to it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Filtering Options
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Top 10 files by write count (most modified)&lt;/span&gt;
npx cc-file-churn &lt;span class="nt"&gt;--writes&lt;/span&gt;

&lt;span class="c"&gt;# Top 10 files by read count (most referenced)&lt;/span&gt;
npx cc-file-churn &lt;span class="nt"&gt;--reads&lt;/span&gt;

&lt;span class="c"&gt;# Last 7 days only&lt;/span&gt;
npx cc-file-churn &lt;span class="nt"&gt;--days&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;7

&lt;span class="c"&gt;# Filter to a specific project&lt;/span&gt;
npx cc-file-churn &lt;span class="nt"&gt;--project&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;cc-loop

&lt;span class="c"&gt;# JSON output for piping&lt;/span&gt;
npx cc-file-churn &lt;span class="nt"&gt;--json&lt;/span&gt; | jq &lt;span class="s1"&gt;'.[0]'&lt;/span&gt;

&lt;span class="c"&gt;# Show top 20 instead of 10&lt;/span&gt;
npx cc-file-churn 20
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Browser Version
&lt;/h2&gt;

&lt;p&gt;If you prefer not to install anything:&lt;/p&gt;

&lt;p&gt;→ &lt;strong&gt;&lt;a href="https://yurukusa.github.io/cc-file-churn/" rel="noopener noreferrer"&gt;yurukusa.github.io/cc-file-churn&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Drag in your &lt;code&gt;~/.claude&lt;/code&gt; folder. Everything runs locally — nothing uploaded.&lt;/p&gt;

&lt;p&gt;The browser version adds filter buttons (All activity / Most-modified / Most-referenced) and shows progress bars with percentage breakdowns.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why This Matters
&lt;/h2&gt;

&lt;p&gt;High churn files reveal a lot:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Planning files with high write counts&lt;/strong&gt;: The AI is actively managing its own state&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Source files with balanced read/write&lt;/strong&gt;: Normal iterative development&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Source files with much higher writes than reads&lt;/strong&gt;: Possibly unstable design being constantly patched&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Config files with high reads, low writes&lt;/strong&gt;: Reference files the AI checks frequently&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Test files with low churn&lt;/strong&gt;: Either tests are stable (good) or being neglected (check this)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Once you know which files are getting churned, you can ask: &lt;em&gt;Is this churn productive?&lt;/em&gt; Sometimes a file with 300 writes means good iterative improvement. Sometimes it means the AI is spinning in circles.&lt;/p&gt;

&lt;h2&gt;
  
  
  Part of cc-toolkit
&lt;/h2&gt;

&lt;p&gt;cc-file-churn is one of 100+ tools in &lt;a href="https://yurukusa.github.io/cc-toolkit/" rel="noopener noreferrer"&gt;cc-toolkit&lt;/a&gt; — all free, for understanding your Claude Code usage.&lt;/p&gt;

&lt;p&gt;Other tools in the same vein:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://yurukusa.github.io/cc-context-check/" rel="noopener noreferrer"&gt;cc-context-check&lt;/a&gt; — How full is your context window right now?&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/yurukusa/cc-tool-mix" rel="noopener noreferrer"&gt;cc-tool-mix&lt;/a&gt; — What percentage of Claude's calls are reads vs writes vs searches?&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://yurukusa.github.io/cc-wrapped/" rel="noopener noreferrer"&gt;cc-wrapped&lt;/a&gt; — Your full Claude Code year in review&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;&lt;em&gt;Built from 60+ days of running Claude Code 24/7 in tmux. All tools are free, zero dependencies, data stays local.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;GitHub&lt;/strong&gt;: &lt;a href="https://github.com/yurukusa/cc-file-churn" rel="noopener noreferrer"&gt;yurukusa/cc-file-churn&lt;/a&gt;&lt;br&gt;
&lt;strong&gt;Try it&lt;/strong&gt;: &lt;code&gt;npx cc-file-churn&lt;/code&gt;&lt;/p&gt;




&lt;p&gt;More on Claude Code safety: &lt;a href="https://github.com/yurukusa/cc-safe-setup" rel="noopener noreferrer"&gt;cc-safe-setup on GitHub&lt;/a&gt;&lt;/p&gt;

</description>
      <category>claudecode</category>
      <category>ai</category>
      <category>productivity</category>
      <category>devtools</category>
    </item>
    <item>
      <title>5 CLAUDE.md Rules That Made My AI Stop Asking and Start Doing</title>
      <dc:creator>Yurukusa</dc:creator>
      <pubDate>Tue, 07 Apr 2026 03:00:01 +0000</pubDate>
      <link>https://dev.to/yurukusa/5-claudemd-rules-that-made-my-ai-stop-asking-and-start-doing-43e1</link>
      <guid>https://dev.to/yurukusa/5-claudemd-rules-that-made-my-ai-stop-asking-and-start-doing-43e1</guid>
      <description>&lt;p&gt;After months of running Claude Code autonomously, I've learned that most of the interruptions aren't the AI's fault. They're the CLAUDE.md's fault.&lt;/p&gt;

&lt;p&gt;Here are 5 rules that eliminated most of my "should I do X?" questions.&lt;/p&gt;




&lt;h2&gt;
  
  
  1. The irreversibility rule (not the uncertainty rule)
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;What most CLAUDE.mds say:&lt;/strong&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Ask for clarification when uncertain."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;What actually works:&lt;/strong&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Ask only for: irreversible actions, external credentials, external visibility (publishing, sending emails), costs beyond the subscription."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The difference is significant. Uncertainty is constant — every decision has unknowns. Irreversibility is rare — most code changes can be reverted with &lt;code&gt;git reset&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;When I switched from "ask when uncertain" to "ask only when irreversible," the question count dropped dramatically. 80%? Maybe. I didn't measure precisely, but it &lt;em&gt;felt&lt;/em&gt; like a different AI.&lt;/p&gt;




&lt;h2&gt;
  
  
  2. Explicit decision framework for common forks
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;What most CLAUDE.mds say:&lt;/strong&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Use your judgment."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;What actually works:&lt;/strong&gt;&lt;/p&gt;

&lt;blockquote&gt;

&lt;pre class="highlight plaintext"&gt;&lt;code&gt;| Situation | Action |
|-----------|--------|
| Technical approach unclear | Choose the conventional approach |
| Two valid implementations | Choose the simpler one |
| Error after 3 attempts | Document in blocked.md, switch tasks |
| Ambiguous requirement | Apply most reasonable interpretation, document assumption |
&lt;/code&gt;&lt;/pre&gt;

&lt;/blockquote&gt;

&lt;p&gt;The AI already has good judgment. The table isn't teaching it to think — it's eliminating the meta-question of "should I ask or should I decide?" By stating explicitly that "unclear approach → conventional approach," that decision is pre-made.&lt;/p&gt;




&lt;h2&gt;
  
  
  3. The pending_for_human.md pattern
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;What stops most workflows:&lt;/strong&gt; A step that requires browser authentication, or a credential I don't have. Without a clear protocol, the AI either loops on it or silently skips it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What works:&lt;/strong&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"If blocked: document blocker in &lt;code&gt;pending_for_human.md&lt;/code&gt;, switch to next available task."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The format I use:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="gu"&gt;## 2026-02-28: Smithery API key needed&lt;/span&gt;
&lt;span class="gs"&gt;**Why blocked**&lt;/span&gt;: Smithery MCP registry requires authentication
&lt;span class="gs"&gt;**Steps for human**&lt;/span&gt;:
&lt;span class="p"&gt;1.&lt;/span&gt; Go to smithery.ai/account/api-keys
&lt;span class="p"&gt;2.&lt;/span&gt; Create API key, add to ~/.credentials
&lt;span class="gs"&gt;**Everything else done**&lt;/span&gt;: smithery.yaml added to repo, package published to npm
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The key is the last line: "everything else done." The human opens this file in the morning and sees exactly one click they need to do.&lt;/p&gt;




&lt;h2&gt;
  
  
  4. Explicit syntax check commands
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;What most CLAUDE.mds say:&lt;/strong&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Make sure the code works."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;What actually works:&lt;/strong&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"After every edit: Python → &lt;code&gt;python -m py_compile &amp;lt;file&amp;gt;&lt;/code&gt;. TypeScript → &lt;code&gt;tsc --noEmit&lt;/code&gt;. Do not move to the next file before fixing errors in the current one."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The "do not move to the next file" part is what matters. Without it, the AI writes 5 files, runs the build, finds 3 errors spread across all of them, and has to context-switch back to each one. With it, each file is clean before the next one starts.&lt;/p&gt;

&lt;p&gt;This is the same reason you do &lt;code&gt;git add -p&lt;/code&gt; instead of &lt;code&gt;git add .&lt;/code&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  5. Context compression protocol
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;What kills autonomous sessions:&lt;/strong&gt; Running out of context window mid-task and starting over.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What works:&lt;/strong&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"When context gets large: write current state to &lt;code&gt;tasks/mission.md&lt;/code&gt;. Include: what's done, what's next, what's blocked, any open questions. The next session should be able to continue from &lt;code&gt;tasks/mission.md&lt;/code&gt; without reading the full history."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The mission.md should be written as if explaining to someone who knows the project but wasn't in the room. Not a transcript. Not a summary. A briefing.&lt;/p&gt;

&lt;p&gt;This creates a natural "checkpoint" that makes context compaction safe.&lt;/p&gt;




&lt;h2&gt;
  
  
  What these have in common
&lt;/h2&gt;

&lt;p&gt;All 5 rules do the same thing: &lt;strong&gt;convert vague expectations into specific protocols.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;"Use judgment" forces a meta-decision. "Choose the simpler one" eliminates it. Every meta-decision costs context window and interruption. Eliminating meta-decisions is what makes autonomous operation actually work.&lt;/p&gt;

&lt;p&gt;The hooks and templates I run in production are open source: &lt;a href="https://github.com/yurukusa/cc-safe-setup" rel="noopener noreferrer"&gt;cc-safe-setup&lt;/a&gt; — 16 hooks (at the time of writing; now 667) + 6 templates from 700+ hours of autonomous operation (at the time of writing).&lt;/p&gt;

&lt;p&gt;More on autonomous Claude Code operation: &lt;a href="https://zenn.dev/yurukusa/books/6076c23b1cb18b" rel="noopener noreferrer"&gt;Safety Guide on Zenn&lt;/a&gt; (chapters 1-3 free).&lt;/p&gt;




&lt;p&gt;What's in your CLAUDE.md that you wish you'd added earlier?&lt;/p&gt;

</description>
      <category>claudecode</category>
      <category>productivity</category>
      <category>ai</category>
      <category>devtools</category>
    </item>
    <item>
      <title>6 Claude Code Permission Traps I Found Answering GitHub Issues This Week</title>
      <dc:creator>Yurukusa</dc:creator>
      <pubDate>Mon, 06 Apr 2026 03:00:05 +0000</pubDate>
      <link>https://dev.to/yurukusa/6-claude-code-permission-traps-i-found-answering-github-issues-this-week-3ja2</link>
      <guid>https://dev.to/yurukusa/6-claude-code-permission-traps-i-found-answering-github-issues-this-week-3ja2</guid>
      <description>&lt;p&gt;My AI (Claude Code) answered 57 GitHub Issues this week about Claude Code permissions not working as expected. Here are the 6 patterns that keep tripping people up — and the hooks that fix them.&lt;/p&gt;

&lt;h2&gt;
  
  
  Trap 1: &lt;code&gt;allow&lt;/code&gt; Cancels &lt;code&gt;ask&lt;/code&gt; (17 Upvotes, 18 Comments)
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"permissions"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"allow"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"Bash(*)"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"ask"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"Bash(rm *)"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Expected: safe commands auto-approve, &lt;code&gt;rm&lt;/code&gt; asks first.&lt;br&gt;
Actual: &lt;strong&gt;everything auto-approves. &lt;code&gt;ask&lt;/code&gt; is silently ignored.&lt;/strong&gt; (&lt;a href="https://github.com/anthropics/claude-code/issues/6527" rel="noopener noreferrer"&gt;#6527&lt;/a&gt;)&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Fix:&lt;/strong&gt; A PreToolUse hook catches what &lt;code&gt;ask&lt;/code&gt; misses:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;#!/bin/bash&lt;/span&gt;
&lt;span class="nv"&gt;COMMAND&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;cat&lt;/span&gt; | jq &lt;span class="nt"&gt;-r&lt;/span&gt; &lt;span class="s1"&gt;'.tool_input.command // empty'&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$COMMAND&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; | &lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-qE&lt;/span&gt; &lt;span class="s1"&gt;'rm\s+(-[rf]+\s+)*(\/|~|\.\./)'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
    &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"BLOCKED: rm on sensitive path"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&amp;amp;2
    &lt;span class="nb"&gt;exit &lt;/span&gt;2
&lt;span class="k"&gt;fi
&lt;/span&gt;&lt;span class="nb"&gt;exit &lt;/span&gt;0
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Trap 2: Trailing Wildcards Don't Match Zero Arguments
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"permissions"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"allow"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"Bash(ssh * uptime *)"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;ssh host uptime -s&lt;/code&gt; → allowed. &lt;code&gt;ssh host uptime&lt;/code&gt; → &lt;strong&gt;prompts.&lt;/strong&gt; The trailing &lt;code&gt;*&lt;/code&gt; requires at least one character. (&lt;a href="https://github.com/anthropics/claude-code/issues/36873" rel="noopener noreferrer"&gt;#36873&lt;/a&gt;)&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Fix:&lt;/strong&gt; Use regex &lt;code&gt;(\s|$)&lt;/code&gt; in a hook — matches "space or end of string":&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$COMMAND&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; | &lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-qE&lt;/span&gt; &lt;span class="s1"&gt;'^\s*ssh\s+\S+\s+uptime(\s|$)'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then&lt;/span&gt;
    &lt;span class="c"&gt;# auto-approve&lt;/span&gt;
&lt;span class="k"&gt;fi&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Trap 3: Edit/Write Rules Ignored on Windows
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;Edit(.claude/**)&lt;/code&gt; in settings.json has no effect on Windows VS Code. Bash rules work fine — Edit/Write don't. (&lt;a href="https://github.com/anthropics/claude-code/issues/36884" rel="noopener noreferrer"&gt;#36884&lt;/a&gt;)&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Fix:&lt;/strong&gt; A PermissionRequest hook bypasses the broken matcher:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;TOOL&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;cat&lt;/span&gt; | jq &lt;span class="nt"&gt;-r&lt;/span&gt; &lt;span class="s1"&gt;'.tool_name // empty'&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[[&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$TOOL&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s2"&gt;"Edit"&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$TOOL&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s2"&gt;"Write"&lt;/span&gt; &lt;span class="o"&gt;]]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
    &lt;/span&gt;jq &lt;span class="nt"&gt;-n&lt;/span&gt; &lt;span class="s1"&gt;'{"hookSpecificOutput":{"hookEventName":"PermissionRequest","permissionDecision":"allow"}}'&lt;/span&gt;
&lt;span class="k"&gt;fi&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Trap 4: Protected Directories Ignore bypassPermissions
&lt;/h2&gt;

&lt;p&gt;Since v2.1.78, &lt;code&gt;.git&lt;/code&gt;, &lt;code&gt;.claude&lt;/code&gt;, &lt;code&gt;.vscode&lt;/code&gt; prompt even with &lt;code&gt;--dangerously-skip-permissions&lt;/code&gt;. Intentional but undocumented. (&lt;a href="https://github.com/anthropics/claude-code/issues/35646" rel="noopener noreferrer"&gt;#35646&lt;/a&gt;)&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Fix:&lt;/strong&gt; Anthropic confirmed a fix is incoming.&lt;/p&gt;

&lt;h2&gt;
  
  
  Trap 5: /model Doesn't Update /status Immediately
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;/model&lt;/code&gt; changes the model for future API calls, but &lt;code&gt;/status&lt;/code&gt; shows the old one. (&lt;a href="https://github.com/anthropics/claude-code/issues/36835" rel="noopener noreferrer"&gt;#36835&lt;/a&gt;)&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Fix:&lt;/strong&gt; Send a new message after &lt;code&gt;/model&lt;/code&gt;, or set via environment:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;ANTHROPIC_MODEL&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;claude-opus-4-6
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Trap 6: Claude Adds Flags Your Pattern Doesn't Expect
&lt;/h2&gt;

&lt;p&gt;You allow &lt;code&gt;Bash(git status:*)&lt;/code&gt;. Claude runs &lt;code&gt;git -C /path status&lt;/code&gt;. The &lt;code&gt;-C&lt;/code&gt; flag breaks your pattern. (&lt;a href="https://github.com/anthropics/claude-code/issues/36900" rel="noopener noreferrer"&gt;#36900&lt;/a&gt;)&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Fix:&lt;/strong&gt; Match the optional flag in a hook:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$COMMAND&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; | &lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-qE&lt;/span&gt; &lt;span class="s1"&gt;'^\s*git\s+(-C\s+\S+\s+)?(status|log|diff|branch|show)'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then&lt;/span&gt;
    &lt;span class="c"&gt;# auto-approve&lt;/span&gt;
&lt;span class="k"&gt;fi&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Your hook returns &lt;code&gt;permissionDecision: "deny"&lt;/code&gt; with exit code 2. For Bash commands, the tool is blocked. For Edit/Write — the file is modified anyway. (&lt;a href="https://github.com/anthropics/claude-code/issues/37210" rel="noopener noreferrer"&gt;#37210&lt;/a&gt;)&lt;br&gt;
&lt;strong&gt;Fix:&lt;/strong&gt; Defense-in-depth — make the file read-only before the deny:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[[&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$TOOL&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s2"&gt;"Edit"&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$TOOL&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s2"&gt;"Write"&lt;/span&gt; &lt;span class="o"&gt;]]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
    if &lt;/span&gt;should_deny &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$FILE&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
        &lt;/span&gt;&lt;span class="nb"&gt;chmod &lt;/span&gt;444 &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$FILE&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; 2&amp;gt;/dev/null
        &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"BLOCKED: Edit denied by policy"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&amp;amp;2
        &lt;span class="nb"&gt;exit &lt;/span&gt;2
    &lt;span class="k"&gt;fi
fi&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  The Pattern
&lt;/h2&gt;

&lt;p&gt;6 out of 7 traps have the same fix: &lt;strong&gt;PreToolUse hooks.&lt;/strong&gt; The permission system has edge cases. Hooks operate independently and don't have them.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx cc-safe-setup
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;890+ example hooks (at the time of writing). 10 seconds to install. Covers destructive commands, force push, &lt;code&gt;.env&lt;/code&gt; leaks, syntax errors, and context monitoring.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/yurukusa/cc-safe-setup" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Every trap in this list came from a real GitHub Issue that my AI responded to. If you've hit a permission problem not listed here, drop a comment — I'll add it.&lt;/em&gt;&lt;/p&gt;




&lt;p&gt;More on Claude Code hooks and safety patterns: &lt;a href="https://zenn.dev/yurukusa/articles/3f12923e298c43" rel="noopener noreferrer"&gt;How hooks work under the hood&lt;/a&gt;&lt;/p&gt;

</description>
      <category>claudecode</category>
      <category>ai</category>
      <category>devtools</category>
      <category>opensource</category>
    </item>
    <item>
      <title>I Built a GitHub-Style Contribution Calendar That Shows When My AI Works Without Me</title>
      <dc:creator>Yurukusa</dc:creator>
      <pubDate>Sun, 05 Apr 2026 03:00:02 +0000</pubDate>
      <link>https://dev.to/yurukusa/i-built-a-github-style-contribution-calendar-that-shows-when-my-ai-works-without-me-1k7</link>
      <guid>https://dev.to/yurukusa/i-built-a-github-style-contribution-calendar-that-shows-when-my-ai-works-without-me-1k7</guid>
      <description>&lt;p&gt;GitHub's contribution calendar shows when you coded. But what if half those green squares weren't actually you?&lt;/p&gt;

&lt;p&gt;I built &lt;code&gt;cc-calendar&lt;/code&gt; — a terminal tool that renders a GitHub-style activity graph for your Claude Code sessions. Two rows: &lt;strong&gt;YOU&lt;/strong&gt; (cyan) and &lt;strong&gt;AI&lt;/strong&gt; (yellow). Ghost Days — when AI ran autonomously while you had zero interactive sessions — glow bright.&lt;/p&gt;

&lt;h2&gt;
  
  
  The output
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;npx cc-calendar
&lt;span class="go"&gt;
  cc-calendar  — AI草カレンダー
  ══════════════════════════════════════════════════

       Jan         Feb         Mar
Sun  ░░░░░▒░░░  Sun  ░▒▒▒▓█▓█▒
Mon  ░░░░░░░░░  Mon  ░▒▒▒▓██▓░
Tue  ░░░░░▒░░░  Tue  ░▒▒▒▒▓▓▓░
Wed  ░░░░▒░░░░  Wed  ░▒▓▒▒▓▓▓░
Thu  ░░░░░░██░  Thu  ░▓▒▒▒▒▓▒░
Fri  ░░░░░░█░░  Fri  ░▒░█▒▒▓▒░
Sat  ░░░░▒░░█░  Sat  ▒░░▒▓▒▓█░

  █ You  █ AI  █ Ghost Day  ░▒▓█ = none→light→heavy

  ▸ Period:      2026-01-10 → 2026-03-01
  ▸ Active Days: 48 total
  ├─ Both active:    8 days
  ├─ You only:       0 days
  └─ Ghost Days:     40 days (AI worked while you rested)

  Your hours:  46.5h
  AI hours:    83.3h

  👻 40 Ghost Days — AI was 83% of your active days
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Those bright yellow cells on the right? Ghost Days. The AI was running autonomous subagent pipelines — publishing npm packages, writing articles, updating GitHub Pages — while I was offline.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why I built this
&lt;/h2&gt;

&lt;p&gt;I already had &lt;a href="https://www.npmjs.com/package/cc-agent-load" rel="noopener noreferrer"&gt;&lt;code&gt;cc-agent-load&lt;/code&gt;&lt;/a&gt; which shows the YOU/AI split as aggregate numbers. But a single ratio doesn't tell the story. You can't see &lt;em&gt;when&lt;/em&gt; the AI was working without you, or whether it was a sustained pattern.&lt;/p&gt;

&lt;p&gt;The contribution calendar format solves this immediately. Engineers are trained to read GitHub contribution graphs at a glance. Same interface, new dimension.&lt;/p&gt;

&lt;h2&gt;
  
  
  How it works
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;cc-calendar&lt;/code&gt; reads from &lt;code&gt;cc-agent-load --json&lt;/code&gt;, which outputs session data by date:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"byDate"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"2026-02-09"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"main"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"sub"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;6.0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"2026-02-10"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"main"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;1.5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"sub"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;2.3&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For each day:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;main&lt;/code&gt; = hours in interactive sessions (you + AI responding to you)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;sub&lt;/code&gt; = hours in autonomous subagent sessions (AI running without you)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Ghost Day = &lt;code&gt;main === 0 &amp;amp;&amp;amp; sub &amp;gt; 0&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The calendar renders 26 weeks with GitHub-style block characters:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;░&lt;/code&gt; light (&amp;lt; 1h)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;▒&lt;/code&gt; medium (1-4h)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;▓&lt;/code&gt; heavy (4h+)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;█&lt;/code&gt; intense (4h+)&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Zero dependencies
&lt;/h2&gt;

&lt;p&gt;No npm packages. Just Node.js 18+. Reads &lt;code&gt;~/.claude/projects/&lt;/code&gt; transcript files directly.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx cc-calendar
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  What 40 Ghost Days means
&lt;/h2&gt;

&lt;p&gt;Out of 48 active days in my log, 40 were AI-only. That's 83%.&lt;/p&gt;

&lt;p&gt;The pattern is: I have an interactive session, set something in motion, then go to sleep. The AI keeps running — finishing tasks, publishing packages, updating docs. Next morning I check the results.&lt;/p&gt;

&lt;p&gt;It's not a problem to fix. It's the intended design. But seeing it visualized makes it concrete.&lt;/p&gt;

&lt;p&gt;The 8 "both active" days were when I was in the middle of something large and the AI was running parallel tasks.&lt;/p&gt;

&lt;p&gt;The 0 "you only" days means I never worked without AI support. Every interactive session had some autonomous component.&lt;/p&gt;

&lt;h2&gt;
  
  
  Related tools
&lt;/h2&gt;

&lt;p&gt;This tool is part of the &lt;code&gt;cc-toolkit&lt;/code&gt; collection:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://www.npmjs.com/package/cc-agent-load" rel="noopener noreferrer"&gt;&lt;code&gt;cc-agent-load&lt;/code&gt;&lt;/a&gt; — source data (run this first)&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://yurukusa.github.io/cc-ghost-log/" rel="noopener noreferrer"&gt;&lt;code&gt;cc-ghost-log&lt;/code&gt;&lt;/a&gt; — see git commits from Ghost Days&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://yurukusa.github.io/cc-session-stats/" rel="noopener noreferrer"&gt;&lt;code&gt;cc-session-stats&lt;/code&gt;&lt;/a&gt; — total usage overview&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;All 106 free tools: &lt;a href="https://yurukusa.github.io/cc-toolkit/" rel="noopener noreferrer"&gt;cc-toolkit&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;More on Claude Code safety: &lt;a href="https://github.com/yurukusa/cc-safe-setup" rel="noopener noreferrer"&gt;cc-safe-setup on GitHub&lt;/a&gt;&lt;/p&gt;

</description>
      <category>claudecode</category>
      <category>ai</category>
      <category>javascript</category>
      <category>opensource</category>
    </item>
    <item>
      <title>5 Lines of Code That Made My Roguelike Worth Playing Every Day</title>
      <dc:creator>Yurukusa</dc:creator>
      <pubDate>Sat, 04 Apr 2026 03:00:05 +0000</pubDate>
      <link>https://dev.to/yurukusa/5-lines-of-code-that-made-my-roguelike-worth-playing-every-day-3klj</link>
      <guid>https://dev.to/yurukusa/5-lines-of-code-that-made-my-roguelike-worth-playing-every-day-3klj</guid>
      <description>&lt;p&gt;In v0.10.0, I gave every run in my roguelike a name.&lt;/p&gt;

&lt;p&gt;In v0.11.0, I gave every &lt;em&gt;day&lt;/em&gt; a run.&lt;/p&gt;




&lt;h2&gt;
  
  
  The problem with Endless Mode
&lt;/h2&gt;

&lt;p&gt;When I shipped Endless Mode (v0.9.9), I added this line to the result screen:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;"Post your Endless score in itch.io comments!"&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;It was a bet that players would naturally turn the comment section into a leaderboard.&lt;/p&gt;

&lt;p&gt;The problem: no two runs are the same. When one player posts "I survived Wave 27 as a Chain Annihilator," there's nothing for another player to compare against. They ran a different map, got different upgrade choices, faced different enemy patterns.&lt;/p&gt;

&lt;p&gt;The itch.io comment section wasn't a leaderboard. It was just a list of unrelated accomplishments.&lt;/p&gt;




&lt;h2&gt;
  
  
  What makes a leaderboard work
&lt;/h2&gt;

&lt;p&gt;A leaderboard needs a fixed variable.&lt;/p&gt;

&lt;p&gt;In golf, the course is fixed. Players compete on the same 18 holes. The comparison is valid because the challenge is identical.&lt;/p&gt;

&lt;p&gt;In Wordle, the word is fixed. Every player gets the same puzzle. The only variable is the number of guesses.&lt;/p&gt;

&lt;p&gt;In my roguelike, nothing was fixed. Random seed on every run, random on every refresh.&lt;/p&gt;

&lt;p&gt;The fix was obvious once I saw it: &lt;strong&gt;use the date as the seed&lt;/strong&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  The implementation
&lt;/h2&gt;

&lt;p&gt;Every run in Spell Cascade uses Godot's global random number generator for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Enemy type selection (&lt;code&gt;randi() % pool&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Enemy spawn positions (&lt;code&gt;randf_range()&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Upgrade choices (&lt;code&gt;array.shuffle()&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Elite enemy probability (&lt;code&gt;randf() &amp;lt; elite_chance&lt;/code&gt;)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;All of this feeds from the same global state. If you set that state at the start of a run, everything that follows is deterministic.&lt;/p&gt;

&lt;p&gt;Here's the complete implementation:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight gdscript"&gt;&lt;code&gt;&lt;span class="c1"&gt;# title.gd — Daily Challenge button handler&lt;/span&gt;
&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;_on_daily&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;void&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;_transitioning&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt;
    &lt;span class="n"&gt;_transitioning&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;true&lt;/span&gt;
    &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;date&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Dictionary&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get_date_dict_from_system&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;seed_base&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;date&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;year&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;10000&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;date&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;month&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;date&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;day&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;daily_seed&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;seed_base&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;31337&lt;/span&gt;  &lt;span class="c1"&gt;# prime number distribution&lt;/span&gt;
    &lt;span class="n"&gt;Engine&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;set_meta&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"daily_challenge_seed"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;daily_seed&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;scene&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;PackedScene&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;load&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"res://scenes/game.tscn"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;get_tree&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;change_scene_to_packed&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;scene&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight gdscript"&gt;&lt;code&gt;&lt;span class="c1"&gt;# game_main.gd — seed setup on game load&lt;/span&gt;
&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;_ready&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;void&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;Engine&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;has_meta&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"daily_challenge_seed"&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;daily_seed&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Engine&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get_meta&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"daily_challenge_seed"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="nb"&gt;seed&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;daily_seed&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;is_daily_challenge&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;true&lt;/span&gt;
        &lt;span class="n"&gt;Engine&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;remove_meta&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"daily_challenge_seed"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's the core of it. The &lt;code&gt;seed()&lt;/code&gt; call sets Godot's global RNG state. Every &lt;code&gt;randi()&lt;/code&gt;, &lt;code&gt;randf()&lt;/code&gt;, and &lt;code&gt;array.shuffle()&lt;/code&gt; that follows is now deterministic.&lt;/p&gt;

&lt;p&gt;The Engine metadata pattern handles the title-to-game scene transition without an autoload singleton: set the value before the scene change, read and delete it immediately on load.&lt;/p&gt;




&lt;h2&gt;
  
  
  What 2026-02-21 looks like
&lt;/h2&gt;

&lt;p&gt;On February 21, 2026, the seed is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;20260221 × 31337 = 634,601,577
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Every player who clicks "Daily Challenge 02/21" that day gets:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The same first three enemies&lt;/li&gt;
&lt;li&gt;The same upgrade choices at level 2, 3, 4...&lt;/li&gt;
&lt;li&gt;The same elite enemy spawns&lt;/li&gt;
&lt;li&gt;The same boss trigger timing&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;What's different: their reaction time, their decision making, their skill execution.&lt;/p&gt;

&lt;p&gt;That's the game. The "map" is shared. The score is earned.&lt;/p&gt;




&lt;h2&gt;
  
  
  The social mechanic
&lt;/h2&gt;

&lt;p&gt;Within 24 hours of shipping this, the first daily challenge post appeared in the itch.io comments. Not just a score — a debrief.&lt;/p&gt;

&lt;p&gt;"Got to Wave 19 as Chain Annihilator. Nearly had Endless but the splitter wave at 8:30 got me."&lt;/p&gt;

&lt;p&gt;That post is meaningful to other players in a way that never was before. They played the same 8:30 splitter wave. They know exactly what it was like. They can compare.&lt;/p&gt;

&lt;p&gt;One comment about a specific wave is now a shared reference point for everyone who played that day.&lt;/p&gt;




&lt;h2&gt;
  
  
  The philosophy of daily challenges
&lt;/h2&gt;

&lt;p&gt;Daily challenges work because they solve a social coordination problem.&lt;/p&gt;

&lt;p&gt;Without a shared seed, comparing roguelike runs requires trusting in statistical similarity — "we both played the same difficulty &lt;em&gt;on average&lt;/em&gt;." That's a weak basis for competition.&lt;/p&gt;

&lt;p&gt;With a shared seed, comparison is direct. "We both saw that splitter wave at 8:30" is a fact, not an approximation.&lt;/p&gt;

&lt;p&gt;The other thing daily challenges do: they create a natural reason to come back. Not "I want to get better" (vague) but "I haven't done today's yet" (specific, actionable, expiring).&lt;/p&gt;




&lt;h2&gt;
  
  
  What the AI contributed
&lt;/h2&gt;

&lt;p&gt;The idea came from reading about how Wordle drove its engagement loop. The implementation question — how to set a deterministic seed in Godot without breaking normal mode — was something I didn't know.&lt;/p&gt;

&lt;p&gt;Claude Code confirmed: &lt;code&gt;seed()&lt;/code&gt; sets the global state, so every downstream call inherits it. The Engine metadata pattern for passing data between scenes without a singleton was also its suggestion. Neither of these was obvious to me going in.&lt;/p&gt;

&lt;p&gt;What I brought: the observation that my comment section wasn't working as a leaderboard, and the theory that shared seeds would fix it. What Claude contributed: the two-line implementation that made it work.&lt;/p&gt;




&lt;h2&gt;
  
  
  Open question
&lt;/h2&gt;

&lt;p&gt;What's the right daily reset time?&lt;/p&gt;

&lt;p&gt;Right now it resets at local midnight. That means players in different timezones are technically playing "different days" starting at different moments. An argument for UTC midnight. But UTC midnight is 9am JST — too awkward for Japanese players to treat as a day boundary.&lt;/p&gt;

&lt;p&gt;I haven't solved this. Local date for now. If the player base ever gets large enough that timezone inconsistency matters, it'll become a real problem.&lt;/p&gt;

&lt;p&gt;For now: same date, same seed. If you're playing Feb 21, you're playing the Feb 21 run.&lt;/p&gt;




&lt;h2&gt;
  
  
  Play it
&lt;/h2&gt;

&lt;p&gt;Spell Cascade is free in the browser: &lt;a href="https://yurukusa.itch.io/spell-cascade" rel="noopener noreferrer"&gt;yurukusa.itch.io/spell-cascade&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you use Claude Code for development, here's how I keep it safe: &lt;a href="https://github.com/yurukusa/cc-safe-setup" rel="noopener noreferrer"&gt;cc-safe-setup&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;What wave did you reach today?&lt;/p&gt;

</description>
      <category>claudecode</category>
      <category>algorithms</category>
      <category>ai</category>
      <category>indiedev</category>
    </item>
    <item>
      <title>I Built an MCP Server So Claude Can Answer Questions About Its Own Usage</title>
      <dc:creator>Yurukusa</dc:creator>
      <pubDate>Fri, 03 Apr 2026 03:00:02 +0000</pubDate>
      <link>https://dev.to/yurukusa/i-built-an-mcp-server-so-claude-can-answer-questions-about-its-own-usage-2792</link>
      <guid>https://dev.to/yurukusa/i-built-an-mcp-server-so-claude-can-answer-questions-about-its-own-usage-2792</guid>
      <description>&lt;p&gt;Here's something that didn't exist until recently: you can ask Claude &lt;em&gt;how much Claude Code you've been using&lt;/em&gt;, and get a real answer backed by your actual data.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;You: "How much have I used Claude Code this month, and is my streak going to survive?"

Claude: "You've logged 47.3h interactive + 83.1h AI sub-agent work in March,
         for 130.4h total. You're on a 36-day streak with 22 Ghost Days.

         Based on your last 14 days, your streak is likely to survive —
         you've been active 100% of days this month."
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's &lt;code&gt;cc-mcp&lt;/code&gt;. An MCP server that gives Claude real-time access to your Claude Code usage stats.&lt;/p&gt;

&lt;h2&gt;
  
  
  The problem with analytics tools
&lt;/h2&gt;

&lt;p&gt;I've built 26 other Claude Code analytics tools. You run them, they print stats, you close the terminal. The knowledge doesn't go anywhere useful.&lt;/p&gt;

&lt;p&gt;What I wanted was for Claude to &lt;em&gt;know&lt;/em&gt; this information during a session. If I'm planning work with Claude, it should be able to factor in that I've already spent 8 hours in Claude Code today, that AI has been running autonomously for 3 hours while I was offline, and that my streak needs protecting.&lt;/p&gt;

&lt;p&gt;MCP makes this possible.&lt;/p&gt;

&lt;h2&gt;
  
  
  How it works
&lt;/h2&gt;

&lt;p&gt;Add to &lt;code&gt;claude_desktop_config.json&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"mcpServers"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"cc-toolkit"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"command"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"npx"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"args"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"@yurukusa/cc-mcp"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Restart Claude Desktop. Now you have four new tools:&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;code&gt;cc_usage_summary&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;Today / 7-day / month-to-date totals, current streak, and autonomy ratio.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Show me my Claude Code stats" → Claude calls this, gets structured data, responds naturally.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  &lt;code&gt;cc_daily_breakdown&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;Day-by-day activity for the last N days, with you vs AI split.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"When were my Ghost Days last week?" → Claude scans the breakdown, finds days where AI ran while you didn't.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  &lt;code&gt;cc_project_stats&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;Per-project time breakdown (top 15 by hours).&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Which project am I spending the most Claude Code time on?" → Claude looks at your project distribution.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  &lt;code&gt;cc_forecast&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;Month-end projection at your current pace.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Will I hit 700+ hours this month?" → Claude runs the projection and gives you the math.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Ghost Days
&lt;/h2&gt;

&lt;p&gt;One concept that comes up frequently in the data: &lt;strong&gt;Ghost Days&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;A Ghost Day is any day where AI sub-agents ran Claude Code autonomously — while you had zero interactive sessions. Your AI kept working while you were offline.&lt;/p&gt;

&lt;p&gt;When you ask Claude "what were my Ghost Days this month?", cc-mcp surfaces these automatically. It's a useful signal for understanding how much your AI pipeline runs unsupervised.&lt;/p&gt;

&lt;h2&gt;
  
  
  What makes this different from just running &lt;code&gt;cc-agent-load&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;When you run &lt;code&gt;npx cc-agent-load&lt;/code&gt;, you get a terminal output you read once and forget. When Claude has this data via MCP, it becomes part of the conversation:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Claude can proactively mention that your streak is at risk&lt;/li&gt;
&lt;li&gt;You can ask follow-up questions without re-running tools&lt;/li&gt;
&lt;li&gt;The data can inform Claude's recommendations ("Given you've already used 8h of AI time today, maybe we should keep this session focused")&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The data is the same. The difference is context persistence within the session.&lt;/p&gt;

&lt;h2&gt;
  
  
  Technical implementation
&lt;/h2&gt;

&lt;p&gt;The server is a Node.js ES module using the &lt;code&gt;@modelcontextprotocol/sdk&lt;/code&gt;. Each tool calls &lt;code&gt;cc-agent-load --json&lt;/code&gt; as a subprocess, parses the output, and returns both plain text (for display) and structured JSON (for downstream processing).&lt;/p&gt;

&lt;p&gt;Source: &lt;a href="https://github.com/yurukusa/cc-mcp" rel="noopener noreferrer"&gt;github.com/yurukusa/cc-mcp&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;No telemetry. No server. All computation happens locally — the MCP server runs on your machine, Claude calls it as a local process, data never leaves your environment.&lt;/p&gt;

&lt;h2&gt;
  
  
  Setup
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Install the data source&lt;/span&gt;
npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-g&lt;/span&gt; cc-agent-load

&lt;span class="c"&gt;# Run the MCP server directly (test it works)&lt;/span&gt;
npx @yurukusa/cc-mcp
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then add to your Claude Desktop config and restart.&lt;/p&gt;

&lt;p&gt;Works with Claude Desktop and any other MCP-compatible client.&lt;/p&gt;

&lt;h2&gt;
  
  
  Part of cc-toolkit
&lt;/h2&gt;

&lt;p&gt;cc-mcp is part of the &lt;a href="https://yurukusa.github.io/cc-toolkit/" rel="noopener noreferrer"&gt;cc-toolkit&lt;/a&gt; collection — 27 free tools for understanding your Claude Code usage.&lt;/p&gt;

&lt;p&gt;The full loop: &lt;strong&gt;Track&lt;/strong&gt; → &lt;strong&gt;Understand&lt;/strong&gt; → &lt;strong&gt;Predict&lt;/strong&gt; → &lt;strong&gt;Act&lt;/strong&gt; → &lt;strong&gt;Ask&lt;/strong&gt; (cc-mcp closes the loop back into Claude).&lt;/p&gt;




&lt;p&gt;More on Claude Code safety: &lt;a href="https://github.com/yurukusa/cc-safe-setup" rel="noopener noreferrer"&gt;cc-safe-setup on GitHub&lt;/a&gt;&lt;/p&gt;

</description>
      <category>mcp</category>
      <category>claudecode</category>
      <category>ai</category>
      <category>productivity</category>
    </item>
  </channel>
</rss>
