<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>Contains LLM-generated content on Olaf Alders</title><link>https://www.olafalders.com/categories/contains-llm-generated-content/</link><description>Recent content in Contains LLM-generated content on Olaf Alders</description><generator>Hugo -- gohugo.io</generator><language>en</language><managingEditor>olaf@wundersolutions.com (Olaf Alders)</managingEditor><webMaster>olaf@wundersolutions.com (Olaf Alders)</webMaster><copyright>© 2026 Olaf Alders</copyright><lastBuildDate>Fri, 17 Jul 2026 00:00:00 +0000</lastBuildDate><atom:link href="https://www.olafalders.com/categories/contains-llm-generated-content/index.xml" rel="self" type="application/rss+xml"/><item><title>Claude Code: Anatomy of a Misfeature</title><link>https://www.olafalders.com/2026/07/17/claude-code-anatomy-of-a-misfeature/</link><pubDate>Fri, 17 Jul 2026 00:00:00 +0000</pubDate><author>olaf@wundersolutions.com (Olaf Alders)</author><guid>https://www.olafalders.com/2026/07/17/claude-code-anatomy-of-a-misfeature/</guid><description>On Canada Day (July 1), 2026, Anthropic shipped a surprising "easter egg" to users of Claude Code: `2.1.198` includes an efficiency bypass which allows agents to continue on without being blocked on direction from a human.</description><content:encoded>&lt;!-- markdownlint-disable MD003 MD033 MD046 --&gt;
&lt;p&gt;&lt;a href="https://www.olafalders.com/2026/07/17/claude-code-anatomy-of-a-misfeature/featured.jpeg"&gt;&lt;img src="https://www.olafalders.com/2026/07/17/claude-code-anatomy-of-a-misfeature/featured.jpeg" alt="featured"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;!-- markdownlint-disable-line --&gt;&lt;p class="attribution"&gt;"&lt;a target="_blank" rel="noopener noreferrer" href="https://commons.wikimedia.org/wiki/File:Mechanical_egg_timer.jpg"&gt;Mechanical egg timer&lt;/a&gt;" by &lt;a target="_blank" rel="noopener noreferrer" href="https://commons.wikimedia.org/wiki/User:Hustvedt"&gt;Hustvedt&lt;/a&gt; is licensed under &lt;a target="_blank" rel="noopener noreferrer" href="https://creativecommons.org/licenses/by-sa/3.0/"&gt;CC BY-SA 3.0 &lt;img src="https://www.olafalders.com/img/cc/cc.svg" alt="" style="height: 1em;" /&gt;&lt;img src="https://www.olafalders.com/img/cc/by.svg" alt="" style="height: 1em;" /&gt;&lt;img src="https://www.olafalders.com/img/cc/sa.svg" alt="" style="height: 1em;" /&gt;&lt;/a&gt;. Padded to a wider frame; this adaptation is likewise licensed CC BY-SA 3.0.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Update, 2026-07-18:&lt;/strong&gt; There was some discussion about this post on &lt;a href="https://news.ycombinator.com/item?id=48947776"&gt;Hacker
News&lt;/a&gt;. A few commenters
dismissed the whole article as LLM-generated. It is most certainly not. I
write my own prose. However, the formatting and layout may have made that a
tempting conclusion to reach. I&amp;rsquo;ve now added special formatting to set off
the LLM-generated portions, so it should hopefully be obvious at this point
which parts were written by an actual human.&lt;/p&gt;
&lt;p&gt;I have left Claude&amp;rsquo;s analysis to stand on its own, but the surrounding prose is my own.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="what-happened"&gt;&lt;a class="heading-anchor" href="#what-happened" aria-label="Permalink to this section"&gt;#&lt;/a&gt;What Happened&lt;/h2&gt;
&lt;p&gt;On Canada Day (July 1), 2026, Anthropic shipped a surprising &amp;ldquo;easter egg&amp;rdquo; to
users of Claude Code: &lt;code&gt;2.1.198&lt;/code&gt; includes an efficiency bypass which allows
agents to continue on without being blocked on direction from a human. You
essentially get a 60 second timer after Claude Code asks for input. If you miss
the window, Claude Code helpfully does what it thinks is best and continues on
its way. It looks like this:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;● Claude asked:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ⎿ …
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ● No response after 60s — continued without an answer
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;● The user stepped away. I&amp;#39;ll proceed with best judgment. My plan:
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;em&gt;Note: the above is taken verbatim from one of my own &lt;code&gt;claude&lt;/code&gt; sessions, with the questions having been trimmed.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;If you find this behaviour surprising, you&amp;rsquo;re not alone. Let&amp;rsquo;s consider the possible consequences:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Do you have to take your laptop to the kitchen with you when you&amp;rsquo;re making a sandwich? What happens if you are afk during this window?&lt;/li&gt;
&lt;li&gt;How many agents are you running at once? Can you possibly observe them all at the same time? What if two or more agents ask for your input during the same 60 second window?&lt;/li&gt;
&lt;li&gt;What if the agent makes the wrong choice? How many tokens have been burned in the meantime?&lt;/li&gt;
&lt;li&gt;What if you are using agents for deployments? (Yes, I know, but &lt;em&gt;what if&lt;/em&gt;)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;These are reasonable things you might consider when shipping this feature and maybe you&amp;rsquo;d document your reasoning in the changelog. But what if you never mentioned the new defaults in the changelog at all? Wouldn&amp;rsquo;t that be even more surprising? (Spoiler: it was!)&lt;/p&gt;
&lt;p&gt;The story has a (sort of) happy ending. Move fast and break things does not necessarily preclude move fast and fix things. Within a couple of days a fix was shipped, but where does that leave user trust in this product?&lt;/p&gt;
&lt;p&gt;We&amp;rsquo;ve learned a few things:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Surprising features in Claude Code can in theory (and in practice) be shipped by Anthropic on a daily cadence&lt;/li&gt;
&lt;li&gt;Not every feature will necessarily appear in the changelog&lt;/li&gt;
&lt;li&gt;Things that should not be defaults may not have a documented off switch&lt;/li&gt;
&lt;li&gt;Claude Code&amp;rsquo;s auto update feature feels more like YOLO mode than we might have suspected early on&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;There are a few things I don&amp;rsquo;t know if we have learned:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;How do humans fit into this equation?&lt;/li&gt;
&lt;li&gt;Did a human dream up the feature?&lt;/li&gt;
&lt;li&gt;Did a human write (or have an agent write) this feature?&lt;/li&gt;
&lt;li&gt;Did a human review the feature?&lt;/li&gt;
&lt;li&gt;Did a human sign off on the feature?&lt;/li&gt;
&lt;li&gt;Did a human merge the feature?&lt;/li&gt;
&lt;li&gt;Did a human opt out of documenting the feature or adding it to the changelog?&lt;/li&gt;
&lt;li&gt;Did a human release manager diff the release with the previous release and give it their seal of approval before it went out the door?&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Personally I would find it hard to believe that a human was gating all of these
steps without asking &amp;ldquo;is this a good idea?&amp;rdquo;. If you told me that Claude Code
actually built the feature, shipped it, signed off on it and then deemed it
unworthy of documentation, that&amp;rsquo;s something I&amp;rsquo;m more inclined to believe, but I
just don&amp;rsquo;t know. Maybe it&amp;rsquo;s some combination of those two things. Maybe a
number of things went wrong, but I think it&amp;rsquo;s clear that this never should have
happened. And I say this as someone who has had at least one performance review
where my manager said &amp;ldquo;well, you did put a serious bug into production&amp;rdquo;.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;ve wondered a bit about how this happened and what kind of post-mortem is
available in the public record. So, I&amp;rsquo;ve asked Claude Code to investigate
itself. To Claude&amp;rsquo;s credit, it seems to have no filter that prevents
self-reflection regarding this code. So, full disclosure, what follows is
mostly Claude&amp;rsquo;s work, so take that for what it&amp;rsquo;s worth and if you rely on any
key assumptions, it&amp;rsquo;s worth reproducing them in isolation.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="claude-investigates"&gt;&lt;a class="heading-anchor" href="#claude-investigates" aria-label="Permalink to this section"&gt;#&lt;/a&gt;Claude Investigates&lt;/h2&gt;
&lt;p&gt;&lt;em&gt;Claude&amp;rsquo;s research begins here.&lt;/em&gt;&lt;/p&gt;
&lt;details class="llm-block" open&gt;
&lt;summary class="llm-block__bar"&gt;
&lt;svg class="llm-block__spark" width="13" height="13" viewBox="0 0 16 16" aria-hidden="true"&gt;&lt;path d="M8 0l1.7 5.4L15 7l-5.3 1.6L8 14l-1.7-5.4L1 7l5.3-1.6z"/&gt;&lt;/svg&gt;
&lt;span class="llm-block__label"&gt;Contains LLM-generated content&lt;/span&gt;
&lt;span class="llm-block__by"&gt;not written by Olaf&lt;/span&gt;
&lt;span class="llm-block__toggle" aria-hidden="true"&gt;&lt;/span&gt;
&lt;/summary&gt;
&lt;div class="llm-block__body"&gt;
&lt;span class="llm-block__gutter" aria-hidden="true" style="background-image:url(&amp;#39;data:image/svg&amp;#43;xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNiIgaGVpZ2h0PSIyNDgiPjx0ZXh0IHRyYW5zZm9ybT0idHJhbnNsYXRlKDExIDI0OCkgcm90YXRlKC05MCkiIGZvbnQtZmFtaWx5PSJ1aS1tb25vc3BhY2UsIFNGTW9uby1SZWd1bGFyLCBNZW5sbywgbW9ub3NwYWNlIiBmb250LXNpemU9IjkuNSIgbGV0dGVyLXNwYWNpbmc9IjIiIGZpbGw9IiNiYjlhZjciIGZpbGwtb3BhY2l0eT0iMC41IiB4bWw6c3BhY2U9InByZXNlcnZlIj5SZXNlYXJjaCBieSBDbGF1ZGUgT3B1cyA0LjggwrcgPC90ZXh0Pjwvc3ZnPg==&amp;#39;)"&gt;&lt;/span&gt;
&lt;h3 id="timeline"&gt;&lt;a class="heading-anchor" href="#timeline" aria-label="Permalink to this section"&gt;#&lt;/a&gt;Timeline&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;2026-06-29&lt;/strong&gt; — &lt;code&gt;2.1.196&lt;/code&gt; released; the reporter&amp;rsquo;s &amp;ldquo;last working version (I am guessing)&amp;rdquo;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;2026-06-30&lt;/strong&gt; — &lt;code&gt;2.1.197&lt;/code&gt; released; one changelog line, the Sonnet 5 launch&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;2026-07-01&lt;/strong&gt; — &lt;strong&gt;&lt;code&gt;2.1.198&lt;/code&gt; released — the version the reporter pins the regression to.&lt;/strong&gt; No public commit shows the change; the only public trace of this release is the bot commit publishing its notes (&lt;a href="https://github.com/anthropics/claude-code/commit/75709eacf1334051ea293fb87a0e88a1e6812f94"&gt;&lt;code&gt;75709ea&lt;/code&gt;&lt;/a&gt;), which touches nothing but &lt;code&gt;CHANGELOG.md&lt;/code&gt; and &lt;code&gt;feed.xml&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;2026-07-02 02:54 UTC&lt;/strong&gt; — issue &lt;a href="https://github.com/anthropics/claude-code/issues/73125"&gt;#73125&lt;/a&gt; filed by &lt;a href="https://github.com/ANogin"&gt;Aleksey Nogin&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;2026-07-02 03:45 UTC&lt;/strong&gt; — &lt;a href="https://github.com/noxasaxon"&gt;a commenter&lt;/a&gt; &lt;a href="https://github.com/anthropics/claude-code/issues/73125#issuecomment-4861995993"&gt;surfaces the escape hatch&lt;/a&gt;: &lt;code&gt;CLAUDE_AFK_TIMEOUT_MS&lt;/code&gt;. Traded peer-to-peer in the thread, not pointed to from any release note&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;2026-07-02&lt;/strong&gt; — &lt;code&gt;2.1.199&lt;/code&gt; ships 24 entries while the issue is open. Still no mention.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;2026-07-03&lt;/strong&gt; — &lt;code&gt;2.1.200&lt;/code&gt; reverses the behaviour; again the only public trace is the notes commit (&lt;a href="https://github.com/anthropics/claude-code/commit/1322e9bacc9fdb575812add107c9421dfbff592b"&gt;&lt;code&gt;1322e9b&lt;/code&gt;&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;2026-07-04 18:04 UTC&lt;/strong&gt; — issue closed&lt;/li&gt;
&lt;li&gt;Reaction/scale on the issue: &lt;strong&gt;384 👍&lt;/strong&gt;, &lt;strong&gt;143 comments&lt;/strong&gt; — not a niche complaint&lt;/li&gt;
&lt;li&gt;Reporter&amp;rsquo;s environment: &lt;code&gt;2.1.198&lt;/code&gt;, &amp;ldquo;last working &lt;code&gt;2.1.196&lt;/code&gt; (guessing)&amp;rdquo;, Opus, AWS Bedrock, VS Code terminal&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;git clone https://github.com/anthropics/claude-code.git
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;cd&lt;/span&gt; claude-code
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# When did the fix land, and in which version?&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;git log -1 --format&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;%h %ai&amp;#39;&lt;/span&gt; -S&lt;span class="s1"&gt;&amp;#39;no longer auto-continue by default&amp;#39;&lt;/span&gt; -- CHANGELOG.md
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# 1322e9ba 2026-07-03 16:52:26 +0000&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# When did the version that shipped the bug land?&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;git log -1 --format&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;%h %ai&amp;#39;&lt;/span&gt; -S&lt;span class="s1"&gt;&amp;#39;## 2.1.198&amp;#39;&lt;/span&gt; -- CHANGELOG.md
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# 75709eac 2026-07-01 20:45:29 +0000&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="the-misfeature"&gt;&lt;a class="heading-anchor" href="#the-misfeature" aria-label="Permalink to this section"&gt;#&lt;/a&gt;The misfeature&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;AskUserQuestion&lt;/code&gt; is the tool Claude Code uses to stop and ask the human a question mid-task&lt;/li&gt;
&lt;li&gt;New behaviour: after &lt;strong&gt;60 seconds of inactivity&lt;/strong&gt;, the tool auto-returns a &amp;ldquo;proceed anyway&amp;rdquo; result instead of blocking&lt;/li&gt;
&lt;li&gt;The message handed back to the model — this is the template, rendered here at the 60-second default:&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-js" data-lang="js"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// v2.1.198, verbatim. `Thl` is the minifier&amp;#39;s name; the prose is the binary&amp;#39;s own.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// Note &amp;#34;60s&amp;#34; is interpolated, not a literal in the file:
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;Thl&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="sb"&gt;`No response after &lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;round&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sb"&gt;s — the user may be
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sb"&gt;away from keyboard. Proceed using your best judgment based on the context so far;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sb"&gt;you can re-ask this question later if it&amp;#39;s still relevant.`&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;
&lt;li&gt;The &amp;ldquo;re-ask later&amp;rdquo; escape hatch is circular: the re-asked question hits the same timeout. Aleksey Nogin made this point in the issue thread within minutes of filing it&lt;/li&gt;
&lt;li&gt;The transcript line has &lt;strong&gt;two variants&lt;/strong&gt; — the binary picks between them on whether you&amp;rsquo;d started answering:&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-js" data-lang="js"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// v2.1.198, verbatim. `a` is the minifier&amp;#39;s name for &amp;#34;some answers exist&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// (`s=Object.entries(r)` over the answers, `a=s.length&amp;gt;0`); both string values
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// are the binary&amp;#39;s own.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;d&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;continued with the answers selected so far&amp;#34;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;continued without an answer&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;
&lt;li&gt;So a half-answered dialog does not discard the partial input — it &lt;strong&gt;submits it&lt;/strong&gt;. Answer question one of three, step away, and the timeout commits your one answer plus whatever the model picks for the other two&lt;/li&gt;
&lt;li&gt;Both strings are absent from &lt;code&gt;2.1.197&lt;/code&gt; and present in &lt;code&gt;2.1.198&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;In fairness: it was not silent on screen.&lt;/strong&gt; The dialog rendered a live countdown, and a keypress restarted the timer. Assembled at runtime rather than stored as one string, so this is the rendered form, not a literal grep hit:&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-js" data-lang="js"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// v2.1.198, verbatim — the pieces. `s` is the remaining-seconds value.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nx"&gt;children&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;auto-continue in &amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;s \xB7 any key to stay&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// renders as: auto-continue in 12s · any key to stay
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;
&lt;li&gt;Which cuts less far than it looks. The countdown only reaches someone watching the screen, and the premise of the feature is that you aren&amp;rsquo;t:
&lt;ul&gt;
&lt;li&gt;the internal name is &lt;strong&gt;AFK&lt;/strong&gt;; the message says &amp;ldquo;the user may be away from keyboard&amp;rdquo;&lt;/li&gt;
&lt;li&gt;running several agents at once, &amp;ldquo;watching the screen&amp;rdquo; is not one place — the countdown you needed was on another tab&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;And the countdown is late. The threshold defaults to &lt;strong&gt;20 seconds&lt;/strong&gt; (&lt;code&gt;CLAUDE_AFK_COUNTDOWN_MS&lt;/code&gt;), and it gates on remaining time, not elapsed — so for the first &lt;strong&gt;40 seconds&lt;/strong&gt; the dialog looks like an ordinary blocking question. It is on screen, but nothing on it says a timer is running:&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-js" data-lang="js"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// v2.1.198 ships this minified — the locals are mangled, but the property
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// names survive, so `showCountdown` and `remainingSeconds` are its own words:
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;u&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;=&lt;/span&gt;&lt;span class="nx"&gt;n&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;remainingSeconds&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nx"&gt;showCountdown&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="nx"&gt;u&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nx"&gt;timeoutMs&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="nx"&gt;t&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// ...which reads, with n at its default of 20000:
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nx"&gt;showCountdown&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;remainingSeconds&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="mi"&gt;20000&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;
&lt;li&gt;The warning arrives in the last third&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;What it does not touch:&lt;/strong&gt; the timeout applies only to &lt;code&gt;AskUserQuestion&lt;/code&gt;. Anthropic&amp;rsquo;s &lt;a href="https://code.claude.com/docs/en/tools-reference"&gt;tools reference&lt;/a&gt; says &lt;em&gt;&amp;ldquo;permission prompts, including plan approval, never auto-resolve on idle&amp;rdquo;&lt;/em&gt; — and unlike the docs claims elsewhere in this post, this one is checkable against the shipped &lt;code&gt;2.1.198&lt;/code&gt; code rather than a page written after the fix:
&lt;ul&gt;
&lt;li&gt;the countdown component (&lt;code&gt;q0m&lt;/code&gt;) has &lt;strong&gt;exactly one call site&lt;/strong&gt; in the entire bundle, and its timer hook (&lt;code&gt;_Rc&lt;/code&gt;) has exactly one caller — &lt;code&gt;q0m&lt;/code&gt; itself. The timer exists in one component&lt;/li&gt;
&lt;li&gt;that component&amp;rsquo;s props identify it past argument: &lt;code&gt;jsx(dRc,{question:V, questions:s, currentQuestionIndex:$, answers:R, questionStates:O, onAnswer:be, onSubmit:N, …})&lt;/code&gt;. Its timeout handler is what fires &lt;code&gt;tengu_ask_user_question_afk_auto_advance&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;the permission prompt (&lt;code&gt;Do you want to proceed&lt;/code&gt;, &lt;code&gt;Do you want to allow …&lt;/code&gt;) is a separate component with no timer attached&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;But the exemption only protects you if a permission prompt appears at all.&lt;/strong&gt; &lt;code&gt;2.1.198&lt;/code&gt; ships &lt;code&gt;bypassPermissions&lt;/code&gt;, &lt;code&gt;acceptEdits&lt;/code&gt;, &lt;code&gt;allowedTools&lt;/code&gt;, &lt;code&gt;--dangerously-skip-permissions&lt;/code&gt; and &lt;code&gt;PreToolUse&lt;/code&gt; hooks. Anyone running agents against deployments has plausibly allowlisted the deploy command or turned prompts off — that is what automating it &lt;em&gt;means&lt;/em&gt;. For them the permission layer was never going to fire, so its immunity to the timer buys nothing&lt;/li&gt;
&lt;li&gt;The narrower claim, and the one that bites: &lt;strong&gt;the timer could not grant permission, but it could make the choice.&lt;/strong&gt; &lt;code&gt;AskUserQuestion&lt;/code&gt; doesn&amp;rsquo;t ask permission, it asks you to decide — &amp;ldquo;staging or production?&amp;rdquo;, &amp;ldquo;which config?&amp;rdquo; On timeout the model is told to &lt;code&gt;proceed using your best judgment&lt;/code&gt;, and the partial-answers path continues &amp;ldquo;with the answers selected so far&amp;rdquo;. If permission was already granted by allowlist or bypass, the choice was the only gate left&lt;/li&gt;
&lt;li&gt;No &lt;code&gt;timeout&lt;/code&gt; parameter exists in the tool schema — the model can neither set nor control it. Verified in the binary (&lt;code&gt;U_f=…H.strictObject({questions:…})&lt;/code&gt;), not taken from the issue thread. The input params are only:&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;questions, answers, annotations, metadata
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;
&lt;li&gt;So the model is truthful when it says it didn&amp;rsquo;t skip anything — the &lt;em&gt;harness&lt;/em&gt; returned the answer, not the model&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="the-fix"&gt;&lt;a class="heading-anchor" href="#the-fix" aria-label="Permalink to this section"&gt;#&lt;/a&gt;The fix&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;2.1.200&lt;/code&gt; made auto-continue &lt;strong&gt;off by default&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Idle timeout is now &lt;strong&gt;opt-in via &lt;code&gt;/config&lt;/code&gt;&lt;/strong&gt;, not forced on everyone&lt;/li&gt;
&lt;li&gt;Note the changelog&amp;rsquo;s verb: &lt;em&gt;&amp;ldquo;no longer auto-continue &lt;strong&gt;by default&lt;/strong&gt;&amp;rdquo;&lt;/em&gt;. Nothing was removed — the default flipped.&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;/config&lt;/code&gt; setting the note points you to &lt;strong&gt;did not exist before the fix&lt;/strong&gt;. Grep &lt;code&gt;2.1.198&lt;/code&gt; for &lt;code&gt;askUserQuestionTimeout&lt;/code&gt; and you get zero hits: when this shipped, the only way to escape it was an env var — and the release notes never named it.&lt;/li&gt;
&lt;li&gt;You can confirm the rest in the current binary (&lt;code&gt;2.1.211&lt;/code&gt;, eleven releases later). The machinery is entirely intact:
&lt;ul&gt;
&lt;li&gt;the setting is &lt;code&gt;askUserQuestionTimeout&lt;/code&gt;, surfaced in &lt;code&gt;/config&lt;/code&gt; as &lt;strong&gt;&amp;ldquo;Question auto-continue timeout&amp;rdquo;&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;accepted values are &lt;code&gt;60s&lt;/code&gt;, &lt;code&gt;5m&lt;/code&gt;, &lt;code&gt;10m&lt;/code&gt;, &lt;code&gt;never&lt;/code&gt; — and unset resolves to &lt;code&gt;never&lt;/code&gt;, which is what makes it opt-in&lt;/li&gt;
&lt;li&gt;the hook&amp;rsquo;s default timeout constant is still &lt;code&gt;60000&lt;/code&gt;; the countdown threshold is &lt;code&gt;20000&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;two&lt;/strong&gt; env vars still override the setting — &lt;code&gt;CLAUDE_AFK_TIMEOUT_MS&lt;/code&gt; and &lt;code&gt;CLAUDE_AFK_COUNTDOWN_MS&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;So the fix is a one-line change in a gate, not a deletion:&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-js" data-lang="js"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// v2.1.211, verbatim — only whitespace added. `Upf` is the minifier&amp;#39;s name for it;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// everything else here is the binary&amp;#39;s own, string values included.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;Upf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt; &lt;span class="k"&gt;switch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;60s&amp;#34;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="mi"&gt;60000&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;5m&amp;#34;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="mi"&gt;300000&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;10m&amp;#34;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="mi"&gt;600000&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;never&amp;#34;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// ^^^^^^^^^^^^ unset =&amp;gt; null =&amp;gt; disabled
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;
&lt;li&gt;Fair reading: this is the &lt;em&gt;right&lt;/em&gt; fix. Opt-in is what it should have been on day one, and the capability is legitimately useful to someone.&lt;/li&gt;
&lt;li&gt;Less comfortable reading: the same code that auto-answered for you is still shipping, one config value away, governed by the same process that turned it on silently the first time.&lt;/li&gt;
&lt;li&gt;Pre-fix stopgap (from the thread), for anyone pinned to an affected version:&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-jsonc" data-lang="jsonc"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// settings.json — disable the auto-continue by setting a huge AFK window
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s2"&gt;&amp;#34;env&amp;#34;&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;CLAUDE_AFK_TIMEOUT_MS&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;&amp;lt;massive number&amp;gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;
&lt;li&gt;Turnaround was fast — roughly two days from report to reversal (credit where due)&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="which-release-shipped-it--and-what-the-notes-said"&gt;&lt;a class="heading-anchor" href="#which-release-shipped-it--and-what-the-notes-said" aria-label="Permalink to this section"&gt;#&lt;/a&gt;Which release shipped it — and what the notes said&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Two places publish release notes: the &lt;a href="https://code.claude.com/docs/en/changelog"&gt;official changelog&lt;/a&gt; and &lt;a href="https://github.com/anthropics/claude-code/blob/main/CHANGELOG.md"&gt;&lt;code&gt;CHANGELOG.md&lt;/code&gt;&lt;/a&gt; in the repo (same content)&lt;/li&gt;
&lt;li&gt;Links below are pinned to commit &lt;code&gt;1322e9b&lt;/code&gt; so they show what the notes said at the time, not as edited later&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/anthropics/claude-code/blob/1322e9bacc9fdb575812add107c9421dfbff592b/CHANGELOG.md#21197"&gt;&lt;code&gt;2.1.197&lt;/code&gt;&lt;/a&gt; changelog: &lt;strong&gt;one line&lt;/strong&gt;, Claude Sonnet 5 launch. Nothing about question timeouts.&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/anthropics/claude-code/blob/1322e9bacc9fdb575812add107c9421dfbff592b/CHANGELOG.md#21198"&gt;&lt;code&gt;2.1.198&lt;/code&gt;&lt;/a&gt; changelog: &lt;strong&gt;~30 entries&lt;/strong&gt;. Nothing about &lt;code&gt;AskUserQuestion&lt;/code&gt; auto-continuing.&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/anthropics/claude-code/blob/1322e9bacc9fdb575812add107c9421dfbff592b/CHANGELOG.md#21199"&gt;&lt;code&gt;2.1.199&lt;/code&gt;&lt;/a&gt; changelog: &lt;strong&gt;24 entries&lt;/strong&gt;, published while the issue was already open. Still nothing.&lt;/li&gt;
&lt;li&gt;The 60s auto-continue was never announced in any release note when it was &lt;em&gt;added&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;AskUserQuestion&lt;/code&gt; is not a stranger to the changelog — it appears 15 times across 13 versions, going back to &lt;code&gt;2.0.55&lt;/code&gt;. It is a tool Anthropic documents changes to, routinely:&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;git show 1322e9b:CHANGELOG.md &lt;span class="p"&gt;|&lt;/span&gt; grep -c &lt;span class="s1"&gt;&amp;#39;AskUserQuestion&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# 15&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;git show 1322e9b:CHANGELOG.md &lt;span class="p"&gt;|&lt;/span&gt; awk &lt;span class="s1"&gt;&amp;#39;/^## /{v=$2} /AskUserQuestion/{print v}&amp;#39;&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt; sort -u &lt;span class="p"&gt;|&lt;/span&gt; tr &lt;span class="s1"&gt;&amp;#39;\n&amp;#39;&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39; &amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# 2.0.55 2.1.136 2.1.141 2.1.144 2.1.147 2.1.181 2.1.200 2.1.47 2.1.69 2.1.70 2.1.83 2.1.85 2.1.9&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;
&lt;li&gt;Which makes the gap the story. Between &lt;strong&gt;&lt;code&gt;2.1.181&lt;/code&gt;&lt;/strong&gt; and &lt;strong&gt;&lt;code&gt;2.1.200&lt;/code&gt;&lt;/strong&gt; — the window containing the change — it appears &lt;strong&gt;nowhere&lt;/strong&gt;. The behaviour changed twice, on and then off, and the notes record only the second&lt;/li&gt;
&lt;li&gt;The &lt;strong&gt;only&lt;/strong&gt; changelog line that ever mentions the auto-continue is the one that &lt;em&gt;removes&lt;/em&gt; it, in &lt;a href="https://github.com/anthropics/claude-code/blob/1322e9bacc9fdb575812add107c9421dfbff592b/CHANGELOG.md#21200"&gt;&lt;code&gt;2.1.200&lt;/code&gt;&lt;/a&gt;:&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;## 2.1.200
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;- Changed `AskUserQuestion` dialogs to no longer auto-continue by default;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; opt into an idle timeout via `/config`
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;
&lt;li&gt;The controlling env var &lt;code&gt;CLAUDE_AFK_TIMEOUT_MS&lt;/code&gt; appears &lt;strong&gt;nowhere&lt;/strong&gt; in the changelog or README&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="the-docs-caught-up-afterwards"&gt;&lt;a class="heading-anchor" href="#the-docs-caught-up-afterwards" aria-label="Permalink to this section"&gt;#&lt;/a&gt;The docs caught up. Afterwards.&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Today, both env vars &lt;strong&gt;are&lt;/strong&gt; documented, in the &lt;a href="https://code.claude.com/docs/en/env-vars"&gt;environment variables reference&lt;/a&gt;. The entry is candid about the episode:&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;CLAUDE_AFK_TIMEOUT_MS — How many milliseconds of idle time before an unanswered
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;AskUserQuestion dialog auto-continues without you. Auto-continue is off by
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;default; opt in with the askUserQuestionTimeout setting. [...] In v2.1.198 and
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;v2.1.199, auto-continue was on by default with a 60000 (60 seconds) timeout.
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;But that text cannot be what was there on 1 July&lt;/strong&gt;, and the binary says so on its own: it points you to &lt;code&gt;askUserQuestionTimeout&lt;/code&gt; as the opt-in, and that setting has &lt;strong&gt;zero&lt;/strong&gt; occurrences in the &lt;code&gt;2.1.198&lt;/code&gt; binary. It also narrates &lt;code&gt;2.1.198&lt;/code&gt; and &lt;code&gt;2.1.199&lt;/code&gt; in the past tense, as a closed range&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;And the Wayback Machine settles it outright.&lt;/strong&gt; The docs have no public repo, so I assumed their past was unknowable. It isn&amp;rsquo;t — the page is archived, repeatedly, straight through the window:&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# every archived capture of the env var reference, 23 Jun - 11 Jul 2026&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;curl -s &lt;span class="s2"&gt;&amp;#34;https://web.archive.org/cdx/search/cdx?url=code.claude.com/docs/en/env-vars\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s2"&gt;&amp;amp;output=json&amp;amp;filter=statuscode:200&amp;amp;fl=timestamp&amp;amp;from=20260601&amp;amp;to=20260718&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# fetch each one and count mentions of the feature&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# (DISABLE_AUTOUPDATER is the control: it should hit on every capture)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;for&lt;/span&gt; ts in &lt;span class="m"&gt;20260623083334&lt;/span&gt; &lt;span class="m"&gt;20260701121132&lt;/span&gt; &lt;span class="m"&gt;20260701213540&lt;/span&gt; 20260705135805&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; curl -s &lt;span class="s2"&gt;&amp;#34;https://web.archive.org/web/&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;ts&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;id_/https://code.claude.com/docs/en/env-vars&amp;#34;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;|&lt;/span&gt; gunzip -c &lt;span class="p"&gt;|&lt;/span&gt; grep -c -i &lt;span class="s1"&gt;&amp;#39;CLAUDE_AFK&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;done&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;capture (UTC)&lt;/th&gt;
&lt;th&gt;&lt;code&gt;CLAUDE_AFK&lt;/code&gt;&lt;/th&gt;
&lt;th&gt;&lt;code&gt;AskUserQuestion&lt;/code&gt;&lt;/th&gt;
&lt;th&gt;&lt;code&gt;DISABLE_AUTOUPDATER&lt;/code&gt; (control)&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;23 Jun&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;1 Jul 12:11&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;0&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;0&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;1 Jul 21:35&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;0&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;0&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;5 Jul&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;2.1.198&lt;/code&gt; was published to npm at &lt;code&gt;2026-07-01T16:50:16Z&lt;/code&gt;.&lt;/strong&gt; The 21:35 capture is &lt;strong&gt;four hours and forty-five minutes later&lt;/strong&gt; — and the page does not mention the feature under any name: not &lt;code&gt;afk&lt;/code&gt;, not &lt;code&gt;auto-continue&lt;/code&gt;, not &lt;code&gt;AskUserQuestion&lt;/code&gt;, not &lt;code&gt;COUNTDOWN&lt;/code&gt;. (&lt;code&gt;idle&lt;/code&gt; appears twice, both unrelated: &lt;code&gt;API_FORCE_IDLE_TIMEOUT&lt;/code&gt; and the MCP tool timeout.) The control hits on every capture, so this is absence, not a broken grep&lt;/li&gt;
&lt;li&gt;So the two questions collapse into one answer. On the day it shipped, the feature was in &lt;strong&gt;neither&lt;/strong&gt; the release notes &lt;strong&gt;nor&lt;/strong&gt; the docs. There was no channel through which a user could have been told&lt;/li&gt;
&lt;li&gt;The documentation appears between 1 July 21:35 and 5 July 13:58 — a window containing the &lt;code&gt;2.1.200&lt;/code&gt; reversal (&lt;code&gt;2026-07-03T04:33:49Z&lt;/code&gt;). And the entry that shows up describes auto-continue as &lt;strong&gt;&amp;ldquo;off by default&amp;rdquo;&lt;/strong&gt;, which was only true &lt;em&gt;after&lt;/em&gt; the fix. The docs never described the world as it actually was on 1 and 2 July. They arrived with the reversal and documented the reversed behaviour&lt;/li&gt;
&lt;li&gt;The tidy phrase for this is that the docs caught up. What they actually did was skip the part where it was on&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="so-wheres-the-commit"&gt;&lt;a class="heading-anchor" href="#so-wheres-the-commit" aria-label="Permalink to this section"&gt;#&lt;/a&gt;So where&amp;rsquo;s the commit?&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;The obvious next move: open the commit that introduced it and read the reasoning&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;There isn&amp;rsquo;t one.&lt;/strong&gt; Not &amp;ldquo;hard to find&amp;rdquo; — it does not exist publicly&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Neither does a revert commit. The reversal in &lt;code&gt;2.1.200&lt;/code&gt; has no public commit either.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;The only git artifacts either release left behind are two automated changelog commits, both titled &lt;code&gt;chore: Update CHANGELOG.md and feed.xml&lt;/code&gt; — notes &lt;em&gt;about&lt;/em&gt; a release, never the release:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/anthropics/claude-code/commit/75709eacf1334051ea293fb87a0e88a1e6812f94"&gt;&lt;code&gt;75709ea&lt;/code&gt;&lt;/a&gt; — publishes the &lt;code&gt;2.1.198&lt;/code&gt; notes (the release that shipped it, unmentioned)&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/anthropics/claude-code/commit/1322e9bacc9fdb575812add107c9421dfbff592b"&gt;&lt;code&gt;1322e9b&lt;/code&gt;&lt;/a&gt; — publishes the &lt;code&gt;2.1.200&lt;/code&gt; notes (the reversal)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Fine — then diff the source between releases. There is no source to diff&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;anthropics/claude-code&lt;/code&gt; is not the product. It is the changelog, the docs, plugin examples, a couple of example infra configs, and the bots that triage the issue tracker:&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;git ls-files &lt;span class="p"&gt;|&lt;/span&gt; wc -l &lt;span class="c1"&gt;# 216 tracked files&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;git ls-files &lt;span class="s1"&gt;&amp;#39;*.md&amp;#39;&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt; wc -l &lt;span class="c1"&gt;# 104 of them markdown&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;git ls-files &lt;span class="p"&gt;|&lt;/span&gt; cut -d/ -f1 &lt;span class="p"&gt;|&lt;/span&gt; sort -u &lt;span class="p"&gt;|&lt;/span&gt; grep -v &lt;span class="s1"&gt;&amp;#39;^\.&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# CHANGELOG.md demo.gif examples feed.xml LICENSE.md&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# plugins README.md Script scripts SECURITY.md&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;
&lt;li&gt;Every executable file in there is an example or a maintenance script. &lt;code&gt;plugins/&lt;/code&gt; holds sample plugins, &lt;code&gt;examples/&lt;/code&gt; holds a GCP gateway Terraform config and an MDM profile, &lt;code&gt;scripts/&lt;/code&gt; is eight files of issue-tracker automation (&lt;code&gt;auto-close-duplicates.ts&lt;/code&gt;, &lt;code&gt;sweep.ts&lt;/code&gt;, &lt;code&gt;gh.sh&lt;/code&gt;). Nothing in it ships to you&lt;/li&gt;
&lt;li&gt;The repo does tag releases, so the tags at least &lt;em&gt;look&lt;/em&gt; diffable. They aren&amp;rsquo;t, in the way that matters:&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;git diff --stat v2.1.197..v2.1.198
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# CHANGELOG.md | 35 +++++++++++++++++++++++++++&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# feed.xml | 77 +++++++++++++++++---------------------------------&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# 2 files changed, 74 insertions(+), 38 deletions(-)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;feed.xml&lt;/code&gt; is the changelog restated as RSS, so that diff is the changelog twice. Across ten consecutive releases (&lt;code&gt;2.1.196&lt;/code&gt; → &lt;code&gt;2.1.206&lt;/code&gt;), every tag-to-tag diff touches those two files and nothing else&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;The punchline: a release tag diff &lt;em&gt;is&lt;/em&gt; the release notes.&lt;/strong&gt; These are release-note tags, not source tags — there is no version of the code to check out&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;So &amp;ldquo;read the release notes&amp;rdquo; fails (silent change), &amp;ldquo;diff the repo&amp;rdquo; fails (no source), and &amp;ldquo;diff the tags&amp;rdquo; fails (the tags &lt;em&gt;are&lt;/em&gt; the notes). Three dead ends, one cause: nothing Anthropic publishes to git is the thing they ship you&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;The authored source is published nowhere; the behaviour ships only inside the compiled binary&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;So the sum of public evidence that this feature ever existed is:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;the message it printed into people&amp;rsquo;s terminals&lt;/li&gt;
&lt;li&gt;an env var (&lt;code&gt;CLAUDE_AFK_TIMEOUT_MS&lt;/code&gt;) that users found by asking each other, no release note having named it&lt;/li&gt;
&lt;li&gt;one changelog line, three days later, announcing its removal&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;The feature&amp;rsquo;s &lt;em&gt;introduction&lt;/em&gt; left no trace in the release notes or in git. Its &lt;em&gt;deletion&lt;/em&gt; is the first time the notes ever mentioned it.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Worth separating two claims that are easy to conflate:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;there is no public &lt;strong&gt;source repository&lt;/strong&gt; — true, and that&amp;rsquo;s the governance problem&lt;/li&gt;
&lt;li&gt;there is no way to &lt;strong&gt;see what shipped&lt;/strong&gt; — false, and that turns out to matter enormously (below)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Skip ahead if you like: the shipped binary settles the question that git can&amp;rsquo;t. The feature is provably absent from &lt;code&gt;2.1.197&lt;/code&gt; and present in &lt;code&gt;2.1.198&lt;/code&gt;, and you can check that yourself in about five minutes.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="why-was-it-added-evidence-not-confirmation"&gt;&lt;a class="heading-anchor" href="#why-was-it-added-evidence-not-confirmation" aria-label="Permalink to this section"&gt;#&lt;/a&gt;Why was it added? (evidence, not confirmation)&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;No official rationale was ever published (no design doc, no changelog line, no PR — see below)&lt;/li&gt;
&lt;li&gt;Circumstantial evidence of intent, all from naming and the message text:
&lt;ul&gt;
&lt;li&gt;Internal name is &lt;strong&gt;AFK&lt;/strong&gt; — &amp;ldquo;away from keyboard&amp;rdquo; (&lt;code&gt;CLAUDE_AFK_TIMEOUT_MS&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;The message assumes an &lt;em&gt;absent&lt;/em&gt; human: &amp;ldquo;the user may be away from keyboard&amp;rdquo;&lt;/li&gt;
&lt;li&gt;Plausible target: unattended / many-parallel-agent runs that would otherwise block forever on an absent human&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Users in the thread describe exactly the workflow it breaks: dozens of agents, some parked for days, waiting on a human by design (&lt;code&gt;earlye&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Tension: the same design that unblocks an absent human also lets an agent pick a fork in the road you explicitly reserved for yourself&lt;/li&gt;
&lt;li&gt;The strongest evidence is inside the binary, and it&amp;rsquo;s present in &lt;code&gt;2.1.198&lt;/code&gt; itself. Two separate things, worth keeping apart:&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;1. A field on the tool&amp;rsquo;s own schema&lt;/strong&gt; — this one stays local. It rides along in the tool result, tells the model the answer was auto-resolved rather than chosen, and picks which component renders the transcript line:&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-js" data-lang="js"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// v2.1.198, verbatim. `H` is the minifier&amp;#39;s name for the schema library
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// (Zod); the field name and the description text are the binary&amp;#39;s own.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nx"&gt;afkTimeoutMs&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;H&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;number&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="kr"&gt;int&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nx"&gt;positive&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nx"&gt;optional&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nx"&gt;describe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;Set when the dialog
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s2"&gt;auto-resolved after this many milliseconds of idle (user away from keyboard).
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s2"&gt;Absent on every human-resolved path.&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;2. An analytics event — this one leaves your machine.&lt;/strong&gt; Fired at the moment the dialog auto-advances:&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-js" data-lang="js"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// v2.1.198, verbatim. The mangled names (q, ld, It, R, I, s) are the
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// minifier&amp;#39;s; the event name and every property key are the binary&amp;#39;s own.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nx"&gt;q&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;tengu_ask_user_question_afk_auto_advance&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,{...&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;source_hash&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="nx"&gt;ld&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;)},&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;timeoutMs&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="nx"&gt;It&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;questionCount&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;hadPartialAnswers&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="nb"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;keys&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;R&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;isInPlanMode&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="nx"&gt;I&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;
&lt;li&gt;&lt;code&gt;tengu_*&lt;/code&gt; is the naming convention for Claude Code&amp;rsquo;s analytics events throughout the binary. The question text isn&amp;rsquo;t sent; &lt;code&gt;source_hash&lt;/code&gt; is a hash, and the rest is counters&lt;/li&gt;
&lt;li&gt;Absent from &lt;code&gt;2.1.197&lt;/code&gt;. It arrived with the feature, in the same release&lt;/li&gt;
&lt;li&gt;Read the payload for what it is: an instrument for counting how often the dialog resolved &lt;em&gt;without&lt;/em&gt; a human — how many questions were pending, whether it happened mid-plan, and &lt;strong&gt;whether you had partially answered&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;That last one is &lt;code&gt;hadPartialAnswers&lt;/code&gt;. The half-answered case wasn&amp;rsquo;t an oversight that nobody saw coming — it has a code path, and that path is counted separately from the rest&lt;/li&gt;
&lt;li&gt;So: this was &lt;strong&gt;built&lt;/strong&gt;, not stumbled into. The behaviour, the countdown, the schema field and the analytics all landed in the same release — that&amp;rsquo;s a feature with a measurement rig attached, not a stray default&lt;/li&gt;
&lt;li&gt;Note what that does &lt;em&gt;not&lt;/em&gt; establish. It says nothing about who, or whether a who was involved at all. The questions at the top of this post stay open; all the binary proves is that the work was coherent and deliberate, not who or what did it&lt;/li&gt;
&lt;li&gt;Same release, the countdown it printed at you: &lt;code&gt;auto-continue in {n}s · any key to stay&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;So the capability was designed, instrumented, and given UI — and &lt;em&gt;still&lt;/em&gt; never made the notes. That&amp;rsquo;s the gap the post is about: this wasn&amp;rsquo;t too small to mention. Someone built a measurement rig for it.&lt;/li&gt;
&lt;li&gt;What none of it tells us is who signed it off, or whether anyone weighed the failure mode against the upside. Still inference; still no published rationale.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="can-you-even-diff-it"&gt;&lt;a class="heading-anchor" href="#can-you-even-diff-it" aria-label="Permalink to this section"&gt;#&lt;/a&gt;Can you even diff it?&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Everything above says &lt;em&gt;no&lt;/em&gt;. Then you look at what&amp;rsquo;s actually installed and the answer changes.&lt;/li&gt;
&lt;li&gt;It&amp;rsquo;s a ~250MB native executable — and, crucially, &lt;strong&gt;not stripped&lt;/strong&gt;:&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;file ~/.local/share/claude/versions/2.1.211
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=..., not stripped&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;
&lt;li&gt;It&amp;rsquo;s a &lt;strong&gt;Bun-compiled&lt;/strong&gt; binary. Bun&amp;rsquo;s single-file executables append a module graph to the end of the runtime, behind a magic marker — and it&amp;rsquo;s right there:&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;grep -abo -- &lt;span class="s1"&gt;&amp;#39;---- Bun! ----&amp;#39;&lt;/span&gt; ~/.local/share/claude/versions/2.1.211 &lt;span class="p"&gt;|&lt;/span&gt; tail -1
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# 261973153 &amp;lt;-- ~50KB from the end of a 262MB file&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;
&lt;li&gt;Bun compiles by &lt;strong&gt;embedding the JS bundle inside the executable&lt;/strong&gt;, so the shipped JavaScript is sitting in the file. &lt;code&gt;strings&lt;/code&gt; reads it:&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;strings -n &lt;span class="m"&gt;3&lt;/span&gt; ~/.local/share/claude/versions/2.1.211 &lt;span class="p"&gt;|&lt;/span&gt; grep -c &lt;span class="s1"&gt;&amp;#39;CLAUDE_AFK_TIMEOUT_MS&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# 4&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;
&lt;li&gt;Every claim in &amp;ldquo;The fix&amp;rdquo; above was read straight out of that binary — the setting name, the &lt;code&gt;60s/5m/10m/never&lt;/code&gt; values, the analytics event, the countdown env var&lt;/li&gt;
&lt;li&gt;The installer keeps recent versions on disk (&lt;code&gt;ls ~/.local/share/claude/versions/&lt;/code&gt;), but only the last few — not enough to reach back to July&lt;/li&gt;
&lt;li&gt;Any version you like is on npm, though. The catch: &lt;code&gt;@anthropic-ai/claude-code&lt;/code&gt; is a &lt;strong&gt;~152KB installer stub&lt;/strong&gt; (7 files, &lt;code&gt;dist.unpackedSize&lt;/code&gt; 155,204) — no product in it. The binary lives in per-platform packages:&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;npm view @anthropic-ai/claude-code-linux-x64@2.1.198 dist.unpackedSize
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# 248900994 &amp;lt;-- ~249MB, the actual thing&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;
&lt;li&gt;So: closed source, but not a black box. Every release is fetchable and every release is legible. The distinction matters.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="so-lets-actually-diff-it"&gt;&lt;a class="heading-anchor" href="#so-lets-actually-diff-it" aria-label="Permalink to this section"&gt;#&lt;/a&gt;So let&amp;rsquo;s actually diff it&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;So let&amp;rsquo;s stop theorising and actually do it: pull &lt;code&gt;2.1.197&lt;/code&gt; and &lt;code&gt;2.1.198&lt;/code&gt; off npm and diff them.&lt;/li&gt;
&lt;li&gt;The feature has a distinctive internal name — &lt;strong&gt;AFK&lt;/strong&gt;. Grep both binaries for it:&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;for&lt;/span&gt; v in 2.1.197 2.1.198&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;=== &lt;/span&gt;&lt;span class="nv"&gt;$v&lt;/span&gt;&lt;span class="s2"&gt; ===&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;for&lt;/span&gt; s in &lt;span class="s2"&gt;&amp;#34;away from keyboard&amp;#34;&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;CLAUDE_AFK_TIMEOUT_MS&amp;#34;&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;CLAUDE_AFK_COUNTDOWN_MS&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nb"&gt;printf&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39; %-26s &amp;#39;&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$s&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; strings -n &lt;span class="m"&gt;3&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;b-&lt;/span&gt;&lt;span class="nv"&gt;$v&lt;/span&gt;&lt;span class="s2"&gt;/package/claude&amp;#34;&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt; grep -c -- &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$s&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;done&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;done&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# === 2.1.197 ===&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# away from keyboard 0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# CLAUDE_AFK_TIMEOUT_MS 0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# CLAUDE_AFK_COUNTDOWN_MS 0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# === 2.1.198 ===&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# away from keyboard 2&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# CLAUDE_AFK_TIMEOUT_MS 3&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# CLAUDE_AFK_COUNTDOWN_MS 3&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Zero to non-zero, across exactly the boundary the reporter named.&lt;/strong&gt; No commit, no changelog line, no PR — but the artifact is unambiguous about when it landed.&lt;/li&gt;
&lt;li&gt;This is the record that doesn&amp;rsquo;t exist in git. It was always in the thing they shipped you.&lt;/li&gt;
&lt;li&gt;And it settles what the release actually did. The gate that decides whether the dialog gets a timer at all, in both versions, side by side:&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-js" data-lang="js"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// Both verbatim, only whitespace added. The mangled names (ke, Ie, li, OOb, Rpf,
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// Di, Jyn) are the minifier&amp;#39;s; `hasExternalRacer` and the env var are the binary&amp;#39;s.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// v2.1.198
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nx"&gt;ke&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;Ie&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;n&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;hasExternalRacer&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;li&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// v2.1.211 — same three conditions, plus one
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nx"&gt;OOb&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;Rpf&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;Xde&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;hasExternalRacer&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;Di&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;Jyn&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nx"&gt;ye&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;CLAUDE_AFK_TIMEOUT_MS&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the entire fix
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;Jyn&lt;/code&gt; there is the &lt;code&gt;afkTimeoutMs&lt;/code&gt; prop — the &lt;code&gt;/config&lt;/code&gt; setting, resolved through the switch above. That&amp;rsquo;s the whole difference: in &lt;code&gt;2.1.198&lt;/code&gt; the gate existed, but nothing you could set was allowed to close it. In &lt;code&gt;2.1.211&lt;/code&gt; it asks your permission first&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Worth being precise, because it&amp;rsquo;s the sort of thing that gets overstated: it isn&amp;rsquo;t that &lt;code&gt;2.1.198&lt;/code&gt; had &lt;em&gt;no&lt;/em&gt; gate. It had this one, and it turned on whenever the dialog had no external racer. What it lacked was any condition a user could influence&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Two days of outcry, and the remedy is one &lt;code&gt;&amp;amp;&amp;amp;&lt;/code&gt; clause. Which is also the point: it was one &lt;code&gt;&amp;amp;&amp;amp;&lt;/code&gt; clause away from never having happened.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;But notice what that grep needed: the reporter handed us the version, and the feature has a name to grep for. Neither is true on an ordinary Wednesday. So the real question is whether you&amp;rsquo;d have found this cold, knowing neither&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;A blind string-level diff of &lt;code&gt;2.1.197&lt;/code&gt; → &lt;code&gt;2.1.198&lt;/code&gt;:&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;for&lt;/span&gt; v in 2.1.197 2.1.198&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; strings -n &lt;span class="m"&gt;8&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;b-&lt;/span&gt;&lt;span class="nv"&gt;$v&lt;/span&gt;&lt;span class="s2"&gt;/package/claude&amp;#34;&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt; sort -u &amp;gt; &lt;span class="s2"&gt;&amp;#34;s-&lt;/span&gt;&lt;span class="nv"&gt;$v&lt;/span&gt;&lt;span class="s2"&gt;.txt&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;done&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;diff s-2.1.197.txt s-2.1.198.txt &lt;span class="p"&gt;|&lt;/span&gt; grep -c &lt;span class="s1"&gt;&amp;#39;^[&amp;lt;&amp;gt;]&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# 21903&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;21,903 changed strings for one release.&lt;/strong&gt; The minifier renames every identifier on every build, so nearly all of it is churn, not change. &lt;code&gt;CLAUDE_AFK_TIMEOUT_MS&lt;/code&gt; is in there — buried in 21,902 lines of noise&lt;/li&gt;
&lt;li&gt;One caveat on that number, since it looks more solid than it is: it&amp;rsquo;s a property of the &lt;em&gt;invocation&lt;/em&gt;, not of the release. &lt;code&gt;strings -n 3&lt;/code&gt; gives 81,289; the default &lt;code&gt;-n 4&lt;/code&gt; gives 29,910; &lt;code&gt;-n 8&lt;/code&gt; gives 21,903. The shape of the argument survives any of them — tens of thousands of lines, overwhelmingly noise — but don&amp;rsquo;t read 21,903 as a constant&lt;/li&gt;
&lt;li&gt;Now filter to things that look like English sentences. Keep only added lines, made of letters and ordinary punctuation, starting with a capital, at least five words long. That drops every mangled identifier, path, and code fragment:&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# added strings only: present in 198, absent from 197&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;diff s-2.1.197.txt s-2.1.198.txt &lt;span class="p"&gt;|&lt;/span&gt; grep &lt;span class="s1"&gt;&amp;#39;^&amp;gt;&amp;#39;&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt; sed &lt;span class="s1"&gt;&amp;#39;s/^&amp;gt; //&amp;#39;&lt;/span&gt; &amp;gt; added.txt
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;wc -l &amp;lt; added.txt
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# 16255&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# ...that read like English sentences&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;grep -E &lt;span class="s1"&gt;&amp;#39;^[A-Z][a-zA-Z0-9 ,.:;&amp;#39;&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&amp;#39;&amp;#34;&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;-]+$&amp;#39;&lt;/span&gt; added.txt &lt;span class="p"&gt;|&lt;/span&gt; awk &lt;span class="s1"&gt;&amp;#39;NF&amp;gt;=5&amp;#39;&lt;/span&gt; &amp;gt; prose.txt
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;wc -l &amp;lt; prose.txt
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# 156&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;156 lines.&lt;/strong&gt; That&amp;rsquo;s the whole surface of new human-readable text in the release — small enough to read over coffee. And the feature is in there, in plain language:&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Before going idle the user had selected:
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;
&lt;li&gt;That&amp;rsquo;s the string injected back into the conversation when the dialog answers for you. Read that line cold, knowing nothing, and you&amp;rsquo;d stop&lt;/li&gt;
&lt;li&gt;It lands at line 11 of the 156, which sounds like a lucky break and isn&amp;rsquo;t: &lt;code&gt;s-*.txt&lt;/code&gt; was &lt;code&gt;sort -u&lt;/code&gt;&amp;rsquo;d, so the list is alphabetical. Ten lines starting with &amp;ldquo;A&amp;rdquo; precede it, and it starts with &amp;ldquo;B&amp;rdquo;. Position tells you nothing here — the point is that 156 lines is a five-minute read, not that the alphabet was kind&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="what-it-costs-to-find-that"&gt;&lt;a class="heading-anchor" href="#what-it-costs-to-find-that" aria-label="Permalink to this section"&gt;#&lt;/a&gt;What it costs to find that&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;So the diff works.&lt;/strong&gt; A person doing this ritual on 1 July, with no privileged information, would have caught it on the day it shipped — before the issue was filed.&lt;/li&gt;
&lt;li&gt;Tempting conclusion, then: &amp;ldquo;so just diff every release.&amp;rdquo;&lt;/li&gt;
&lt;li&gt;Which answers one of the questions from the top of this post — &lt;em&gt;did a human release manager diff the release against the previous one before it went out the door?&lt;/em&gt;
&lt;ul&gt;
&lt;li&gt;Whoever shipped &lt;code&gt;2.1.198&lt;/code&gt; had every advantage I didn&amp;rsquo;t: the source, the build, the diff, the review, the authors to ask&lt;/li&gt;
&lt;li&gt;I had a &lt;code&gt;curl&lt;/code&gt; and a &lt;code&gt;grep&lt;/code&gt;, and it took about five minutes&lt;/li&gt;
&lt;li&gt;So: either nobody looked, or someone looked and shipped it anyway. Both are answers. Neither is good.&lt;/li&gt;
&lt;li&gt;The rest of those questions — who wrote it, who reviewed it, who signed it off — stay unanswerable, because the public record where that would live does not exist. That&amp;rsquo;s the same absence as the missing commit, wearing a different hat.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Which is the uncomfortable finding, not a reassuring one:
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Can you?&lt;/strong&gt; Yes. Demonstrably. It took a &lt;code&gt;curl&lt;/code&gt;, a &lt;code&gt;strings&lt;/code&gt;, and a &lt;code&gt;diff&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Should you have to?&lt;/strong&gt; 156 lines per release, forever, across every tool that auto-updates, to learn what a one-line release note would have told you.&lt;/li&gt;
&lt;li&gt;Nobody is going to do this. The people most exposed — the ones running unattended agents at scale — are the least likely to be grepping binaries at 2am.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;The capability is a workaround, not a remedy. That it &lt;em&gt;works&lt;/em&gt; is what makes its necessity hard to accept.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="why-this-is-more-than-burned-tokens"&gt;&lt;a class="heading-anchor" href="#why-this-is-more-than-burned-tokens" aria-label="Permalink to this section"&gt;#&lt;/a&gt;Why this is more than burned tokens&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Cost angle: an unattended agent auto-answering its own questions can burn tokens on the wrong path&lt;/li&gt;
&lt;li&gt;Safety angle is worse than cost:
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;AskUserQuestion&lt;/code&gt; is used as an explicit &lt;strong&gt;safety gate&lt;/strong&gt; — hooks/rules built on it assume it &lt;em&gt;blocks&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;Turning a blocking gate into a 60s countdown silently voids that assumption&lt;/li&gt;
&lt;li&gt;People run Claude Code in genuinely risky contexts — deployments, infra, prod-adjacent scripts&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Compounding factor: Claude Code &lt;strong&gt;auto-updates by default&lt;/strong&gt;
&lt;ul&gt;
&lt;li&gt;A silent behaviour change + auto-update = the gate can change under you without a single action on your part&lt;/li&gt;
&lt;li&gt;Ties back to &lt;a href="https://www.olafalders.com/2026/05/19/On-Cooldowns-and-Dependabot-Tuning"&gt;On Cooldowns and Dependabot Tuning&lt;/a&gt; — why &amp;ldquo;newest immediately&amp;rdquo; is a risk posture&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="turning-auto-update-off"&gt;&lt;a class="heading-anchor" href="#turning-auto-update-off" aria-label="Permalink to this section"&gt;#&lt;/a&gt;Turning auto-update off&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Three env vars. The resolver checks them in this order, first match wins — note it is &lt;em&gt;not&lt;/em&gt; the order you&amp;rsquo;d guess:
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;DISABLE_UPDATES=1&lt;/code&gt; — checked first. The strictest: blocks &lt;em&gt;all&lt;/em&gt; update paths, including a manual &lt;code&gt;claude update&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;DISABLE_AUTOUPDATER=1&lt;/code&gt; — stops the background check only; &lt;code&gt;claude update&lt;/code&gt; still works. &lt;strong&gt;Takes precedence over&lt;/strong&gt; the &lt;code&gt;autoUpdates&lt;/code&gt; config setting&lt;/li&gt;
&lt;li&gt;&lt;code&gt;CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC=1&lt;/code&gt; — the big hammer: equivalent to &lt;code&gt;DISABLE_AUTOUPDATER&lt;/code&gt; + &lt;code&gt;DISABLE_FEEDBACK_COMMAND&lt;/code&gt; + &lt;code&gt;DISABLE_ERROR_REPORTING&lt;/code&gt; + &lt;code&gt;DISABLE_TELEMETRY&lt;/code&gt; (&lt;code&gt;DISABLE_BUG_COMMAND&lt;/code&gt; is the older name, still accepted)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;All of them freeze your plugins too. That&amp;rsquo;s documented for exactly one of the three — see below&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;The &amp;ldquo;set it everywhere&amp;rdquo; problem has a fix&lt;/strong&gt;: don&amp;rsquo;t export the var from a shell profile — put it in the &lt;code&gt;env&lt;/code&gt; block of &lt;code&gt;settings.json&lt;/code&gt;, documented as &lt;em&gt;&amp;ldquo;environment variables that will be applied to every session&amp;rdquo;&lt;/em&gt;. One file, every invocation — CI, cron, systemd, IDE-spawned terminals included.&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-jsonc" data-lang="jsonc"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// ~/.claude/settings.json — user-wide, survives every shell/IDE/CI invocation
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;env&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;DISABLE_AUTOUPDATER&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;1&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;
&lt;li&gt;Scopes, least to most durable:
&lt;ul&gt;
&lt;li&gt;shell profile export → per-shell, easy to miss an environment (the trap)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;~/.claude/settings.json&lt;/code&gt; → user-wide, one place&lt;/li&gt;
&lt;li&gt;&lt;code&gt;.claude/settings.json&lt;/code&gt; in a repo → team-wide, checked into source control&lt;/li&gt;
&lt;li&gt;&lt;code&gt;managed-settings.json&lt;/code&gt; → enterprise policy, &lt;strong&gt;highest precedence&lt;/strong&gt;, centrally enforced:&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;macOS: /Library/Application Support/ClaudeCode/managed-settings.json
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Linux/WSL: /etc/claude-code/managed-settings.json
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Windows: C:\Program Files\ClaudeCode\managed-settings.json
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;(C:\ProgramData\ClaudeCode is the legacy path and is no longer read.)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;
&lt;li&gt;No CLI flag exists to disable auto-update; &lt;code&gt;claude update&lt;/code&gt; is manual, &lt;code&gt;/doctor&lt;/code&gt; reports the update channel and install type&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="the-catch-this-also-stops-updating-your-plugins"&gt;&lt;a class="heading-anchor" href="#the-catch-this-also-stops-updating-your-plugins" aria-label="Permalink to this section"&gt;#&lt;/a&gt;The catch: this also stops updating your plugins&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;Turn off the auto-updater by &lt;em&gt;any&lt;/em&gt; of the means above and &lt;strong&gt;plugin auto-updates stop as well&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;This one is documented&lt;/strong&gt; — but on the &lt;a href="https://code.claude.com/docs/en/discover-plugins#configure-auto-updates"&gt;plugin discovery page&lt;/a&gt;, under &amp;ldquo;Configure auto-updates&amp;rdquo;, which is not where you are standing when you disable auto-updates:&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;To disable all automatic updates entirely for both Claude Code and all plugins,
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;set the DISABLE_AUTOUPDATER environment variable.
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;To keep plugin auto-updates enabled while disabling Claude Code auto-updates,
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;set FORCE_AUTOUPDATE_PLUGINS=1 along with DISABLE_AUTOUPDATER.
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;
&lt;li&gt;Where it &lt;em&gt;isn&amp;rsquo;t&lt;/em&gt;: &lt;a href="https://code.claude.com/docs/en/setup#disable-auto-updates"&gt;&lt;code&gt;/setup&lt;/code&gt; → Disable auto-updates&lt;/a&gt;, the page that tells you how to do this, mentions neither plugins nor &lt;code&gt;FORCE_AUTOUPDATE_PLUGINS&lt;/code&gt;. Nor does the &lt;a href="https://code.claude.com/docs/en/settings"&gt;settings&lt;/a&gt; env var table. Follow the docs for the task you&amp;rsquo;re actually doing and you never learn about it&lt;/li&gt;
&lt;li&gt;And the docs only ever say &lt;code&gt;DISABLE_AUTOUPDATER&lt;/code&gt;. The binary shows &lt;strong&gt;four&lt;/strong&gt; paths freeze plugins — &lt;code&gt;DISABLE_UPDATES&lt;/code&gt;, &lt;code&gt;CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC&lt;/code&gt; and &lt;code&gt;autoUpdates: false&lt;/code&gt; do it too, and &lt;em&gt;that&lt;/em&gt; part is undocumented. It&amp;rsquo;s a single gate on &amp;ldquo;is the updater off for any reason&amp;rdquo;:&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-js" data-lang="js"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// v2.1.211, verbatim. The names are meaningless because the minifier ate them —
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// the env var and the log string survive, being strings rather than identifiers.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;u_e&lt;/span&gt;&lt;span class="p"&gt;(){&lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;h$e&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;!==&lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;blt&lt;/span&gt;&lt;span class="p"&gt;(){&lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;u_e&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&amp;amp;!&lt;/span&gt;&lt;span class="nx"&gt;ut&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;FORCE_AUTOUPDATE_PLUGINS&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// ...and at the plugin auto-update entry point:
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;blt&lt;/span&gt;&lt;span class="p"&gt;()){&lt;/span&gt;&lt;span class="nx"&gt;w&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;Plugin autoupdate: skipped (auto-updater disabled)&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;
&lt;li&gt;Unreadable, so here it is again with the five functions renamed &lt;strong&gt;by me&lt;/strong&gt; — &lt;code&gt;h$e&lt;/code&gt; → &lt;code&gt;disabledReason&lt;/code&gt;, &lt;code&gt;u_e&lt;/code&gt; → &lt;code&gt;updatesAreDisabled&lt;/code&gt;, &lt;code&gt;blt&lt;/code&gt; → &lt;code&gt;pluginUpdatesBlocked&lt;/code&gt;, &lt;code&gt;ut&lt;/code&gt; → &lt;code&gt;truthy&lt;/code&gt;, &lt;code&gt;w&lt;/code&gt; → &lt;code&gt;debugLog&lt;/code&gt;. The logic is untouched; the names are my guesses at intent, not the authors':&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-js" data-lang="js"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// NOT the shipped code — function names below are mine, invented for legibility.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// The control flow, the env var and the log string are verbatim from v2.1.211.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;updatesAreDisabled&lt;/span&gt;&lt;span class="p"&gt;(){&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;disabledReason&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;pluginUpdatesBlocked&lt;/span&gt;&lt;span class="p"&gt;(){&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;updatesAreDisabled&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;truthy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;FORCE_AUTOUPDATE_PLUGINS&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;pluginUpdatesBlocked&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;debugLog&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;Plugin autoupdate: skipped (auto-updater disabled)&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;
&lt;li&gt;At runtime the skip is nearly invisible — it&amp;rsquo;s a debug log line, not a warning. Documented or not, nothing in the session tells you your plugins have frozen.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;The fix is one more env var&lt;/strong&gt; — the documented, supported one. It restores plugin updates while leaving the CLI pinned:&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-jsonc" data-lang="jsonc"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// ~/.claude/settings.json — pin the CLI, keep plugins current
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;env&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;DISABLE_AUTOUPDATER&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;1&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;FORCE_AUTOUPDATE_PLUGINS&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;1&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;
&lt;li&gt;&lt;code&gt;FORCE_AUTOUPDATE_PLUGINS&lt;/code&gt;, &lt;code&gt;DISABLE_AUTOUPDATER&lt;/code&gt; and &lt;code&gt;DISABLE_UPDATES&lt;/code&gt; are parsed properly: the parser accepts &lt;code&gt;1&lt;/code&gt;, &lt;code&gt;true&lt;/code&gt;, &lt;code&gt;yes&lt;/code&gt;, or &lt;code&gt;on&lt;/code&gt; (case-insensitive), so &lt;code&gt;=1&lt;/code&gt; does what you&amp;rsquo;d hope and &lt;code&gt;=0&lt;/code&gt; correctly reads as false&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC&lt;/code&gt; is not.&lt;/strong&gt; It&amp;rsquo;s presence-detected, so &lt;em&gt;any&lt;/em&gt; non-empty value switches it on — &lt;code&gt;=0&lt;/code&gt; included, which means &lt;code&gt;CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC=0&lt;/code&gt; disables your auto-updater and freezes your plugins:&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-js" data-lang="js"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// v2.1.211, verbatim. `Z3t` is the minifier&amp;#39;s name; the env var is the binary&amp;#39;s.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// Note the bare `process.env.X` — the value is never read, only its presence.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;Z3t&lt;/span&gt;&lt;span class="p"&gt;(){&lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;
&lt;li&gt;Note the shape of this: a var whose name begins with &lt;code&gt;FORCE_&lt;/code&gt; is the supported way to get the &lt;em&gt;ordinary&lt;/em&gt; behaviour of keeping plugins current. It reads like an escape hatch someone added on the way past.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="sharp-edges"&gt;&lt;a class="heading-anchor" href="#sharp-edges" aria-label="Permalink to this section"&gt;#&lt;/a&gt;Sharp edges&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;Reading the resolver in &lt;code&gt;2.1.211&lt;/code&gt;, &lt;strong&gt;four&lt;/strong&gt; things disable updates — the three env vars above, plus &lt;code&gt;autoUpdates: false&lt;/code&gt; in config. All four also stop plugin updates.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC&lt;/code&gt; is the surprising one: reach for it as a &lt;em&gt;privacy/egress&lt;/em&gt; control and you have silently pinned your CLI and frozen your plugins&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;autoUpdates: false&lt;/code&gt; can be ignored outright.&lt;/strong&gt; The config path is gated on an extra condition:&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-js" data-lang="js"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// v2.1.211, verbatim — `t` is the minified name for the settings object; every
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// key on it is real, because property names survive. `!1`/`!0` are false/true.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;t&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;autoUpdates&lt;/span&gt;&lt;span class="o"&gt;===!&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;t&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;installMethod&lt;/span&gt;&lt;span class="o"&gt;!==&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;native&amp;#34;&lt;/span&gt;&lt;span class="o"&gt;||&lt;/span&gt;&lt;span class="nx"&gt;t&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;autoUpdatesProtectedForNative&lt;/span&gt;&lt;span class="o"&gt;!==!&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;type&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;config&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// ^ on a native install with autoUpdatesProtectedForNative,
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// your `autoUpdates: false` does nothing at all
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;
&lt;li&gt;So the config key is both &lt;strong&gt;undocumented&lt;/strong&gt; — &lt;code&gt;autoUpdates&lt;/code&gt;, as distinct from &lt;code&gt;autoUpdatesChannel&lt;/code&gt;, appears nowhere in the docs — and &lt;strong&gt;conditionally overridden&lt;/strong&gt;. Prefer the env vars: they&amp;rsquo;re checked before it, and unconditionally.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;2.1.98&lt;/code&gt;&lt;/strong&gt; fixed &lt;code&gt;DISABLE_AUTOUPDATER&lt;/code&gt; &lt;strong&gt;not fully suppressing&lt;/strong&gt; the npm registry version check and symlink modification &lt;em&gt;on npm-based installs&lt;/em&gt; — for a long stretch, &amp;ldquo;disabled&amp;rdquo; wasn&amp;rsquo;t entirely disabled&lt;/li&gt;
&lt;li&gt;The auto-updater has overwritten a custom launcher/symlink at &lt;code&gt;~/.local/bin/claude&lt;/code&gt; on every release (since fixed; &lt;code&gt;/doctor&lt;/code&gt; now flags externally managed launchers)&lt;/li&gt;
&lt;li&gt;Which install methods self-update matters: &lt;strong&gt;native and npm auto-update by default&lt;/strong&gt;; Homebrew, WinGet, apt, dnf and apk do not (Homebrew and WinGet can opt in via &lt;code&gt;CLAUDE_CODE_PACKAGE_MANAGER_AUTO_UPDATE=1&lt;/code&gt;). If you&amp;rsquo;re on native or npm, you are on the daily-cadence treadmill unless you say otherwise&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class="llm-block__foot"&gt;
&lt;span&gt;// end LLM-generated content&lt;/span&gt;
&lt;button type="button" class="llm-block__collapse" data-llm-collapse&gt;Hide&lt;/button&gt;
&lt;/div&gt;
&lt;/details&gt;
&lt;p&gt;&lt;em&gt;Claude&amp;rsquo;s research ends here.&lt;/em&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="wrap-up"&gt;&lt;a class="heading-anchor" href="#wrap-up" aria-label="Permalink to this section"&gt;#&lt;/a&gt;Wrap-up&lt;/h2&gt;
&lt;p&gt;Even though the source code is not properly public, I was surprised at how much we could learn from it. Having some clues as to what to look for certainly helped, but it&amp;rsquo;s still not a replacement for a well edited and accurate changelog.&lt;/p&gt;
&lt;p&gt;This wasn&amp;rsquo;t a stray line of code that slipped through. It looks like an actual feature. Why it got shipped completely under the radar remains baffling.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;m not assuming bad faith on the part of Anthropic. Things happen. Whether or not things like this continue to happen will help us to understand what Anthropic did or did not learn from this misfeature.&lt;/p&gt;
&lt;h2 id="related-posts"&gt;&lt;a class="heading-anchor" href="#related-posts" aria-label="Permalink to this section"&gt;#&lt;/a&gt;Related posts&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.olafalders.com/2026/05/19/On-Cooldowns-and-Dependabot-Tuning"&gt;On Cooldowns and Dependabot Tuning&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.olafalders.com/2026/07/06/the-dot-claude-attack-surface/"&gt;The dot claude Attack Surface&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.olafalders.com/2026/06/11/claude-will-find-a-way/"&gt;Claude Will Find a Way&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;a href="https://www.olafalders.com/2026/07/17/claude-code-anatomy-of-a-misfeature/"&gt;Read on website&lt;/a&gt;&lt;/p&gt;</content:encoded><media:content xmlns:media="http://search.yahoo.com/mrss/" url="https://www.olafalders.com/2026/07/17/claude-code-anatomy-of-a-misfeature/featured.jpeg"/></item><item><title>AI Shoulder Surf V3</title><link>https://www.olafalders.com/2026/06/09/ai-shoulder-surf-v3/</link><pubDate>Tue, 09 Jun 2026 00:00:00 +0000</pubDate><author>olaf@wundersolutions.com (Olaf Alders)</author><guid>https://www.olafalders.com/2026/06/09/ai-shoulder-surf-v3/</guid><description>The third AI Shoulder Surf — a small, no-recording group on Zoom comparing notes on Tailscale home labs, coding from a phone, and giving agents their own scoped identities.</description><content:encoded>&lt;!-- markdownlint-disable MD003 MD033 MD046 --&gt;
&lt;p&gt;What follows is an AI summary of our meeting. The target audience is mostly the
folks who were on the call, but I&amp;rsquo;ll be happy if anyone else gets something out
of it.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://www.olafalders.com/2026/06/09/ai-shoulder-surf-v3/featured.jpeg"&gt;&lt;img src="https://www.olafalders.com/2026/06/09/ai-shoulder-surf-v3/featured.jpeg" alt="featured"&gt;&lt;/a&gt; &lt;!-- markdownlint-disable-line --&gt;&lt;/p&gt;
&lt;p class="attribution"&gt;"&lt;a rel="noopener noreferrer" href="https://www.flickr.com/photos/troy_williams/31926210275/"&gt;Stop....hammer time?&lt;/a&gt;" by &lt;a rel="noopener noreferrer" href="https://www.flickr.com/photos/troy_williams"&gt;troy_williams&lt;/a&gt; is licensed under &lt;a rel="noopener noreferrer" href="https://creativecommons.org/licenses/by/2.0/?ref=openverse"&gt;CC BY 2.0 &lt;img src="https://www.olafalders.com/img/cc/cc.svg" alt="" style="height: 1em;" /&gt;&lt;img src="https://www.olafalders.com/img/cc/by.svg" alt="" style="height: 1em;" /&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;details class="llm-block" open&gt;
&lt;summary class="llm-block__bar"&gt;
&lt;svg class="llm-block__spark" width="13" height="13" viewBox="0 0 16 16" aria-hidden="true"&gt;&lt;path d="M8 0l1.7 5.4L15 7l-5.3 1.6L8 14l-1.7-5.4L1 7l5.3-1.6z"/&gt;&lt;/svg&gt;
&lt;span class="llm-block__label"&gt;Contains LLM-generated content&lt;/span&gt;
&lt;span class="llm-block__by"&gt;not written by Olaf&lt;/span&gt;
&lt;span class="llm-block__toggle" aria-hidden="true"&gt;&lt;/span&gt;
&lt;/summary&gt;
&lt;div class="llm-block__body"&gt;
&lt;span class="llm-block__gutter" aria-hidden="true" style="background-image:url(&amp;#39;data:image/svg&amp;#43;xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNiIgaGVpZ2h0PSIxMTIiPjx0ZXh0IHRyYW5zZm9ybT0idHJhbnNsYXRlKDExIDExMikgcm90YXRlKC05MCkiIGZvbnQtZmFtaWx5PSJ1aS1tb25vc3BhY2UsIFNGTW9uby1SZWd1bGFyLCBNZW5sbywgbW9ub3NwYWNlIiBmb250LXNpemU9IjkuNSIgbGV0dGVyLXNwYWNpbmc9IjIiIGZpbGw9IiNiYjlhZjciIGZpbGwtb3BhY2l0eT0iMC41IiB4bWw6c3BhY2U9InByZXNlcnZlIj5BSSBzdW1tYXJ5IMK3IDwvdGV4dD48L3N2Zz4=&amp;#39;)"&gt;&lt;/span&gt;
&lt;p&gt;On Thursday, May 28, 2026 we had our third AI Shoulder Surf. The
&lt;a href="https://www.olafalders.com/2026/03/16/ai-shoulder-surf-v1"&gt;first&lt;/a&gt; writeup explains the format, but the
short version: it&amp;rsquo;s an informal Zoom call where we share screens, talk about
what we&amp;rsquo;re working on, and admit what we don&amp;rsquo;t know.&lt;/p&gt;
&lt;p&gt;The connective thread this time was &lt;a href="https://tailscale.com/"&gt;Tailscale&lt;/a&gt;:
everyone at the table had quietly built a private home lab and was reaching it
from anywhere without exposing a single port to the public internet.&lt;/p&gt;
&lt;h2 id="olaf-coach-claude"&gt;&lt;a class="heading-anchor" href="#olaf-coach-claude" aria-label="Permalink to this section"&gt;#&lt;/a&gt;Olaf: Coach Claude&lt;/h2&gt;
&lt;p&gt;I have a triathlon coming up, so I asked Claude to build me a training program.
I fed it a GPX file of the bike course so it could analyze the climbs and base
the training around the actual route, then gave it my constraints — swim on
these days, long run on a Wednesday — and it laid the whole thing out nicely.&lt;/p&gt;
&lt;p&gt;As a bonus it generated a little static website for the plan. I spun that up on
my &lt;a href="https://www.hetzner.com/"&gt;Hetzner&lt;/a&gt; VM and within about five minutes
something had already tried to &lt;code&gt;GET&lt;/code&gt; the &lt;code&gt;.env&lt;/code&gt; file. It wasn&amp;rsquo;t being served, so
no harm done, but it was a good reminder of what the open internet is like the
moment you put anything on it. So I moved the whole thing onto my Tailscale
network instead. Now my training plan isn&amp;rsquo;t getting probed by creeps — it&amp;rsquo;s just
there for me when I want it.&lt;/p&gt;
&lt;p&gt;The other nice touch: Claude also produced an iCal subscription and parks it in a
GitHub gist. I subscribed to that URL from my phone calendar, and it actually
updates when the plan changes. I&amp;rsquo;m happier with that than I would be wrangling a
spreadsheet or paying a monthly fee for an app that doesn&amp;rsquo;t quite do what I want.&lt;/p&gt;
&lt;h2 id="aaron-a-job-hunt-workspace-you-can-reach-from-anywhere"&gt;&lt;a class="heading-anchor" href="#aaron-a-job-hunt-workspace-you-can-reach-from-anywhere" aria-label="Permalink to this section"&gt;#&lt;/a&gt;Aaron: A job-hunt workspace you can reach from anywhere&lt;/h2&gt;
&lt;p&gt;Aaron has been job hunting, and he hit the familiar problem of bookmarking a
posting to &amp;ldquo;apply later&amp;rdquo; and then forgetting it. So he built himself a little
GitHub project: a spreadsheet of every place he&amp;rsquo;s thinking about applying to.
When he&amp;rsquo;s in the mood, he kicks off an agent — he&amp;rsquo;s on &lt;a href="https://github.com/google-gemini/gemini-cli"&gt;Gemini
CLI&lt;/a&gt; / Antigravity now — to research
a company, draft a cover letter, and coach him with questions about the role.&lt;/p&gt;
&lt;p&gt;The clever part is &lt;em&gt;where&lt;/em&gt; it lives. The whole thing sits in a folder on his VM,
so when he&amp;rsquo;s at a coffee shop and feels like chipping away at it, he connects to
his Tailscale network, SSHes into the VM, and it&amp;rsquo;s right there. No syncing the
project onto multiple machines, no &amp;ldquo;which laptop has the latest version.&amp;rdquo; One
home for the work, reachable from anywhere on the tailnet.&lt;/p&gt;
&lt;h2 id="aaron-a-wildcard-tailnet-with-homepage"&gt;&lt;a class="heading-anchor" href="#aaron-a-wildcard-tailnet-with-homepage" aria-label="Permalink to this section"&gt;#&lt;/a&gt;Aaron: A wildcard tailnet with Homepage&lt;/h2&gt;
&lt;p&gt;Aaron is also self-hosting a pile of little static reports and dashboards, and
he&amp;rsquo;s wired them together with &lt;a href="https://gethomepage.dev/"&gt;Homepage&lt;/a&gt; — a project
that gives you a web front end plus an NGINX reverse proxy on a Docker Compose
stack. He spins the stack up on his VM and points the reverse proxy at his
various static-page folders.&lt;/p&gt;
&lt;p&gt;Then the DNS trick: he created a &lt;code&gt;*.dev.&amp;lt;his-domain&amp;gt;&lt;/code&gt; wildcard A record pointing
at a Tailscale IP address for his tailnet. So every time he spins up a new static
site on the VM, it&amp;rsquo;s instantly reachable at a &lt;code&gt;something.dev.&amp;lt;his-domain&amp;gt;&lt;/code&gt; URL —
but &lt;em&gt;only&lt;/em&gt; if you&amp;rsquo;re on his tailnet. Public DNS, private reachability.&lt;/p&gt;
&lt;p&gt;Mateu is doing something similar from the other direction: he runs a couple of
&lt;a href="https://pi-hole.net/"&gt;Pi-hole&lt;/a&gt; instances for DNS, and he&amp;rsquo;s made Tailscale aware
of them. Because Tailscale knows about his internal DNS servers, it can resolve
his domain names and route to the right instance behind an NGINX reverse proxy —
which means he doesn&amp;rsquo;t need the Tailscale client installed on &lt;em&gt;every&lt;/em&gt; machine.
The cloud in the home, as he put it.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Claude&amp;rsquo;s note: three people, three slightly different recipes, one shape. A
private overlay network plus your own DNS turns &amp;ldquo;self-hosting&amp;rdquo; from a
port-forwarding-and-dynamic-DNS chore into something closer to a personal cloud.
The work has moved from &amp;ldquo;how do I expose this safely&amp;rdquo; to &amp;ldquo;how do I name this
conveniently.&amp;rdquo;&lt;/em&gt;&lt;/p&gt;
&lt;h2 id="a-quick-note-on-what-tailscale-actually-is"&gt;&lt;a class="heading-anchor" href="#a-quick-note-on-what-tailscale-actually-is" aria-label="Permalink to this section"&gt;#&lt;/a&gt;A quick note on what Tailscale actually is&lt;/h2&gt;
&lt;p&gt;A useful clarification came up for anyone who hasn&amp;rsquo;t set it up. Tailscale isn&amp;rsquo;t
exactly a VPN in the route-all-my-traffic sense. Without an exit node enabled,
it behaves more like a VLAN — it just gives the machines on your tailnet a route
to each other. It only routes &lt;em&gt;all&lt;/em&gt; of your traffic through another node if you
explicitly turn on exit-node mode. And because it punches through NAT for you,
there&amp;rsquo;s no opening ports on your router, which is most of the historical pain of
self-hosting gone in one step.&lt;/p&gt;
&lt;p&gt;The recurring sentiment around the table was simply: Tailscale has been a
blessing. I can now mostly just tell Claude to set up the Tailscale piece I need
and it works.&lt;/p&gt;
&lt;h2 id="coding-from-a-phone"&gt;&lt;a class="heading-anchor" href="#coding-from-a-phone" aria-label="Permalink to this section"&gt;#&lt;/a&gt;Coding from a phone&lt;/h2&gt;
&lt;p&gt;Aaron joined part of the call from the road and has been doing real work from his
phone over Tailscale. Two things made that bearable. First,
&lt;a href="https://termius.com/"&gt;Termius&lt;/a&gt;, a terminal app with pinch-to-zoom, so bumping
up the font size mid-session is trivial. Second, saved
macros — he keeps things like &lt;code&gt;docker ps&lt;/code&gt; one tap away to check whether anything
is still alive. That&amp;rsquo;s a small feature that turns out to be a lifesaver on a tiny
screen.&lt;/p&gt;
&lt;p&gt;The pain point we all recognized: tmux on a phone. Trying to fire a &lt;code&gt;Ctrl-A&lt;/code&gt;
prefix and then a pane-switch key on a touch keyboard is genuinely miserable.
Aaron&amp;rsquo;s suggestion was to record the whole key combination as a macro so you can
switch panes with a single tap — a good idea I hadn&amp;rsquo;t tried.&lt;/p&gt;
&lt;h2 id="tools-roundup"&gt;&lt;a class="heading-anchor" href="#tools-roundup" aria-label="Permalink to this section"&gt;#&lt;/a&gt;Tools roundup&lt;/h2&gt;
&lt;p&gt;A lap around what people are running:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;OpenClaw as the driver.&lt;/strong&gt; Mateu still uses &lt;a href="https://github.com/openclaw/openclaw"&gt;OpenClaw&lt;/a&gt;
on his OpenAI subscription as his main controller — mostly conversational,
which is where he spends most of his time. After a rough patch the project
refocused on stability and it&amp;rsquo;s noticeably better. A new feature he wants to
try lets the agent join a Google Meet as a full participant with a voice. I
pointed out that video plus text-to-speech sounds like a fast way to rack up
tokens.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Hermes as a backup.&lt;/strong&gt; Mateu has also picked up Hermes, a Python-flavored
cousin of OpenClaw that&amp;rsquo;s gaining momentum, and likes keeping
a second agent around — when an update breaks one, the other keeps working.
Many heavy users drive these through Discord for its threaded conversations,
though Mateu uses OpenClaw&amp;rsquo;s built-in Control UI. On memory, he&amp;rsquo;s been using a
notes plugin that searches saved memory, which works well but occasionally
forgets to look in all the right places.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Two quotas, not one.&lt;/strong&gt; Aaron&amp;rsquo;s find of the day: Gemini on the web and the
Gemini CLI draw from &lt;em&gt;separate&lt;/em&gt; quotas, even when you&amp;rsquo;re signed into the same
subscription. So he does his planning and architecture conversation in the web
app, asks it to emit markdown — a plan, a README, a fresh agent config — then
downloads those into his working directory and runs the CLI against them. Two
budgets, planning on one and implementation on the other.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Koan and plan review.&lt;/strong&gt; &lt;a href="https://github.com/sukria/koan"&gt;Koan&lt;/a&gt; runs on a
subscription rather than API credits, and Mateu confirmed you can have it
review its own plan before it acts. I&amp;rsquo;d found some of its autonomous behavior a
bit head-scratching, and reviewing the plan up front is the lever for that.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;em&gt;Claude&amp;rsquo;s note: the &amp;ldquo;two separate quotas&amp;rdquo; thing is the kind of accidental
arbitrage that won&amp;rsquo;t last, but while it does it neatly matches the natural shape
of the work — expensive, exploratory thinking in one place, cheaper mechanical
execution in another.&lt;/em&gt;&lt;/p&gt;
&lt;h2 id="sandboxing-and-how-much-to-trust-the-agent"&gt;&lt;a class="heading-anchor" href="#sandboxing-and-how-much-to-trust-the-agent" aria-label="Permalink to this section"&gt;#&lt;/a&gt;Sandboxing and how much to trust the agent&lt;/h2&gt;
&lt;p&gt;Everyone has landed somewhere different on the trust-versus-isolation dial.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;ve been leaning on &lt;a href="https://nono.sh/"&gt;Nono&lt;/a&gt; sandboxes, even
inside a VM that exists only for side projects — partly because I once gave
Claude broad filesystem permissions and didn&amp;rsquo;t love what it did with them. Nono
lets you define profiles and compose them, so I have a wrapper that detects
whether it&amp;rsquo;s a Go, Perl, or JavaScript project and pulls the right profile
automatically. It gets trickier when I want to grant Terraform or SSH, which I&amp;rsquo;m
still working out. It matters most for the CPAN security work: when I&amp;rsquo;m poking at
a proof-of-concept exploit, I want the agent locked down hard — the last thing I
want is an over-eager agent opening a public issue about an unpatched problem.&lt;/p&gt;
&lt;p&gt;Aaron keeps a dedicated Ubuntu VM that holds nothing but his dev environment,
backed by snapshots, so a wiped disk is a non-event. For his own side projects he
often doesn&amp;rsquo;t bother sandboxing further, since the sister directories share the
same credentials anyway. When he wants real isolation he used to run Gemini CLI
inside its own restricted Docker container; lately he&amp;rsquo;s been trusting
Antigravity&amp;rsquo;s allow-list controls for system commands, running on the host in its
own sandbox mode.&lt;/p&gt;
&lt;p&gt;Mateu sits at the trusting end: LXC for some instances, bare metal on macOS for
others, and because he enjoys the DevOps side he hands the agent SSH access and
passwordless root so it can manage other machines. No incidents so far — knock on
wood.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Claude&amp;rsquo;s note: this is the same axis as the v1 and v2 conversations, but the
spread is the interesting part. The right amount of isolation isn&amp;rsquo;t a constant —
it tracks the blast radius of the task. A throwaway side project and a
proof-of-concept exploit deserve very different cages.&lt;/em&gt;&lt;/p&gt;
&lt;h2 id="identity-roles-and-the-tax-of-least-privilege"&gt;&lt;a class="heading-anchor" href="#identity-roles-and-the-tax-of-least-privilege" aria-label="Permalink to this section"&gt;#&lt;/a&gt;Identity, roles, and the tax of least privilege&lt;/h2&gt;
&lt;p&gt;The richest thread came out of Aaron comparing AWS and Google Cloud. GCP lets you
define more granular IAM roles and pin a role to an identity, and it makes it
easier to see what permissions you actually hold in a given environment. That got
him thinking about agents. Today, an agent usually acts &lt;em&gt;as you&lt;/em&gt; — it carries an
SSH key that represents you, reused across many projects, which is only ever as
secure as you are. His plan is to flip that: generate scoped, role-based keys and
hand the agent an identity that says &amp;ldquo;this is me, but a sub-agent that can only do
these specific things,&amp;rdquo; reusing the same role template across repos so he isn&amp;rsquo;t
minting a fresh identity per project.&lt;/p&gt;
&lt;p&gt;Mateu came at the same topic from the scar tissue side. At a former job he spent
an entire day — hundreds of messages back and forth — chasing permissions one
piece at a time, to the point where he couldn&amp;rsquo;t even see his own permissions
because he lacked permission to view them. His take: least privilege is great in
theory, but it falls apart when the people granting access don&amp;rsquo;t have full
knowledge of what&amp;rsquo;s needed, and it becomes a tax that slowly drains your will to
do the actual work.&lt;/p&gt;
&lt;p&gt;That tipped us into a broader gripe about process: how a small shop lets you just
pick something up and do it, and how every additional reviewer — team, then SRE,
then a security gate with nitpicks that aren&amp;rsquo;t even security-related — adds drag,
until a long-lived branch becomes a thing to dread. I admitted that a nitpicky AI
review sometimes reminds me of an annoying colleague; the difference is I can turn
that one off.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Claude&amp;rsquo;s note: there&amp;rsquo;s a real tension here that the agent era sharpens rather
than resolves. Aaron wants more granular identities so an agent can be trusted
with less; Mateu has lived the version where granularity becomes its own
full-time job. Both are right. The thing that makes scoped roles humane is good
tooling to see and apply them — which is exactly what Aaron liked about GCP and
exactly what was missing in Mateu&amp;rsquo;s story.&lt;/em&gt;&lt;/p&gt;
&lt;h2 id="the-bigger-themes"&gt;&lt;a class="heading-anchor" href="#the-bigger-themes" aria-label="Permalink to this section"&gt;#&lt;/a&gt;The Bigger Themes&lt;/h2&gt;
&lt;p&gt;A few threads ran through the whole session:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Tailscale changed the default.&lt;/strong&gt; Self-hosting used to mean port forwarding,
dynamic DNS, and a low-grade anxiety about what you&amp;rsquo;d exposed. The whole table
has quietly moved to a private overlay network where the hard question is no
longer &amp;ldquo;is this safe to expose&amp;rdquo; but &amp;ldquo;what do I want to call it.&amp;rdquo; That&amp;rsquo;s a real
shift in posture.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The work is portable now.&lt;/strong&gt; Between Aaron&amp;rsquo;s coffee-shop SSH sessions and a
training plan that follows me to my phone calendar, the pattern is the same:
keep the work in one place on a VM, reach it from anywhere on the tailnet. The
device you&amp;rsquo;re holding stops mattering.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Scope the agent&amp;rsquo;s identity, not just its sandbox.&lt;/strong&gt; Last time the theme was
tighter isolation. This time it extended inward: not only &lt;em&gt;where&lt;/em&gt; the agent runs,
but &lt;em&gt;who it is&lt;/em&gt; when it acts. Role-based identities for agents are the logical
next step from role-based containers.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Process is the hidden cost.&lt;/strong&gt; The flip side of solo speed is that bureaucracy
is a tax you feel acutely once you&amp;rsquo;ve worked without it. The same instinct that
makes people scope their agents carefully also makes them allergic to ceremony
that doesn&amp;rsquo;t earn its keep.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Claude&amp;rsquo;s note: the through-line from v1 to v2 to v3 is consistent —
containerize, choose your models deliberately, shrink the blast radius. V3&amp;rsquo;s
contribution is that the boundary people care about is moving from the machine to
the identity.&lt;/em&gt;&lt;/p&gt;
&lt;h2 id="cadence"&gt;&lt;a class="heading-anchor" href="#cadence" aria-label="Permalink to this section"&gt;#&lt;/a&gt;Cadence&lt;/h2&gt;
&lt;p&gt;Same as before: we&amp;rsquo;ll keep doing these on an &lt;em&gt;ad hoc&lt;/em&gt; basis. Frequent enough to
keep up with what people are building, infrequent enough that it never becomes a
standing meeting.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="llm-block__foot"&gt;
&lt;span&gt;// end LLM-generated content&lt;/span&gt;
&lt;button type="button" class="llm-block__collapse" data-llm-collapse&gt;Hide&lt;/button&gt;
&lt;/div&gt;
&lt;/details&gt;
&lt;h2 id="where-this-is-going"&gt;&lt;a class="heading-anchor" href="#where-this-is-going" aria-label="Permalink to this section"&gt;#&lt;/a&gt;Where This Is Going&lt;/h2&gt;
&lt;p&gt;There will be a V4. If you&amp;rsquo;d like to join the next one, reach out.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;Related posts:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.olafalders.com/2026/03/16/ai-shoulder-surf-v1"&gt;AI Shoulder Surf V1&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.olafalders.com/2026/05/20/ai-shoulder-surf-v2"&gt;AI Shoulder Surf V2&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.olafalders.com/2026/01/15/can-others-explain-my-work-without-me"&gt;Can Others Explain My Work Without Me?&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;a href="https://www.olafalders.com/2026/06/09/ai-shoulder-surf-v3/"&gt;Read on website&lt;/a&gt;&lt;/p&gt;</content:encoded><media:content xmlns:media="http://search.yahoo.com/mrss/" url="https://www.olafalders.com/2026/06/09/ai-shoulder-surf-v3/featured.jpeg"/></item><item><title>The Great Perl Toolchain Summit CLI Throwdown 2026</title><link>https://www.olafalders.com/2026/05/21/the-great-pts-cli-throwdown-2026/</link><pubDate>Thu, 21 May 2026 00:00:00 +0000</pubDate><author>olaf@wundersolutions.com (Olaf Alders)</author><guid>https://www.olafalders.com/2026/05/21/the-great-pts-cli-throwdown-2026/</guid><description>A roundup of the command-line tools and terminal setups shared at the 2026 edition of our now-annual CLI throwdown at the Perl Toolchain Summit.</description><content:encoded>&lt;!-- markdownlint-disable MD003 MD033 MD046 --&gt;
&lt;p&gt;Last year a few of us at the Perl Toolchain Summit got together to trade
command-line tips. I &lt;a href="https://www.olafalders.com/2025/06/03/the-great-pts-cli-throwdown"&gt;wrote up the
notes&lt;/a&gt;. This year there was some
demand for a repeat, so we continued the tradition. Hopefully you find some
helpful tips.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Full disclosure: I don&amp;rsquo;t use AI to write the content of my blog posts, but in
this case I did get an assist from Claude, particularly in summarizing notes and
adding project links. Since this is meant to be a cheat sheet rather than a
piece of creative writing, I&amp;rsquo;m ok with using AI as a tool to help get the job
done.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;This year&amp;rsquo;s participants, in order of appearance, were:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://metacpan.org/author/LLAP"&gt;Leo Lapworth&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/ssoriche/dotfiles"&gt;Shawn Sorichetti&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/pjcj/base"&gt;Paul Johnson&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/mickeyn"&gt;Mickey Nasriachi&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/oalders/dot-files"&gt;Olaf Alders&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The initial post featured male wrestlers, so I&amp;rsquo;m hoping this year&amp;rsquo;s photo
provides a much needed counterbalance.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://www.olafalders.com/2026/05/21/the-great-pts-cli-throwdown-2026/featured.jpeg"&gt;&lt;img src="https://www.olafalders.com/2026/05/21/the-great-pts-cli-throwdown-2026/featured.jpeg" alt="featured"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;!-- markdownlint-disable-line --&gt;&lt;p class="attribution"&gt;"&lt;a rel="noopener noreferrer" href="https://www.flickr.com/photos/45646111@N00/27513236583"&gt;Jungle Kyona vs Natsumi Maki-japanese female&lt;/a&gt;" by &lt;a rel="noopener noreferrer" href="https://www.flickr.com/photos/45646111@N00"&gt;sabrebiade&lt;/a&gt; is marked with &lt;a rel="noopener noreferrer" href="https://creativecommons.org/publicdomain/mark/1.0/?ref=openverse"&gt;Public Domain Mark 1.0 &lt;img src="https://www.olafalders.com/img/cc/pd.svg" alt="" style="height: 1em;" /&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;details class="llm-block" open&gt;
&lt;summary class="llm-block__bar"&gt;
&lt;svg class="llm-block__spark" width="13" height="13" viewBox="0 0 16 16" aria-hidden="true"&gt;&lt;path d="M8 0l1.7 5.4L15 7l-5.3 1.6L8 14l-1.7-5.4L1 7l5.3-1.6z"/&gt;&lt;/svg&gt;
&lt;span class="llm-block__label"&gt;Contains LLM-generated content&lt;/span&gt;
&lt;span class="llm-block__by"&gt;not written by Olaf&lt;/span&gt;
&lt;span class="llm-block__toggle" aria-hidden="true"&gt;&lt;/span&gt;
&lt;/summary&gt;
&lt;div class="llm-block__body"&gt;
&lt;span class="llm-block__gutter" aria-hidden="true" style="background-image:url(&amp;#39;data:image/svg&amp;#43;xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNiIgaGVpZ2h0PSIxNDQiPjx0ZXh0IHRyYW5zZm9ybT0idHJhbnNsYXRlKDExIDE0NCkgcm90YXRlKC05MCkiIGZvbnQtZmFtaWx5PSJ1aS1tb25vc3BhY2UsIFNGTW9uby1SZWd1bGFyLCBNZW5sbywgbW9ub3NwYWNlIiBmb250LXNpemU9IjkuNSIgbGV0dGVyLXNwYWNpbmc9IjIiIGZpbGw9IiNiYjlhZjciIGZpbGwtb3BhY2l0eT0iMC41IiB4bWw6c3BhY2U9InByZXNlcnZlIj5DbGF1ZGUgc3VtbWFyeSDCtyA8L3RleHQ&amp;#43;PC9zdmc&amp;#43;&amp;#39;)"&gt;&lt;/span&gt;
&lt;h2 id="leos-picks"&gt;&lt;a class="heading-anchor" href="#leos-picks" aria-label="Permalink to this section"&gt;#&lt;/a&gt;Leo&amp;rsquo;s Picks&lt;/h2&gt;
&lt;h3 id="superpowers"&gt;&lt;a class="heading-anchor" href="#superpowers" aria-label="Permalink to this section"&gt;#&lt;/a&gt;&lt;a href="https://github.com/obra/superpowers"&gt;superpowers&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;An agentic skills framework and software-development methodology for coding
agents like Claude Code. Rather than diving straight into writing code, it
pushes the agent to tease a spec out of the conversation, get your sign-off,
and then work through an implementation plan with an emphasis on test-driven
development.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Olaf&amp;rsquo;s note: superpowers deserves its own series of posts. I rely on this
quite heavily for all sorts of daily tasks.&lt;/em&gt;&lt;/p&gt;
&lt;h3 id="nono"&gt;&lt;a class="heading-anchor" href="#nono" aria-label="Permalink to this section"&gt;#&lt;/a&gt;&lt;a href="https://github.com/always-further/nono"&gt;nono&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;A capability-based sandbox for AI agents and other untrusted processes. It uses
kernel-level primitives — Landlock on Linux, Seatbelt on macOS — to enforce a
default-deny policy, so a process starts with no file, network, or command
access until you explicitly grant it.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Olaf&amp;rsquo;s note: I use nono every day, thanks to Leo having pointed it out shortly
before we got together for the summit. Now I spend a lot less time building
Docker containers. 😅&lt;/em&gt;&lt;/p&gt;
&lt;h2 id="shawns-picks"&gt;&lt;a class="heading-anchor" href="#shawns-picks" aria-label="Permalink to this section"&gt;#&lt;/a&gt;Shawn&amp;rsquo;s Picks&lt;/h2&gt;
&lt;h3 id="eza"&gt;&lt;a class="heading-anchor" href="#eza" aria-label="Permalink to this section"&gt;#&lt;/a&gt;&lt;a href="https://github.com/eza-community/eza"&gt;eza&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;A modern replacement for &lt;code&gt;ls&lt;/code&gt; with colourful, human-friendly output and git
integration for directories. &lt;em&gt;Claude&amp;rsquo;s note: eza was also a pick in &lt;a href="https://www.olafalders.com/2025/06/03/the-great-pts-cli-throwdown"&gt;last
year&amp;rsquo;s throwdown&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;
&lt;h3 id="fx"&gt;&lt;a class="heading-anchor" href="#fx" aria-label="Permalink to this section"&gt;#&lt;/a&gt;&lt;a href="https://github.com/antonmedv/fx"&gt;fx&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;A terminal-based JSON viewer and processor. It offers an interactive mode for
exploring large JSON documents as well as a scriptable mode for transforming
them, which makes it handy as an alternative to reaching for &lt;code&gt;jq&lt;/code&gt;.&lt;/p&gt;
&lt;h3 id="flox"&gt;&lt;a class="heading-anchor" href="#flox" aria-label="Permalink to this section"&gt;#&lt;/a&gt;&lt;a href="https://flox.dev/"&gt;Flox&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;A package and environment manager built on Nix. Flox installs sandboxed
binaries, pins their versions, and lets you reproduce the same development
environment across machines and projects.&lt;/p&gt;
&lt;h3 id="zoxide"&gt;&lt;a class="heading-anchor" href="#zoxide" aria-label="Permalink to this section"&gt;#&lt;/a&gt;&lt;a href="https://github.com/ajeetdsouza/zoxide"&gt;zoxide&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;A smarter &lt;code&gt;cd&lt;/code&gt; command. It remembers the directories you visit most and lets
you jump straight to them with a few characters instead of typing out full
paths.&lt;/p&gt;
&lt;h3 id="fish"&gt;&lt;a class="heading-anchor" href="#fish" aria-label="Permalink to this section"&gt;#&lt;/a&gt;&lt;a href="https://fishshell.com/"&gt;fish&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;A user-friendly shell with syntax highlighting, autosuggestions, and smart tab
completion out of the box. &lt;em&gt;Claude&amp;rsquo;s note: fish made the list in &lt;a href="https://www.olafalders.com/2025/06/03/the-great-pts-cli-throwdown"&gt;the 2025
throwdown&lt;/a&gt; too.&lt;/em&gt;&lt;/p&gt;
&lt;h3 id="fastgron"&gt;&lt;a class="heading-anchor" href="#fastgron" aria-label="Permalink to this section"&gt;#&lt;/a&gt;&lt;a href="https://github.com/adamritter/fastgron"&gt;fastgron&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;A high-performance implementation of &lt;code&gt;gron&lt;/code&gt;, which turns JSON into discrete,
greppable assignment statements — one path per line — so you can search
structured data with ordinary tools like &lt;code&gt;grep&lt;/code&gt;. Running &lt;code&gt;fastgron -u&lt;/code&gt; performs
the reverse transformation, reassembling the flattened output back into JSON.&lt;/p&gt;
&lt;h3 id="wezterm"&gt;&lt;a class="heading-anchor" href="#wezterm" aria-label="Permalink to this section"&gt;#&lt;/a&gt;&lt;a href="https://github.com/wezterm/wezterm"&gt;wezterm&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;A GPU-accelerated, cross-platform terminal emulator and multiplexer written in
Rust. &lt;em&gt;Claude&amp;rsquo;s note: WezTerm was &lt;a href="https://www.olafalders.com/2025/06/03/the-great-pts-cli-throwdown"&gt;a 2025 pick&lt;/a&gt;
as well.&lt;/em&gt;&lt;/p&gt;
&lt;h3 id="q"&gt;&lt;a class="heading-anchor" href="#q" aria-label="Permalink to this section"&gt;#&lt;/a&gt;&lt;a href="https://github.com/natesales/q"&gt;q&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;A tiny command-line DNS client, positioned as a modern replacement for &lt;code&gt;dig&lt;/code&gt;.
Alongside the classic UDP and TCP transports it speaks DoT, DoH, DoQ, and ODoH,
and can emit results as raw dig-style output, JSON, or YAML.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Olaf&amp;rsquo;s note: fun fact, &lt;code&gt;dig&lt;/code&gt; apparently stands for &lt;code&gt;domain information groper&lt;/code&gt;&lt;/em&gt;&lt;/p&gt;
&lt;h3 id="jujutsu"&gt;&lt;a class="heading-anchor" href="#jujutsu" aria-label="Permalink to this section"&gt;#&lt;/a&gt;&lt;a href="https://github.com/jj-vcs/jj"&gt;Jujutsu&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;A Git-compatible version control system. Jujutsu (&lt;code&gt;jj&lt;/code&gt;) uses a Git repository as
its storage layer, so it interoperates with existing Git tooling while offering
a different — and arguably simpler — working model on top of it.&lt;/p&gt;
&lt;h3 id="dyff"&gt;&lt;a class="heading-anchor" href="#dyff" aria-label="Permalink to this section"&gt;#&lt;/a&gt;&lt;a href="https://github.com/homeport/dyff"&gt;dyff&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;A diff tool for YAML (and JSON) files. Unlike a plain textual diff, &lt;code&gt;dyff&lt;/code&gt;
compares documents structurally, so two YAML files that hold the same data in a
different key order are correctly reported as equivalent.&lt;/p&gt;
&lt;h3 id="cswap"&gt;&lt;a class="heading-anchor" href="#cswap" aria-label="Permalink to this section"&gt;#&lt;/a&gt;&lt;a href="https://github.com/realiti4/claude-swap"&gt;cswap&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;A switcher for multiple Claude accounts that works with both the Claude Code
CLI and the VS Code extension. &lt;code&gt;cswap --list&lt;/code&gt; shows each account along with its
5-hour and 7-day usage and reset times, so you can check your quotas before
deciding which account to switch to.&lt;/p&gt;
&lt;h3 id="maccy"&gt;&lt;a class="heading-anchor" href="#maccy" aria-label="Permalink to this section"&gt;#&lt;/a&gt;&lt;a href="https://github.com/p0deje/Maccy"&gt;Maccy&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;A lightweight clipboard-history manager for macOS. It keeps a searchable history
of what you have copied and makes earlier entries available again with a
keyboard shortcut.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Olaf&amp;rsquo;s note: I use Alfred as my clipboard history manager, but I should check this out&lt;/em&gt;&lt;/p&gt;
&lt;h3 id="gcrane"&gt;&lt;a class="heading-anchor" href="#gcrane" aria-label="Permalink to this section"&gt;#&lt;/a&gt;&lt;a href="https://github.com/google/go-containerregistry/blob/main/cmd/gcrane/README.md"&gt;gcrane&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;A command-line tool from Google&amp;rsquo;s &lt;code&gt;go-containerregistry&lt;/code&gt; project for inspecting
and manipulating container images directly in a registry — listing tags,
copying images, and examining metadata without a full &lt;code&gt;docker pull&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id="pauls-picks"&gt;&lt;a class="heading-anchor" href="#pauls-picks" aria-label="Permalink to this section"&gt;#&lt;/a&gt;Paul&amp;rsquo;s Picks&lt;/h2&gt;
&lt;h3 id="aerospace"&gt;&lt;a class="heading-anchor" href="#aerospace" aria-label="Permalink to this section"&gt;#&lt;/a&gt;&lt;a href="https://github.com/nikitabobko/AeroSpace"&gt;AeroSpace&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;An i3-inspired tiling window manager for macOS. It arranges windows
automatically, manages workspaces, and is driven entirely from the keyboard.
&lt;em&gt;Claude&amp;rsquo;s note: AeroSpace was &lt;a href="https://www.olafalders.com/2025/06/03/the-great-pts-cli-throwdown"&gt;Shawn&amp;rsquo;s pick last
year&lt;/a&gt; — this year it changed hands.&lt;/em&gt;&lt;/p&gt;
&lt;h3 id="ghostty"&gt;&lt;a class="heading-anchor" href="#ghostty" aria-label="Permalink to this section"&gt;#&lt;/a&gt;&lt;a href="https://ghostty.org/"&gt;Ghostty&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;A fast, native, GPU-accelerated terminal emulator. Paul has switched to Ghostty
from WezTerm, which was his terminal of choice in &lt;a href="https://www.olafalders.com/2025/06/03/the-great-pts-cli-throwdown"&gt;last year&amp;rsquo;s
throwdown&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id="zsh"&gt;&lt;a class="heading-anchor" href="#zsh" aria-label="Permalink to this section"&gt;#&lt;/a&gt;&lt;a href="https://www.zsh.org/"&gt;zsh&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;An extended shell with powerful completion, scripting capabilities, and a deep
plugin ecosystem. &lt;em&gt;Claude&amp;rsquo;s note: zsh also featured in &lt;a href="https://www.olafalders.com/2025/06/03/the-great-pts-cli-throwdown"&gt;the 2025
throwdown&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;
&lt;h2 id="mickeys-one-weird-trick--shell-wizards-hate-him"&gt;&lt;a class="heading-anchor" href="#mickeys-one-weird-trick--shell-wizards-hate-him" aria-label="Permalink to this section"&gt;#&lt;/a&gt;Mickey&amp;rsquo;s One Weird Trick — Shell Wizards HATE Him&lt;/h2&gt;
&lt;h3 id="process-substitution-with-"&gt;&lt;a class="heading-anchor" href="#process-substitution-with-" aria-label="Permalink to this section"&gt;#&lt;/a&gt;Process substitution with &lt;code&gt;&amp;lt;()&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;Mickey&amp;rsquo;s contribution wasn&amp;rsquo;t a tool to install but a shell feature worth
knowing: process substitution. The &lt;code&gt;&amp;lt;(...)&lt;/code&gt; syntax runs a command and presents
its output as if it were a file, which lets you feed command output to programs
that expect a filename.&lt;/p&gt;
&lt;p&gt;A couple of examples of where this comes in handy.&lt;/p&gt;
&lt;p&gt;Compare the output of two commands without creating temporary files:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# See how the contents of two directories differ&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;diff &amp;lt;&lt;span class="o"&gt;(&lt;/span&gt;ls dir-one&lt;span class="o"&gt;)&lt;/span&gt; &amp;lt;&lt;span class="o"&gt;(&lt;/span&gt;ls dir-two&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# Compare the installed packages on two hosts&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;diff &amp;lt;&lt;span class="o"&gt;(&lt;/span&gt;ssh host1 &lt;span class="s1"&gt;&amp;#39;dpkg --get-selections&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &amp;lt;&lt;span class="o"&gt;(&lt;/span&gt;ssh host2 &lt;span class="s1"&gt;&amp;#39;dpkg --get-selections&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Feed remote or generated content to a tool that expects a file on disk:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# grep a remote file without downloading it first&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;grep &lt;span class="s1"&gt;&amp;#39;TODO&amp;#39;&lt;/span&gt; &amp;lt;&lt;span class="o"&gt;(&lt;/span&gt;curl -s https://example.com/notes.txt&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# Find the lines common to two sorted lists&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;comm -12 &amp;lt;&lt;span class="o"&gt;(&lt;/span&gt;sort a.txt&lt;span class="o"&gt;)&lt;/span&gt; &amp;lt;&lt;span class="o"&gt;(&lt;/span&gt;sort b.txt&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;There is also a companion form, &lt;code&gt;&amp;gt;(...)&lt;/code&gt;, which provides a filename that pipes
&lt;em&gt;into&lt;/em&gt; a command — useful when a tool insists on writing to an output file but
you would rather stream the result somewhere else.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="llm-block__foot"&gt;
&lt;span&gt;// end LLM-generated content&lt;/span&gt;
&lt;button type="button" class="llm-block__collapse" data-llm-collapse&gt;Hide&lt;/button&gt;
&lt;/div&gt;
&lt;/details&gt;
&lt;p&gt;One caveat, &lt;a href="https://fosstodon.org/@DrHyde/116613154659622283"&gt;via David Cantrell on
Mastodon&lt;/a&gt;: &lt;code&gt;&amp;lt;(...)&lt;/code&gt; doesn&amp;rsquo;t
give you a real &lt;em&gt;file&lt;/em&gt;, it gives you a &lt;em&gt;pipe&lt;/em&gt;. Most tools don&amp;rsquo;t care, but some
will fail in confusing ways — for instance, a script that checks whether its
input is a readable file before doing anything will refuse to proceed.&lt;/p&gt;
&lt;h2 id="olaf-should-not-have-chosen-to-go-last"&gt;&lt;a class="heading-anchor" href="#olaf-should-not-have-chosen-to-go-last" aria-label="Permalink to this section"&gt;#&lt;/a&gt;Olaf Should Not Have Chosen to Go Last&lt;/h2&gt;
&lt;p&gt;I didn&amp;rsquo;t have a lot to contribute this year since I haven&amp;rsquo;t written much code
in the past year, having foisted most of that responsibility onto Claude.
Having said that, Leo&amp;rsquo;s picks of &lt;code&gt;superpowers&lt;/code&gt; and &lt;code&gt;nono&lt;/code&gt; are game changers for
me and I&amp;rsquo;m still in love with &lt;code&gt;WezTerm&lt;/code&gt;. I also did share my &lt;a href="https://www.olafalders.com/2026/01/15/can-others-explain-my-work-without-me/"&gt;talk about
us&lt;/a&gt; AI skill, which is
helpful in auditing everything from blog posts, to resumes. I believe that
qualifies as a CLI tool, even if it also works in browsers.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://www.olafalders.com/2026/05/21/the-great-pts-cli-throwdown-2026/"&gt;Read on website&lt;/a&gt;&lt;/p&gt;</content:encoded><media:content xmlns:media="http://search.yahoo.com/mrss/" url="https://www.olafalders.com/2026/05/21/the-great-pts-cli-throwdown-2026/featured.jpeg"/></item><item><title>AI Shoulder Surf V2</title><link>https://www.olafalders.com/2026/05/20/ai-shoulder-surf-v2/</link><pubDate>Wed, 20 May 2026 00:00:00 +0000</pubDate><author>olaf@wundersolutions.com (Olaf Alders)</author><guid>https://www.olafalders.com/2026/05/20/ai-shoulder-surf-v2/</guid><description>The second AI Shoulder Surf — a friendly group on Zoom, no recording, honest notes on the AI tools they're really using and where they sandbox them.</description><content:encoded>&lt;!-- markdownlint-disable MD003 MD033 MD046 --&gt;
&lt;p&gt;Back on April 1, 2026 we had our second AI Shoulder Surf. &lt;a href="https://www.olafalders.com/2026/03/16/ai-shoulder-surf-v1"&gt;I wrote up the first
of these sessions last time around&lt;/a&gt;. It&amp;rsquo;s
basically an informal Zoom call where we share screens, talk about what we&amp;rsquo;re
working on, and admit what we don&amp;rsquo;t know. No video recording, to keep the
stress and performative aspect of video calls out of it, and to leave space for
asking questions without posturing. Admitting to knowledge gaps is not a
problem for me personally, because knowledge gaps are basically all I have, but
I want other people to have a safe space too.&lt;/p&gt;
&lt;p&gt;What follows is again a combination of a factual AI summary and my
own commentary. I had an assist but it&amp;rsquo;s not slop. The target audience is
mostly the folks who were on the call, but I&amp;rsquo;ll be happy if anyone else gets
something out of it.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://www.olafalders.com/2026/05/20/ai-shoulder-surf-v2/featured.jpeg"&gt;&lt;img src="https://www.olafalders.com/2026/05/20/ai-shoulder-surf-v2/featured.jpeg" alt="featured"&gt;&lt;/a&gt; &lt;!-- markdownlint-disable-line --&gt;&lt;/p&gt;
&lt;p class="attribution"&gt;"&lt;a rel="noopener noreferrer" href="https://www.flickr.com/photos/30492852@N00/11281061303"&gt;Cardiff Kook, December 8 2013&lt;/a&gt;" by &lt;a rel="noopener noreferrer" href="https://www.flickr.com/photos/30492852@N00"&gt;Tim Buss&lt;/a&gt; is licensed under &lt;a rel="noopener noreferrer" href="https://creativecommons.org/licenses/by/2.0/?ref=openverse"&gt;CC BY 2.0 &lt;img src="https://www.olafalders.com/img/cc/cc.svg" alt="" style="height: 1em;" /&gt;&lt;img src="https://www.olafalders.com/img/cc/by.svg" alt="" style="height: 1em;" /&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;details class="llm-block" open&gt;
&lt;summary class="llm-block__bar"&gt;
&lt;svg class="llm-block__spark" width="13" height="13" viewBox="0 0 16 16" aria-hidden="true"&gt;&lt;path d="M8 0l1.7 5.4L15 7l-5.3 1.6L8 14l-1.7-5.4L1 7l5.3-1.6z"/&gt;&lt;/svg&gt;
&lt;span class="llm-block__label"&gt;Contains LLM-generated content&lt;/span&gt;
&lt;span class="llm-block__by"&gt;not written by Olaf&lt;/span&gt;
&lt;span class="llm-block__toggle" aria-hidden="true"&gt;&lt;/span&gt;
&lt;/summary&gt;
&lt;div class="llm-block__body"&gt;
&lt;span class="llm-block__gutter" aria-hidden="true" style="background-image:url(&amp;#39;data:image/svg&amp;#43;xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNiIgaGVpZ2h0PSIxMTIiPjx0ZXh0IHRyYW5zZm9ybT0idHJhbnNsYXRlKDExIDExMikgcm90YXRlKC05MCkiIGZvbnQtZmFtaWx5PSJ1aS1tb25vc3BhY2UsIFNGTW9uby1SZWd1bGFyLCBNZW5sbywgbW9ub3NwYWNlIiBmb250LXNpemU9IjkuNSIgbGV0dGVyLXNwYWNpbmc9IjIiIGZpbGw9IiNiYjlhZjciIGZpbGwtb3BhY2l0eT0iMC41IiB4bWw6c3BhY2U9InByZXNlcnZlIj5BSSBzdW1tYXJ5IMK3IDwvdGV4dD48L3N2Zz4=&amp;#39;)"&gt;&lt;/span&gt;
&lt;h2 id="daniel-incuslxd-coding-sandbox"&gt;&lt;a class="heading-anchor" href="#daniel-incuslxd-coding-sandbox" aria-label="Permalink to this section"&gt;#&lt;/a&gt;Daniel: Incus/LXD Coding Sandbox&lt;/h2&gt;
&lt;p&gt;First off Daniel demoed &lt;a href="https://github.com/dehnhard/coding-sandbox"&gt;coding-sandbox&lt;/a&gt;,
which he had been building for several weeks around an
&lt;a href="https://linuxcontainers.org/incus/"&gt;Incus&lt;/a&gt;/&lt;a href="https://canonical.com/lxd"&gt;LXD&lt;/a&gt;
sandbox. He landed on LXD over QEMU/KVM and VirtualBox because the CLI is
faster, mounting directories is more Docker-like, and the whole setup leans
well into the ephemeral-container model.&lt;/p&gt;
&lt;p&gt;There are two execution modes:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Ephemeral container&lt;/strong&gt; (the default): built from scratch on top of Debian
and Bash, with a unique directory per session. Cheap to spin up, cheap to
throw away.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;VM&lt;/strong&gt;: persistent storage, but expect roughly ten minutes the first time
to build images and install tooling.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;To avoid hitting the public internet every rebuild, Daniel runs an APT cache
on his local network. The package of interest is
&lt;a href="https://wiki.debian.org/AptCacherNg"&gt;&lt;code&gt;apt-cacher-ng&lt;/code&gt;&lt;/a&gt; — multiple machines on
the LAN pull from a central cache, which is handy both for testing new images
without re-downloading the world and for keeping packages in sync across
machines.&lt;/p&gt;
&lt;p&gt;He demoed two variants: a standard coding sandbox and a &amp;ldquo;quick&amp;rdquo; coding sandbox
on top of an Ubuntu image with Node.js as a baseline dependency. Inside the
sandbox he&amp;rsquo;s tested several coding tools so far — &lt;a href="https://www.claude.com/product/claude-code"&gt;Claude Code&lt;/a&gt;,
&lt;a href="https://qwen.ai/qwencode"&gt;Qwen Code&lt;/a&gt;, and &lt;a href="https://opencode.ai/"&gt;OpenCode&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;There&amp;rsquo;s still some polishing to do on the setup script for general usability,
and he&amp;rsquo;s eyeing automation around the Chrome connection.&lt;/p&gt;
&lt;h2 id="ingy-sandboxing-via-kvm"&gt;&lt;a class="heading-anchor" href="#ingy-sandboxing-via-kvm" aria-label="Permalink to this section"&gt;#&lt;/a&gt;Ingy: Sandboxing via KVM&lt;/h2&gt;
&lt;p&gt;Ingy talked about a how he keeps Claude in a sandbox using KVM, motivated by the
realization that the AI agents he was running had access to a lot more of his
machine than he was really comfortable with. Once you start thinking about API
keys, credentials, and what a misbehaving agent could touch, the appeal of a
heavier isolation boundary goes up quickly. He also brought up the importance
of limited-access roles and proper backups.&lt;/p&gt;
&lt;p&gt;Daniel chimed in to suggest Incus as worth trying for development use —
similar reasoning, lighter footprint than full VMs.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Claude&amp;rsquo;s note: this thread tracked closely with the &amp;ldquo;containerization for
safety&amp;rdquo; theme from the v1 writeup. The trend line in this group is unambiguous:
people are tightening up the blast radius of their agents, not loosening it.&lt;/em&gt;&lt;/p&gt;
&lt;h2 id="claude-performance-and-pricing"&gt;&lt;a class="heading-anchor" href="#claude-performance-and-pricing" aria-label="Permalink to this section"&gt;#&lt;/a&gt;Claude: Performance and Pricing&lt;/h2&gt;
&lt;p&gt;There was a long, slightly grumpy thread about Claude performance. People
reported high load averages and slow processing, which led Ingy to wonder out
loud whether KVM was making things worse and to float external VMs at
&lt;a href="https://www.hetzner.com/"&gt;Hetzner&lt;/a&gt; as an option. Daniel made the counter-case
that containers might actually be better here, since they use system resources
directly rather than virtualizing them.&lt;/p&gt;
&lt;p&gt;On pricing: Ingy is on the $100/month tier and says he never hits limits. I&amp;rsquo;m
also on $100/month and hit them regularly. Same plan, very different
experience. That gap is interesting in its own right — it depends a lot on
what you ask Claude to do, how much you let it run, and whether you&amp;rsquo;re
running things overnight.&lt;/p&gt;
&lt;p&gt;There was also a passing mention of a known bug in the Claude CLI where
processing can get stuck and the fix is to kill and restart. Nothing
ground-breaking, but worth knowing when you&amp;rsquo;re staring at a frozen prompt at
midnight.&lt;/p&gt;
&lt;p&gt;We also chatted about using the &lt;code&gt;CLAUDE_CODE_DISABLE_1M_CONTEXT=1&lt;/code&gt; env var to
keep Claude at the 200k token ceiling. I have almost never used 1 million
tokens and I don&amp;rsquo;t feel like I&amp;rsquo;m missing out.&lt;/p&gt;
&lt;h2 id="tools-roundup"&gt;&lt;a class="heading-anchor" href="#tools-roundup" aria-label="Permalink to this section"&gt;#&lt;/a&gt;Tools Roundup&lt;/h2&gt;
&lt;p&gt;A quick lap around what people were trying:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Eugen&lt;/strong&gt;: positive experience with &lt;a href="https://cursor.com/"&gt;Cursor&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Mateu&lt;/strong&gt;: using OpenCode with GPT-5.4. He noted improved security
features as a reason for sticking with that combination.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Daniel&lt;/strong&gt;: pointed out that AI recommendations can be inconsistent between
sessions and tools — likely because of the different &amp;ldquo;bubbles&amp;rdquo; or contexts
the model is operating in. The same question can get a different answer
depending on what else is loaded into the context window.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;em&gt;Claude&amp;rsquo;s note: the &amp;ldquo;bubbles&amp;rdquo; framing stuck with me. It&amp;rsquo;s a useful way to
explain why two people can ask the same model the same question and walk away
with different answers. The model didn&amp;rsquo;t change — the surrounding context
did.&lt;/em&gt;&lt;/p&gt;
&lt;h2 id="mateu-tuning-berts-personality"&gt;&lt;a class="heading-anchor" href="#mateu-tuning-berts-personality" aria-label="Permalink to this section"&gt;#&lt;/a&gt;Mateu: Tuning Bert&amp;rsquo;s Personality&lt;/h2&gt;
&lt;p&gt;Mateu walked through some work on tuning his bot Bert&amp;rsquo;s personality — mostly
in the direction of &lt;em&gt;talking less&lt;/em&gt;.&lt;/p&gt;
&lt;h2 id="the-bigger-themes"&gt;&lt;a class="heading-anchor" href="#the-bigger-themes" aria-label="Permalink to this section"&gt;#&lt;/a&gt;The Bigger Themes&lt;/h2&gt;
&lt;p&gt;A few threads ran through the whole session:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Tighter isolation, not looser.&lt;/strong&gt; Between Daniel&amp;rsquo;s Incus/LXD work and Ingy&amp;rsquo;s
use of KVM, the direction of travel is clear: as agents do more, people want
them to be able to touch less. Containers and VMs aren&amp;rsquo;t just for production
anymore — they&amp;rsquo;re a development-environment hygiene question.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Same plan, different mileage.&lt;/strong&gt; Two people on the same $100/month Claude
plan can have wildly different experiences with rate limits and performance.
That makes blanket statements about value-for-money basically useless. What
actually matters is &lt;em&gt;your&lt;/em&gt; workload pattern.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Context bubbles.&lt;/strong&gt; Daniel&amp;rsquo;s &amp;ldquo;bubbles&amp;rdquo; observation — that AI recommendations
shift based on the surrounding context — explains a lot of disagreements that
look like disagreements about the model but are really about what&amp;rsquo;s been
loaded into the conversation. Worth keeping in mind the next time someone
tells you &amp;ldquo;Claude said X.&amp;rdquo; Claude said X &lt;em&gt;given everything else in the
session&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Less talkative is better.&lt;/strong&gt; Mateu&amp;rsquo;s work on Bert and the general drift of
the conversation pointed at the same thing: agents that respond with less,
more carefully, are easier to live with than agents that fill the screen.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Claude&amp;rsquo;s note: this is roughly the same shape of theme list as last time
(containerization, model choice, image input, &lt;code&gt;--chrome&lt;/code&gt;). I&amp;rsquo;d take that as a
sign that these are durable things to think about, not just first-session
novelty.&lt;/em&gt;&lt;/p&gt;
&lt;h2 id="cadence"&gt;&lt;a class="heading-anchor" href="#cadence" aria-label="Permalink to this section"&gt;#&lt;/a&gt;Cadence&lt;/h2&gt;
&lt;p&gt;We&amp;rsquo;re planning to keep doing these on an &lt;em&gt;ad hoc&lt;/em&gt; basis. Frequent enough
to actually keep up with what people are working on, infrequent enough that
nobody feels like it&amp;rsquo;s a standing meeting.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="llm-block__foot"&gt;
&lt;span&gt;// end LLM-generated content&lt;/span&gt;
&lt;button type="button" class="llm-block__collapse" data-llm-collapse&gt;Hide&lt;/button&gt;
&lt;/div&gt;
&lt;/details&gt;
&lt;h2 id="where-this-is-going"&gt;&lt;a class="heading-anchor" href="#where-this-is-going" aria-label="Permalink to this section"&gt;#&lt;/a&gt;Where This Is Going&lt;/h2&gt;
&lt;p&gt;V3 will happen soon. &lt;a href="https://luma.com/97x47tja"&gt;Sign up now&lt;/a&gt;.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;Related posts:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.olafalders.com/2026/03/16/ai-shoulder-surf-v1"&gt;AI Shoulder Surf V1&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.olafalders.com/2026/01/15/can-others-explain-my-work-without-me"&gt;Can Others Explain My Work Without Me?&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;a href="https://www.olafalders.com/2026/05/20/ai-shoulder-surf-v2/"&gt;Read on website&lt;/a&gt;&lt;/p&gt;</content:encoded><media:content xmlns:media="http://search.yahoo.com/mrss/" url="https://www.olafalders.com/2026/05/20/ai-shoulder-surf-v2/featured.jpeg"/></item><item><title>AI Shoulder Surf V1</title><link>https://www.olafalders.com/2026/03/16/ai-shoulder-surf-v1/</link><pubDate>Mon, 16 Mar 2026 00:00:00 +0000</pubDate><author>olaf@wundersolutions.com (Olaf Alders)</author><guid>https://www.olafalders.com/2026/03/16/ai-shoulder-surf-v1/</guid><description>Notes from an informal Zoom session where developers shared AI tools, automation techniques, and projects — covering everything from headless Claude in Makefiles to overnight bots that work while you sleep.</description><content:encoded>&lt;!-- markdownlint-disable MD003 MD033 MD046 --&gt;
&lt;p&gt;A while back I thought of having some regular office hours so that I could
share my screen with some friends and we could just talk about what we are
learning and working on. I think office hours are hard to sell unless you&amp;rsquo;re
some kind of expert or thought leader. I am neither of those things, but
I do enjoy showing what I&amp;rsquo;m working on. So, I proposed a &amp;ldquo;shoulder surf&amp;rdquo;
session where people could share screens and gab. No video recording was made,
in order to remove the stress and the performative aspect of video calls. It also
leaves space for asking questions and admitting you have knowledge gaps.
Admitting to not having answers is not a problem for me personally, because
knowledge gaps are basically all that I have, but I want other people to have a
safe space.&lt;/p&gt;
&lt;p&gt;I posted something on LinkedIn, texted some former colleagues whom I have been
keeping in touch with and we set up a meeting. I thought we&amp;rsquo;d have a handful of
folks, but we had a dozen and I learned a lot. This was the first session of at
least two. (I&amp;rsquo;m not making big plans).&lt;/p&gt;
&lt;p&gt;What follows is a combination of a factual AI summary of the call and some of
my comments. So, I did have an assist, but it&amp;rsquo;s also not slop. The target
audience of this post is the folks who were on the call, but maybe some others
will find the digest version useful.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://www.olafalders.com/2026/03/16/ai-shoulder-surf-v1/featured.jpeg"&gt;&lt;img src="https://www.olafalders.com/2026/03/16/ai-shoulder-surf-v1/featured.jpeg" alt="featured"&gt;&lt;/a&gt; &lt;!-- markdownlint-disable-line --&gt;&lt;/p&gt;
&lt;!-- markdownlint-disable-line --&gt;&lt;p class="attribution"&gt;"&lt;a target="_blank" rel="noopener noreferrer" href="https://www.flickr.com/photos/74105777@N00/9598190955"&gt;Peaking over @brad_frost's shoulder at An Event Apart&lt;/a&gt;" by &lt;a target="_blank" rel="noopener noreferrer" href="https://www.flickr.com/photos/74105777@N00"&gt;Jeremy Keith&lt;/a&gt; is licensed under &lt;a target="_blank" rel="noopener noreferrer" href="https://creativecommons.org/licenses/by/2.0/"&gt;CC BY 2.0 &lt;img src="https://www.olafalders.com/img/cc/cc.svg" alt="" style="height: 1em;" /&gt;&lt;img src="https://www.olafalders.com/img/cc/by.svg" alt="" style="height: 1em;" /&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;details class="llm-block" open&gt;
&lt;summary class="llm-block__bar"&gt;
&lt;svg class="llm-block__spark" width="13" height="13" viewBox="0 0 16 16" aria-hidden="true"&gt;&lt;path d="M8 0l1.7 5.4L15 7l-5.3 1.6L8 14l-1.7-5.4L1 7l5.3-1.6z"/&gt;&lt;/svg&gt;
&lt;span class="llm-block__label"&gt;Contains LLM-generated content&lt;/span&gt;
&lt;span class="llm-block__by"&gt;not written by Olaf&lt;/span&gt;
&lt;span class="llm-block__toggle" aria-hidden="true"&gt;&lt;/span&gt;
&lt;/summary&gt;
&lt;div class="llm-block__body"&gt;
&lt;span class="llm-block__gutter" aria-hidden="true" style="background-image:url(&amp;#39;data:image/svg&amp;#43;xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNiIgaGVpZ2h0PSIxMTIiPjx0ZXh0IHRyYW5zZm9ybT0idHJhbnNsYXRlKDExIDExMikgcm90YXRlKC05MCkiIGZvbnQtZmFtaWx5PSJ1aS1tb25vc3BhY2UsIFNGTW9uby1SZWd1bGFyLCBNZW5sbywgbW9ub3NwYWNlIiBmb250LXNpemU9IjkuNSIgbGV0dGVyLXNwYWNpbmc9IjIiIGZpbGw9IiNiYjlhZjciIGZpbGwtb3BhY2l0eT0iMC41IiB4bWw6c3BhY2U9InByZXNlcnZlIj5BSSBzdW1tYXJ5IMK3IDwvdGV4dD48L3N2Zz4=&amp;#39;)"&gt;&lt;/span&gt;
&lt;h2 id="mateu-openclaw-and-ai-generated-video"&gt;&lt;a class="heading-anchor" href="#mateu-openclaw-and-ai-generated-video" aria-label="Permalink to this section"&gt;#&lt;/a&gt;Mateu: OpenClaw and AI-Generated Video&lt;/h2&gt;
&lt;p&gt;Mateu kicked things off by demonstrating how he used AI to produce &lt;a href="https://www.youtube.com/watch?v=4QwQQiLk7pE"&gt;OpenClaw: Introduction &amp;amp; Memory Search Overview&lt;/a&gt;, a YouTube video explaining &lt;a href="https://github.com/openclaw/openclaw"&gt;OpenClaw&lt;/a&gt; — a project he&amp;rsquo;s been experimenting with. He runs it inside a Linux container on &lt;a href="https://www.proxmox.com/"&gt;Proxmox&lt;/a&gt; and used &lt;a href="https://manus.im/app"&gt;Manus&lt;/a&gt; to generate the video.&lt;/p&gt;
&lt;p&gt;On the cost side, Mateu has been happy with the &lt;a href="https://openai.com/codex"&gt;Codex
model&lt;/a&gt; at $20/month and finds it genuinely useful for
day-to-day work.&lt;/p&gt;
&lt;h2 id="ingy-headless-claude-in-a-makefile"&gt;&lt;a class="heading-anchor" href="#ingy-headless-claude-in-a-makefile" aria-label="Permalink to this section"&gt;#&lt;/a&gt;Ingy: Headless Claude in a Makefile&lt;/h2&gt;
&lt;p&gt;Ingy talked about &lt;a href="https://github.com/makeplus/makes"&gt;makes&lt;/a&gt;, and an automation that he put together just a few minutes before the call. It centres on a &lt;a href="https://github.com/makeplus/makes/blob/main/.claude/skills/version-update/SKILL.md"&gt;version-update skill&lt;/a&gt; that runs Claude in headless mode. The skill instructs Claude to:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Run &lt;code&gt;make version-check&lt;/code&gt; and capture the output&lt;/li&gt;
&lt;li&gt;Find all lines indicating an outdated version (&lt;code&gt;&amp;lt;file&amp;gt; &amp;lt;old-version&amp;gt; -&amp;gt; &amp;lt;new-version&amp;gt;&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Update the version string in each corresponding &lt;code&gt;.mk&lt;/code&gt; file&lt;/li&gt;
&lt;li&gt;Re-run &lt;code&gt;make version-check&lt;/code&gt; to confirm everything is current&lt;/li&gt;
&lt;li&gt;Commit the changes with a descriptive message&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;This is then wired up as a &lt;a href="https://github.com/makeplus/makes/blob/main/.github/workflows/version-update.yaml"&gt;GitHub Actions workflow&lt;/a&gt; that runs on a daily schedule. It checks out the repo, passes the &lt;code&gt;ANTHROPIC_API_KEY&lt;/code&gt;, runs &lt;code&gt;make version-update&lt;/code&gt;, and pushes any commits if versions changed.&lt;/p&gt;
&lt;p&gt;Ingy described this as a shift toward building &lt;strong&gt;agent-friendly tooling&lt;/strong&gt; rather than just human-centric tools. The skill file is the spec; Claude is the executor.&lt;/p&gt;
&lt;h2 id="olaf-the-talk-about-us-skill"&gt;&lt;a class="heading-anchor" href="#olaf-the-talk-about-us-skill" aria-label="Permalink to this section"&gt;#&lt;/a&gt;Olaf: The &amp;ldquo;Talk About Us&amp;rdquo; Skill&lt;/h2&gt;
&lt;p&gt;I presented the &lt;a href="https://github.com/oalders/talk-about-us"&gt;talk-about-us&lt;/a&gt; skill, which I wrote about at length in an &lt;a href="https://www.olafalders.com/2026/01/15/can-others-explain-my-work-without-me"&gt;earlier post&lt;/a&gt;. The short version: it&amp;rsquo;s derived from &lt;a href="https://www.anildash.com/2025/12/05/talk-about-us-without-us/"&gt;Anil Dash&amp;rsquo;s framework&lt;/a&gt; for writing copy that other people can repeat accurately without you in the room.&lt;/p&gt;
&lt;p&gt;The skill audits text for jargon, distinctiveness, emotional resonance, and value-first messaging. It gives frank feedback and rewrite suggestions while preserving the author&amp;rsquo;s voice. Friends have found it useful for blog posts, sponsor emails, resumes, and grant proposals. It gives you the honest outside perspective that&amp;rsquo;s hard to get when you&amp;rsquo;re too close to your own work.&lt;/p&gt;
&lt;p&gt;The skill itself was written using superpowers&amp;rsquo; &lt;a href="https://github.com/obra/superpowers/tree/main/skills/writing-skills"&gt;skill-writing skill&lt;/a&gt; — a nice example of using the tools to build the tools.&lt;/p&gt;
&lt;h2 id="nico-the-bot-that-works-while-you-sleep"&gt;&lt;a class="heading-anchor" href="#nico-the-bot-that-works-while-you-sleep" aria-label="Permalink to this section"&gt;#&lt;/a&gt;Nico: The Bot That Works While You Sleep&lt;/h2&gt;
&lt;p&gt;Nico showed off the most ambitious automation of the afternoon: &lt;a href="https://github.com/sukria/koan"&gt;koan&lt;/a&gt;, a bot system designed to maximize Claude quota usage during off-hours. While he&amp;rsquo;s asleep, the bot:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Processes a queue of GitHub issues&lt;/li&gt;
&lt;li&gt;Implements fixes and creates pull requests&lt;/li&gt;
&lt;li&gt;Responds to PR comments&lt;/li&gt;
&lt;li&gt;Runs multiple refinement passes: implementation, refactor, security audit&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The queue is accessible via Telegram, which means Nico can add tasks to the pipeline from his phone before bed and wake up to completed pull requests. It&amp;rsquo;s queue-based, runs unattended, and uses iterative passes to improve code quality rather than trying to get everything right in one shot. The combination of multiple refinement stages and overnight execution is clever — the quota limits that would be annoying during the day become a non-issue when you have eight hours.&lt;/p&gt;
&lt;h2 id="the-bigger-themes"&gt;&lt;a class="heading-anchor" href="#the-bigger-themes" aria-label="Permalink to this section"&gt;#&lt;/a&gt;The Bigger Themes&lt;/h2&gt;
&lt;p&gt;A few threads ran through the whole session:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Specification over code.&lt;/strong&gt; Todd made the case that the future of development is writing detailed specifications rather than code. The measure of success isn&amp;rsquo;t whether the code is correct — it&amp;rsquo;s whether the tests validate the expected behavior. He argued this requires roughly 10x more tests than traditional development. The &lt;a href="https://agentskills.io/specification"&gt;Agent Skills specification&lt;/a&gt; is worth reading if this resonates with you.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Model selection matters.&lt;/strong&gt; Most people in the group have settled on Claude Opus for serious development work. The $100/month cost is real, but the quality difference justifies it when you&amp;rsquo;re using AI as a core part of your workflow rather than an occasional helper.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Editor&amp;rsquo;s note: there was some discussion about using the Haiku model and having issues getting quality code back out of it. I do think it&amp;rsquo;s going to be an uphill battle to get great results out of Haiku for everything. There are, however, some things it does very well. I use it to extract event and organization details out of web pages for &lt;a href="https://mymindisracing.com/"&gt;My Mind is Racing&lt;/a&gt;. I would not use it to produce code, but for less complex tasks it can be a significant money saver.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Containerization for safety.&lt;/strong&gt; There was broad agreement that running AI agents in isolated environments — Docker, KVM, &lt;a href="https://linuxcontainers.org/incus/"&gt;Incus&lt;/a&gt; — is important for anything that touches real systems. You want controlled, auditable access, not a process that can reach anywhere it wants. See also this walkthrough on &lt;a href="https://mensfeld.pl/2026/01/claude-on-incus-all-the-autonomy-securely/"&gt;Claude on Incus&lt;/a&gt; if you want a practical starting point.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Editor&amp;rsquo;s note: I&amp;rsquo;ve spent a fair amount of time getting custom Docker containers set up so that I can let Claude essentially run hog wild while I sleep. While this is a good fit for my particular use case right now, I&amp;rsquo;m looking forward to trying out more lightweight solutions.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Image input is underused.&lt;/strong&gt; Several people mentioned that feeding screenshots and photos to Claude for debugging is surprisingly effective. When you&amp;rsquo;re staring at a visual bug or a confusing terminal output, sometimes the fastest path is just to take a screenshot and ask.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;--chrome&lt;/code&gt; is worth knowing about.&lt;/strong&gt; Claude&amp;rsquo;s &lt;code&gt;--chrome&lt;/code&gt; flag enables browser control, which opens up front-end testing automation that would otherwise require a separate framework. A few people hadn&amp;rsquo;t heard of it and were immediately interested.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Editor&amp;rsquo;s note: &lt;a href="https://github.com/microsoft/playwright-mcp"&gt;Playwright MCP Server&lt;/a&gt; can be very handy for inspecting web content as well as the network requests involved.&lt;/em&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;div class="llm-block__foot"&gt;
&lt;span&gt;// end LLM-generated content&lt;/span&gt;
&lt;button type="button" class="llm-block__collapse" data-llm-collapse&gt;Hide&lt;/button&gt;
&lt;/div&gt;
&lt;/details&gt;
&lt;h2 id="addendum"&gt;&lt;a class="heading-anchor" href="#addendum" aria-label="Permalink to this section"&gt;#&lt;/a&gt;Addendum&lt;/h2&gt;
&lt;p&gt;I&amp;rsquo;m not sure if this actually, came up but I&amp;rsquo;ve been using &lt;a href="https://github.com/ali-nr/claude-pulse"&gt;claude-pulse&lt;/a&gt; status line for Claude Code that gives you some visibility into what the agent is doing right now, especially around token usage. I get a lot out of that.&lt;/p&gt;
&lt;h2 id="where-this-is-going"&gt;&lt;a class="heading-anchor" href="#where-this-is-going" aria-label="Permalink to this section"&gt;#&lt;/a&gt;Where This Is Going&lt;/h2&gt;
&lt;p&gt;We&amp;rsquo;ll do this again at least one more time. If you want to join the next session, reach out.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;Related posts:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.olafalders.com/2026/05/20/ai-shoulder-surf-v2"&gt;AI Shoulder Surf V2&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.olafalders.com/2026/01/15/can-others-explain-my-work-without-me"&gt;Can Others Explain My Work Without Me?&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;a href="https://www.olafalders.com/2026/03/16/ai-shoulder-surf-v1/"&gt;Read on website&lt;/a&gt;&lt;/p&gt;</content:encoded><media:content xmlns:media="http://search.yahoo.com/mrss/" url="https://www.olafalders.com/2026/03/16/ai-shoulder-surf-v1/featured.jpeg"/></item><item><title>The Great PTS CLI Throwdown</title><link>https://www.olafalders.com/2025/06/03/the-great-pts-cli-throwdown/</link><pubDate>Tue, 03 Jun 2025 00:00:00 +0000</pubDate><author>olaf@wundersolutions.com (Olaf Alders)</author><guid>https://www.olafalders.com/2025/06/03/the-great-pts-cli-throwdown/</guid><description>A quick overview of some command-line tools and terminal configurations shared by a few of us at the Perl Toolchain Summit.</description><content:encoded>&lt;p&gt;I have this kind of annual tradition at the Perl Toolchain Summit where, at
some point in the weekend, I look over &lt;a href="https://github.com/pjcj"&gt;Paul Johnson&amp;rsquo;s&lt;/a&gt; shoulder and admire his
terminal setup. He knows his way around tmux, Neovim and lots of other tools. I
make it a point to check in with him again before the weekend is over so that I
can steal everything. By the time the weekend is over, we&amp;rsquo;ve both left and I
haven&amp;rsquo;t had a chance to poach his setup. At some point afterwards I&amp;rsquo;ll share
some tool &lt;a href="https://fosstodon.org/@oalders"&gt;in the Fediverse&lt;/a&gt; that I think is cool and Paul will inevitably point me at something
newer, shinier and cooler.&lt;/p&gt;
&lt;p&gt;This year the tables were turned and Paul came to me on the first day of PTS to chat about
CLI. We decided that we&amp;rsquo;d get a few of us together on the following morning and
we&amp;rsquo;d trade secrets. What follows are the notes that I took.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Full disclosure: I
don&amp;rsquo;t use AI to write the content of my blog posts, but in this case I did run
my notes through claude.ai to add some summaries and links. Claude didn&amp;rsquo;t get
everything, but it was very helpful and it sped things along. Since this is
meant to be a cheat sheet rather than a piece of creative writing, I&amp;rsquo;m OK with
using AI as a tool to help get the job done.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;This year&amp;rsquo;s participants in our first (annual?) CLI throwdown were, in order of
appearance:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/pjcj/base"&gt;Paul Johnson&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/ssoriche/dotfiles"&gt;Shawn Sorichetti&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/mickeyn"&gt;Mickey Nasriachi&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/simbabque"&gt;Julien Fiegehenn&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/oalders/dot-files"&gt;Olaf Alders&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;a href="https://www.olafalders.com/2025/06/03/the-great-pts-cli-throwdown/featured.jpeg"&gt;&lt;img src="https://www.olafalders.com/2025/06/03/the-great-pts-cli-throwdown/featured.jpeg" alt="featured"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;!-- markdownlint-disable-line --&gt;&lt;p class="attribution"&gt;"&lt;a rel="noopener noreferrer" href="https://commons.wikimedia.org/w/index.php?curid=63950904"&gt;File:Roppongi 3K 3K (Professional wrestling moves).jpg&lt;/a&gt;" by &lt;a rel="noopener noreferrer" href="https://commons.wikimedia.org/w/index.php?title=User:%E3%82%BE%E3%83%BC%E3%83%92%E3%83%A7%E3%83%BC&amp;action=edit&amp;redlink=1"&gt;ゾーヒョー&lt;/a&gt; is licensed under &lt;a rel="noopener noreferrer" href="https://creativecommons.org/licenses/by-sa/4.0/?ref=openverse"&gt;CC BY-SA 4.0 &lt;img src="https://www.olafalders.com/img/cc/cc.svg" alt="" style="height: 1em;" /&gt;&lt;img src="https://www.olafalders.com/img/cc/by.svg" alt="" style="height: 1em;" /&gt;&lt;img src="https://www.olafalders.com/img/cc/sa.svg" alt="" style="height: 1em;" /&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;details class="llm-block" open&gt;
&lt;summary class="llm-block__bar"&gt;
&lt;svg class="llm-block__spark" width="13" height="13" viewBox="0 0 16 16" aria-hidden="true"&gt;&lt;path d="M8 0l1.7 5.4L15 7l-5.3 1.6L8 14l-1.7-5.4L1 7l5.3-1.6z"/&gt;&lt;/svg&gt;
&lt;span class="llm-block__label"&gt;Contains LLM-generated content&lt;/span&gt;
&lt;span class="llm-block__by"&gt;not written by Olaf&lt;/span&gt;
&lt;span class="llm-block__toggle" aria-hidden="true"&gt;&lt;/span&gt;
&lt;/summary&gt;
&lt;div class="llm-block__body"&gt;
&lt;span class="llm-block__gutter" aria-hidden="true" style="background-image:url(&amp;#39;data:image/svg&amp;#43;xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNiIgaGVpZ2h0PSIxNDQiPjx0ZXh0IHRyYW5zZm9ybT0idHJhbnNsYXRlKDExIDE0NCkgcm90YXRlKC05MCkiIGZvbnQtZmFtaWx5PSJ1aS1tb25vc3BhY2UsIFNGTW9uby1SZWd1bGFyLCBNZW5sbywgbW9ub3NwYWNlIiBmb250LXNpemU9IjkuNSIgbGV0dGVyLXNwYWNpbmc9IjIiIGZpbGw9IiNiYjlhZjciIGZpbGwtb3BhY2l0eT0iMC41IiB4bWw6c3BhY2U9InByZXNlcnZlIj5DbGF1ZGUgc3VtbWFyeSDCtyA8L3RleHQ&amp;#43;PC9zdmc&amp;#43;&amp;#39;)"&gt;&lt;/span&gt;
&lt;h2 id="pauls-picks"&gt;&lt;a class="heading-anchor" href="#pauls-picks" aria-label="Permalink to this section"&gt;#&lt;/a&gt;Paul&amp;rsquo;s Picks&lt;/h2&gt;
&lt;h3 id="wezterm"&gt;&lt;a class="heading-anchor" href="#wezterm" aria-label="Permalink to this section"&gt;#&lt;/a&gt;&lt;a href="https://github.com/wezterm/wezterm"&gt;WezTerm&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;A GPU-accelerated cross-platform terminal emulator and multiplexer implemented
in Rust. Features include native mouse support, scrollback, ligatures, and color
emoji.&lt;/p&gt;
&lt;h3 id="yazi"&gt;&lt;a class="heading-anchor" href="#yazi" aria-label="Permalink to this section"&gt;#&lt;/a&gt;&lt;a href="https://github.com/sxyazi/yazi"&gt;yazi&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;A blazingly fast terminal file manager written in Rust, based on asynchronous
I/O. Features include full asynchronous support, built-in image viewing
capabilities, code highlighting, and git integration.&lt;/p&gt;
&lt;h3 id="tmux-powerline"&gt;&lt;a class="heading-anchor" href="#tmux-powerline" aria-label="Permalink to this section"&gt;#&lt;/a&gt;&lt;a href="https://github.com/erikw/tmux-powerline"&gt;tmux powerline&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;A tmux plugin giving you a hackable status bar with beautiful powerline
segments. Implemented in bash, it provides customizable segments for displaying
information like session details, music player status, battery, and more.&lt;/p&gt;
&lt;h3 id="tailscale"&gt;&lt;a class="heading-anchor" href="#tailscale" aria-label="Permalink to this section"&gt;#&lt;/a&gt;&lt;a href="https://tailscale.com/"&gt;Tailscale&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;A zero-configuration VPN built on WireGuard protocol that creates a secure
network between your devices. It simplifies secure connections by handling NAT
traversal and provides easy access control.&lt;/p&gt;
&lt;h3 id="neovim-plugins"&gt;&lt;a class="heading-anchor" href="#neovim-plugins" aria-label="Permalink to this section"&gt;#&lt;/a&gt;Neovim plugins&lt;/h3&gt;
&lt;h4 id="git-signs"&gt;&lt;a class="heading-anchor" href="#git-signs" aria-label="Permalink to this section"&gt;#&lt;/a&gt;&lt;a href="https://github.com/lewis6991/gitsigns.nvim"&gt;git-signs&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;A Neovim plugin that shows Git changes directly in the buffer signcolumn.
Features include per-line git blame, stage/unstage changes, and navigation
between hunks of modifications.&lt;/p&gt;
&lt;h4 id="smoothcursor"&gt;&lt;a class="heading-anchor" href="#smoothcursor" aria-label="Permalink to this section"&gt;#&lt;/a&gt;&lt;a href="https://github.com/gen740/SmoothCursor.nvim"&gt;SmoothCursor&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;A Neovim plugin that adds a sub-cursor to show scroll direction, making it
easier to track cursor position when using commands like &lt;code&gt;%&lt;/code&gt; or &lt;code&gt;&amp;lt;c-f&amp;gt;&lt;/code&gt; and
&lt;code&gt;&amp;lt;c-b&amp;gt;&lt;/code&gt;.&lt;/p&gt;
&lt;h4 id="which-key"&gt;&lt;a class="heading-anchor" href="#which-key" aria-label="Permalink to this section"&gt;#&lt;/a&gt;&lt;a href="https://github.com/folke/which-key.nvim"&gt;which-key&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;A Neovim plugin that displays a popup showing keybindings as you type, helping
users remember complex key combinations and commands. Works across various
modes, including normal, insert, and visual.&lt;/p&gt;
&lt;h4 id="nvim-cmp"&gt;&lt;a class="heading-anchor" href="#nvim-cmp" aria-label="Permalink to this section"&gt;#&lt;/a&gt;&lt;a href="https://github.com/hrsh7th/nvim-cmp"&gt;nvim-cmp&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;A completion plugin for Neovim written in Lua. It provides a powerful and
extensible completion experience with support for LSP, snippets, and custom
sources.&lt;/p&gt;
&lt;h4 id="magazinenvim"&gt;&lt;a class="heading-anchor" href="#magazinenvim" aria-label="Permalink to this section"&gt;#&lt;/a&gt;&lt;a href="https://github.com/iguanacucumber/magazine.nvim"&gt;magazine.nvim&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;An nvim-cmp beta fork.&lt;/p&gt;
&lt;h4 id="perlnavigator"&gt;&lt;a class="heading-anchor" href="#perlnavigator" aria-label="Permalink to this section"&gt;#&lt;/a&gt;&lt;a href="https://github.com/bscan/PerlNavigator"&gt;PerlNavigator&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;A language server for Perl, providing features like code navigation,
completion, and diagnostics.&lt;/p&gt;
&lt;h4 id="treesitter"&gt;&lt;a class="heading-anchor" href="#treesitter" aria-label="Permalink to this section"&gt;#&lt;/a&gt;&lt;a href="https://github.com/nvim-treesitter/nvim-treesitter"&gt;treesitter&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;A Neovim plugin providing an interface for Tree-sitter, a parser generator tool
that provides incremental parsing capabilities, enabling better syntax
highlighting and text-objects.&lt;/p&gt;
&lt;h4 id="avante"&gt;&lt;a class="heading-anchor" href="#avante" aria-label="Permalink to this section"&gt;#&lt;/a&gt;&lt;a href="https://github.com/yetone/avante.nvim"&gt;avante&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;A Neovim plugin designed to emulate the behaviour of the
&lt;a href="https://www.cursor.com/"&gt;Cursor&lt;/a&gt; AI IDE.&lt;/p&gt;
&lt;h4 id="mcp-hub"&gt;&lt;a class="heading-anchor" href="#mcp-hub" aria-label="Permalink to this section"&gt;#&lt;/a&gt;&lt;a href="https://github.com/ravitemer/mcphub.nvim"&gt;mcp hub&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;A Neovim plugin that integrates MCP (Model Context Protocol) servers into your
workflow.&lt;/p&gt;
&lt;h4 id="markview"&gt;&lt;a class="heading-anchor" href="#markview" aria-label="Permalink to this section"&gt;#&lt;/a&gt;&lt;a href="https://github.com/OXY2DEV/markview.nvim"&gt;markview&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;A Neovim plugin for viewing and editing markdown files.&lt;/p&gt;
&lt;h4 id="nvim-scrollbar"&gt;&lt;a class="heading-anchor" href="#nvim-scrollbar" aria-label="Permalink to this section"&gt;#&lt;/a&gt;&lt;a href="https://github.com/petertriho/nvim-scrollbar"&gt;nvim-scrollbar&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;A customizable scrollbar for Neovim that can be integrated with other plugins to
display git changes or diagnostics in the scrollbar.&lt;/p&gt;
&lt;h3 id="zsh"&gt;&lt;a class="heading-anchor" href="#zsh" aria-label="Permalink to this section"&gt;#&lt;/a&gt;&lt;a href="https://www.zsh.org/"&gt;zsh&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;An extended shell with improved completion, scripting capabilities, and plugins.
It&amp;rsquo;s highly customizable and offers numerous features beyond the standard bash.&lt;/p&gt;
&lt;h3 id="eza"&gt;&lt;a class="heading-anchor" href="#eza" aria-label="Permalink to this section"&gt;#&lt;/a&gt;&lt;a href="https://github.com/eza-community/eza"&gt;eza&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;A modern replacement for the &lt;code&gt;ls&lt;/code&gt; command with more colorful and human-friendly
output, including git integration for directories.&lt;/p&gt;
&lt;h3 id="raycast"&gt;&lt;a class="heading-anchor" href="#raycast" aria-label="Permalink to this section"&gt;#&lt;/a&gt;&lt;a href="https://www.raycast.com/"&gt;Raycast&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;A productivity tool for macOS that provides a quick launcher, extensible
commands, and scriptable automation capabilities.&lt;/p&gt;
&lt;h3 id="stats"&gt;&lt;a class="heading-anchor" href="#stats" aria-label="Permalink to this section"&gt;#&lt;/a&gt;&lt;a href="https://github.com/exelban/stats"&gt;stats&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;A macOS system monitor in your menu bar that shows detailed system statistics
like CPU usage, memory, network, and more.&lt;/p&gt;
&lt;h2 id="shawns-picks"&gt;&lt;a class="heading-anchor" href="#shawns-picks" aria-label="Permalink to this section"&gt;#&lt;/a&gt;Shawn&amp;rsquo;s Picks&lt;/h2&gt;
&lt;h3 id="aerospace"&gt;&lt;a class="heading-anchor" href="#aerospace" aria-label="Permalink to this section"&gt;#&lt;/a&gt;&lt;a href="https://github.com/nikitabobko/aerospace"&gt;aerospace&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;A tiled window manager for macOS that arranges windows automatically and
provides keyboard shortcuts for window management.&lt;/p&gt;
&lt;h3 id="git-restore"&gt;&lt;a class="heading-anchor" href="#git-restore" aria-label="Permalink to this section"&gt;#&lt;/a&gt;&lt;a href="https://git-scm.com/docs/git-restore"&gt;git restore&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;A Git command to restore working tree files, allowing you to discard changes or
restore files from a specific commit.&lt;/p&gt;
&lt;h3 id="lazyvim"&gt;&lt;a class="heading-anchor" href="#lazyvim" aria-label="Permalink to this section"&gt;#&lt;/a&gt;&lt;a href="https://www.lazyvim.org/"&gt;lazyvim&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;A Neovim configuration framework that provides a pre-configured and opinionated
setup with various plugins and sensible defaults.&lt;/p&gt;
&lt;h3 id="ctrl-a"&gt;&lt;a class="heading-anchor" href="#ctrl-a" aria-label="Permalink to this section"&gt;#&lt;/a&gt;ctrl-a&lt;/h3&gt;
&lt;p&gt;A Vim/Neovim feature that allows auto-incrementing numbers in text.&lt;/p&gt;
&lt;h3 id="tmux-keybindings-in-wezterm"&gt;&lt;a class="heading-anchor" href="#tmux-keybindings-in-wezterm" aria-label="Permalink to this section"&gt;#&lt;/a&gt;tmux keybindings in WezTerm&lt;/h3&gt;
&lt;p&gt;Using tmux-like key mappings within the WezTerm terminal emulator for consistent
workflow.&lt;/p&gt;
&lt;h3 id="caps-lock-ctrl--escape"&gt;&lt;a class="heading-anchor" href="#caps-lock-ctrl--escape" aria-label="Permalink to this section"&gt;#&lt;/a&gt;caps-lock ctrl + escape&lt;/h3&gt;
&lt;p&gt;A keyboard remapping that makes Caps Lock act as Control when held and Escape
when tapped.&lt;/p&gt;
&lt;h3 id="karabiner"&gt;&lt;a class="heading-anchor" href="#karabiner" aria-label="Permalink to this section"&gt;#&lt;/a&gt;&lt;a href="https://karabiner-elements.pqrs.org/"&gt;karabiner&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;A powerful keyboard customizer for macOS that allows complex remappings and
custom modifications.&lt;/p&gt;
&lt;h3 id="bat"&gt;&lt;a class="heading-anchor" href="#bat" aria-label="Permalink to this section"&gt;#&lt;/a&gt;&lt;a href="https://github.com/sharkdp/bat"&gt;bat&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;A cat clone with syntax highlighting, git integration, and line numbers, making
it easier to view file contents.&lt;/p&gt;
&lt;h3 id="fish"&gt;&lt;a class="heading-anchor" href="#fish" aria-label="Permalink to this section"&gt;#&lt;/a&gt;&lt;a href="https://fishshell.com/"&gt;fish&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;A user-friendly command line shell with syntax highlighting, autosuggestions,
and smart tab completions.&lt;/p&gt;
&lt;h3 id="delta"&gt;&lt;a class="heading-anchor" href="#delta" aria-label="Permalink to this section"&gt;#&lt;/a&gt;&lt;a href="https://github.com/dandavison/delta"&gt;delta&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;A syntax-highlighting pager for git, diff, and grep output that improves
readability of diffs.&lt;/p&gt;
&lt;h3 id="spacer"&gt;&lt;a class="heading-anchor" href="#spacer" aria-label="Permalink to this section"&gt;#&lt;/a&gt;&lt;a href="https://github.com/samwho/spacer"&gt;spacer&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;A utility for adding visual separation or spacing in user interfaces.&lt;/p&gt;
&lt;h3 id="atuin"&gt;&lt;a class="heading-anchor" href="#atuin" aria-label="Permalink to this section"&gt;#&lt;/a&gt;&lt;a href="https://atuin.sh/"&gt;atuin&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;A tool that provides a searchable history with context for your shell, syncing
across multiple machines.&lt;/p&gt;
&lt;h3 id="devbox"&gt;&lt;a class="heading-anchor" href="#devbox" aria-label="Permalink to this section"&gt;#&lt;/a&gt;&lt;a href="https://www.jetpack.io/devbox/"&gt;devbox&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;A command-line tool for creating isolated, reproducible development
environments.&lt;/p&gt;
&lt;h3 id="direnv"&gt;&lt;a class="heading-anchor" href="#direnv" aria-label="Permalink to this section"&gt;#&lt;/a&gt;&lt;a href="https://direnv.net/"&gt;direnv&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;An environment switcher that automatically loads and unloads environment
variables depending on the current directory.&lt;/p&gt;
&lt;h3 id="wezterm-quick-select"&gt;&lt;a class="heading-anchor" href="#wezterm-quick-select" aria-label="Permalink to this section"&gt;#&lt;/a&gt;&lt;a href="https://wezterm.org/quickselect.html"&gt;WezTerm quick select&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;A feature in WezTerm that allows quick selection and copying of text patterns
like URLs, paths, or IPs.&lt;/p&gt;
&lt;h3 id="chezmoi"&gt;&lt;a class="heading-anchor" href="#chezmoi" aria-label="Permalink to this section"&gt;#&lt;/a&gt;&lt;a href="https://www.chezmoi.io/"&gt;chezmoi&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;A dotfile manager that helps keep track and synchronize your dotfiles across
multiple machines.&lt;/p&gt;
&lt;h3 id="asciinema"&gt;&lt;a class="heading-anchor" href="#asciinema" aria-label="Permalink to this section"&gt;#&lt;/a&gt;&lt;a href="https://asciinema.org/"&gt;asciinema&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;A tool for recording and sharing terminal sessions with playback capabilities.&lt;/p&gt;
&lt;h2 id="mickeys-picks"&gt;&lt;a class="heading-anchor" href="#mickeys-picks" aria-label="Permalink to this section"&gt;#&lt;/a&gt;Mickey&amp;rsquo;s Picks&lt;/h2&gt;
&lt;h3 id="terminator"&gt;&lt;a class="heading-anchor" href="#terminator" aria-label="Permalink to this section"&gt;#&lt;/a&gt;&lt;a href="https://gnome-terminator.org/"&gt;terminator&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;A terminal emulator that allows you to arrange multiple terminals in a grid-like
structure, each with configurable options.&lt;/p&gt;
&lt;h3 id="ctrl-s-stop-streaming-output"&gt;&lt;a class="heading-anchor" href="#ctrl-s-stop-streaming-output" aria-label="Permalink to this section"&gt;#&lt;/a&gt;ctrl-s stop streaming output&lt;/h3&gt;
&lt;p&gt;A terminal shortcut that freezes the terminal output, which can be resumed with
ctrl-q (software flow control). This feature can be disabled in the shell using
&lt;code&gt;stty -ixon&lt;/code&gt;.&lt;/p&gt;
&lt;h3 id="tmux-resurrect"&gt;&lt;a class="heading-anchor" href="#tmux-resurrect" aria-label="Permalink to this section"&gt;#&lt;/a&gt;&lt;a href="https://github.com/tmux-plugins/tmux-resurrect"&gt;tmux-resurrect&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;A tmux plugin that allows saving and restoring tmux sessions across system
restarts.&lt;/p&gt;
&lt;h3 id="cd-is-an-alias-to-pushd"&gt;&lt;a class="heading-anchor" href="#cd-is-an-alias-to-pushd" aria-label="Permalink to this section"&gt;#&lt;/a&gt;cd is an alias to pushd&lt;/h3&gt;
&lt;p&gt;A shell configuration where the &lt;code&gt;cd&lt;/code&gt; command is aliased to &lt;code&gt;pushd&lt;/code&gt;, maintaining
a directory stack for easy navigation. Complemented with &lt;code&gt;cd-&lt;/code&gt; aliased to
&lt;code&gt;popd&lt;/code&gt;.&lt;/p&gt;
&lt;h3 id="zmv-for-mass-renaming-via-regex"&gt;&lt;a class="heading-anchor" href="#zmv-for-mass-renaming-via-regex" aria-label="Permalink to this section"&gt;#&lt;/a&gt;zmv for mass renaming via regex&lt;/h3&gt;
&lt;p&gt;A (zsh) tool for batch renaming files using regular expressions.&lt;/p&gt;
&lt;h3 id="pdftk"&gt;&lt;a class="heading-anchor" href="#pdftk" aria-label="Permalink to this section"&gt;#&lt;/a&gt;&lt;a href="https://www.pdflabs.com/tools/pdftk-the-pdf-toolkit/"&gt;pdftk&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;A command-line tool for manipulating PDF documents, including merging,
splitting, and form filling.&lt;/p&gt;
&lt;h3 id="fpp"&gt;&lt;a class="heading-anchor" href="#fpp" aria-label="Permalink to this section"&gt;#&lt;/a&gt;&lt;a href="https://github.com/facebook/PathPicker"&gt;fpp&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Facebook Path Picker, a tool that helps you select files from command output for
further operations.&lt;/p&gt;
&lt;h3 id="highlight"&gt;&lt;a class="heading-anchor" href="#highlight" aria-label="Permalink to this section"&gt;#&lt;/a&gt;&lt;a href="https://github.com/kepkin/dev-shell-essentials"&gt;highlight&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;A simple tool that adds colors to matched text input.&lt;/p&gt;
&lt;h3 id="some-favorite-git-commands"&gt;&lt;a class="heading-anchor" href="#some-favorite-git-commands" aria-label="Permalink to this section"&gt;#&lt;/a&gt;Some favorite git commands&lt;/h3&gt;
&lt;h4 id="git-checkout--p"&gt;&lt;a class="heading-anchor" href="#git-checkout--p" aria-label="Permalink to this section"&gt;#&lt;/a&gt;git checkout -p&lt;/h4&gt;
&lt;p&gt;A Git command that allows interactive selection of hunks to check out, similar
to &lt;code&gt;git add -p&lt;/code&gt; but for discarding changes.&lt;/p&gt;
&lt;h4 id="git-rebase--i"&gt;&lt;a class="heading-anchor" href="#git-rebase--i" aria-label="Permalink to this section"&gt;#&lt;/a&gt;git rebase -i&lt;/h4&gt;
&lt;p&gt;Interactively manipulate (reword comments, reorder or squash) commits (that are
ahead of upstream).&lt;/p&gt;
&lt;h4 id="git-grep--w"&gt;&lt;a class="heading-anchor" href="#git-grep--w" aria-label="Permalink to this section"&gt;#&lt;/a&gt;git grep -W&lt;/h4&gt;
&lt;p&gt;Match showing the function context (e.g. Perl sub).&lt;/p&gt;
&lt;h4 id="git-push-origin-head"&gt;&lt;a class="heading-anchor" href="#git-push-origin-head" aria-label="Permalink to this section"&gt;#&lt;/a&gt;git push origin HEAD&lt;/h4&gt;
&lt;p&gt;Push current local branch to remote.&lt;/p&gt;
&lt;h4 id="git-branch-merged--grep--v-master--xargs-no-run-if-empty-git-branch--d"&gt;&lt;a class="heading-anchor" href="#git-branch-merged--grep--v-master--xargs-no-run-if-empty-git-branch--d" aria-label="Permalink to this section"&gt;#&lt;/a&gt;git branch &amp;ndash;merged | grep -v master | xargs &amp;ndash;no-run-if-empty git branch -d&lt;/h4&gt;
&lt;p&gt;Remove merged branches from local directory (use an alias).&lt;/p&gt;
&lt;h4 id="git-clean--dfx"&gt;&lt;a class="heading-anchor" href="#git-clean--dfx" aria-label="Permalink to this section"&gt;#&lt;/a&gt;git clean -dfx&lt;/h4&gt;
&lt;p&gt;Clean working tree from all untracked files (I have it aliased to distclean in
.gitconfig).&lt;/p&gt;
&lt;h2 id="juliens-picks"&gt;&lt;a class="heading-anchor" href="#juliens-picks" aria-label="Permalink to this section"&gt;#&lt;/a&gt;Julien&amp;rsquo;s Picks&lt;/h2&gt;
&lt;h3 id="tig"&gt;&lt;a class="heading-anchor" href="#tig" aria-label="Permalink to this section"&gt;#&lt;/a&gt;&lt;a href="https://github.com/jonas/tig"&gt;tig&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;A text-mode interface for git that provides a visual interface for navigating
commits, diffs, and branches.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Editor&amp;rsquo;s note: I have previously &lt;a href="https://www.olafalders.com/2024/01/17/tig-git-browser/"&gt;written about tig&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;
&lt;h3 id="shutter"&gt;&lt;a class="heading-anchor" href="#shutter" aria-label="Permalink to this section"&gt;#&lt;/a&gt;&lt;a href="https://shutter-project.org/"&gt;shutter&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;A feature-rich screenshot tool with editing capabilities, annotations, and
various capture modes.&lt;/p&gt;
&lt;h3 id="peek"&gt;&lt;a class="heading-anchor" href="#peek" aria-label="Permalink to this section"&gt;#&lt;/a&gt;peek&lt;/h3&gt;
&lt;h2 id="olafs-picks"&gt;&lt;a class="heading-anchor" href="#olafs-picks" aria-label="Permalink to this section"&gt;#&lt;/a&gt;Olaf&amp;rsquo;s Picks&lt;/h2&gt;
&lt;h3 id="sketchybar"&gt;&lt;a class="heading-anchor" href="#sketchybar" aria-label="Permalink to this section"&gt;#&lt;/a&gt;&lt;a href="https://github.com/FelixKratz/SketchyBar"&gt;Sketchybar&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;A highly customizable macOS status bar replacement that can display system
information, application status, and custom scripts. I recently &lt;a href="https://www.olafalders.com/2025/05/28/enhancing-sketchybar-with-is-battery/"&gt;wrote about SketchyBar&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id="hammerspoon"&gt;&lt;a class="heading-anchor" href="#hammerspoon" aria-label="Permalink to this section"&gt;#&lt;/a&gt;&lt;a href="https://www.hammerspoon.org/"&gt;Hammerspoon&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;A tool for powerful automation of macOS, allowing you to write Lua scripts that
hook into system events and perform complex tasks.&lt;/p&gt;
&lt;h3 id="oh-my-posh"&gt;&lt;a class="heading-anchor" href="#oh-my-posh" aria-label="Permalink to this section"&gt;#&lt;/a&gt;&lt;a href="https://ohmyposh.dev/"&gt;oh-my-posh&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;A prompt theme engine for any shell that provides a customizable and beautiful
prompt with git status, execution time, and more.&lt;/p&gt;
&lt;h3 id="alfred"&gt;&lt;a class="heading-anchor" href="#alfred" aria-label="Permalink to this section"&gt;#&lt;/a&gt;&lt;a href="https://www.alfredapp.com/"&gt;Alfred&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;A productivity application for macOS that offers features like hotkeys,
keywords, text expansion, and clipboard history.&lt;/p&gt;
&lt;h4 id="clipboard"&gt;&lt;a class="heading-anchor" href="#clipboard" aria-label="Permalink to this section"&gt;#&lt;/a&gt;clipboard&lt;/h4&gt;
&lt;p&gt;Alfred&amp;rsquo;s clipboard history feature that stores text, images, and files, making
them accessible via keyboard shortcut.&lt;/p&gt;
&lt;h4 id="alfred-metacpan"&gt;&lt;a class="heading-anchor" href="#alfred-metacpan" aria-label="Permalink to this section"&gt;#&lt;/a&gt;&lt;a href="https://github.com/oalders/alfred-metacpan-workflow"&gt;alfred-metacpan&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;An Alfred workflow for searching the Comprehensive Perl Archive Network (CPAN).&lt;/p&gt;
&lt;h3 id="cloudflare-tunnels"&gt;&lt;a class="heading-anchor" href="#cloudflare-tunnels" aria-label="Permalink to this section"&gt;#&lt;/a&gt;&lt;a href="https://www.cloudflare.com/products/tunnel/"&gt;Cloudflare tunnels&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;A service that creates secure connections between your local resources and the
Cloudflare network, without exposing public IPs.&lt;/p&gt;
&lt;h3 id="typos"&gt;&lt;a class="heading-anchor" href="#typos" aria-label="Permalink to this section"&gt;#&lt;/a&gt;&lt;a href="https://github.com/crate-ci/typos"&gt;typos&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;A source code spell checker that helps catch typos in your code, comments, and
documentation.&lt;/p&gt;
&lt;h3 id="is"&gt;&lt;a class="heading-anchor" href="#is" aria-label="Permalink to this section"&gt;#&lt;/a&gt;&lt;a href="https://github.com/oalders/is"&gt;is&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;An inspector for your environment. I have &lt;a href="https://www.olafalders.com/categories/is/"&gt;written too much about
is&lt;/a&gt; already.&lt;/p&gt;
&lt;h3 id="debounce"&gt;&lt;a class="heading-anchor" href="#debounce" aria-label="Permalink to this section"&gt;#&lt;/a&gt;&lt;a href="https://github.com/oalders/debounce"&gt;debounce&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Limit the rate at which a command can fire. I have written about
&lt;a href="https://www.olafalders.com/2025/02/25/debounce-all-of-the-things/"&gt;debounce&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id="gh"&gt;&lt;a class="heading-anchor" href="#gh" aria-label="Permalink to this section"&gt;#&lt;/a&gt;&lt;a href="https://cli.github.com/"&gt;gh&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;GitHub&amp;rsquo;s official command line tool for interacting with GitHub repositories,
issues, and pull requests directly from the terminal.&lt;/p&gt;
&lt;h3 id="ot"&gt;&lt;a class="heading-anchor" href="#ot" aria-label="Permalink to this section"&gt;#&lt;/a&gt;&lt;a href="https://metacpan.org/dist/Open-This/view/script/ot"&gt;ot&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;A command line utility tool with specialized functionality. I have written &lt;a href="https://www.perl.com/article/how-do-i-open-this-/"&gt;an
intro to Open::This&lt;/a&gt; and &lt;a href="https://www.olafalders.com/2022/01/05/open-this-file-from-inside-vim/"&gt;a
vim integration
guide&lt;/a&gt;.
I should write up &lt;a href="https://github.com/oalders/dot-files/blob/5128252e83558530b941b91494a6f1262599cbfb/nvim/lua/conf/open-this.lua"&gt;my Neovim integration
sometime&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id="ubi"&gt;&lt;a class="heading-anchor" href="#ubi" aria-label="Permalink to this section"&gt;#&lt;/a&gt;&lt;a href="https://github.com/houseabsolute/ubi"&gt;ubi&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;A command line tool for installing universal binaries across different
platforms.&lt;/p&gt;
&lt;h3 id="precious"&gt;&lt;a class="heading-anchor" href="#precious" aria-label="Permalink to this section"&gt;#&lt;/a&gt;&lt;a href="https://github.com/houseabsolute/precious"&gt;precious&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;A linter and formatter harness.&lt;/p&gt;
&lt;h3 id="git-absorb"&gt;&lt;a class="heading-anchor" href="#git-absorb" aria-label="Permalink to this section"&gt;#&lt;/a&gt;&lt;a href="https://github.com/tummychow/git-absorb"&gt;git-absorb&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;A git command that automatically identifies and squashes fixup commits into
their relevant commits.&lt;/p&gt;
&lt;h3 id="gum"&gt;&lt;a class="heading-anchor" href="#gum" aria-label="Permalink to this section"&gt;#&lt;/a&gt;&lt;a href="https://github.com/charmbracelet/gum"&gt;gum&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;A tool for glamorous shell scripts, helping create interactive CLI components
like inputs, prompts, and spinners.&lt;/p&gt;
&lt;h3 id="tailspin"&gt;&lt;a class="heading-anchor" href="#tailspin" aria-label="Permalink to this section"&gt;#&lt;/a&gt;&lt;a href="https://github.com/bensadeh/tailspin"&gt;tailspin&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;A log file highlighter that improves readability of log files in the terminal
with color coding and formatting.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="llm-block__foot"&gt;
&lt;span&gt;// end LLM-generated content&lt;/span&gt;
&lt;button type="button" class="llm-block__collapse" data-llm-collapse&gt;Hide&lt;/button&gt;
&lt;/div&gt;
&lt;/details&gt;
&lt;p&gt;&lt;a href="https://www.olafalders.com/2025/06/03/the-great-pts-cli-throwdown/"&gt;Read on website&lt;/a&gt;&lt;/p&gt;</content:encoded><media:content xmlns:media="http://search.yahoo.com/mrss/" url="https://www.olafalders.com/2025/06/03/the-great-pts-cli-throwdown/featured.jpeg"/></item></channel></rss>